15e5c12b0Sopenharmony_ci/**
25e5c12b0Sopenharmony_ci * segment.c
35e5c12b0Sopenharmony_ci *
45e5c12b0Sopenharmony_ci * Many parts of codes are copied from Linux kernel/fs/f2fs.
55e5c12b0Sopenharmony_ci *
65e5c12b0Sopenharmony_ci * Copyright (C) 2015 Huawei Ltd.
75e5c12b0Sopenharmony_ci * Witten by:
85e5c12b0Sopenharmony_ci *   Hou Pengyang <houpengyang@huawei.com>
95e5c12b0Sopenharmony_ci *   Liu Shuoran <liushuoran@huawei.com>
105e5c12b0Sopenharmony_ci *   Jaegeuk Kim <jaegeuk@kernel.org>
115e5c12b0Sopenharmony_ci * Copyright (c) 2020 Google Inc.
125e5c12b0Sopenharmony_ci *   Robin Hsu <robinhsu@google.com>
135e5c12b0Sopenharmony_ci *  : add sload compression support
145e5c12b0Sopenharmony_ci *
155e5c12b0Sopenharmony_ci * This program is free software; you can redistribute it and/or modify
165e5c12b0Sopenharmony_ci * it under the terms of the GNU General Public License version 2 as
175e5c12b0Sopenharmony_ci * published by the Free Software Foundation.
185e5c12b0Sopenharmony_ci */
195e5c12b0Sopenharmony_ci#include "fsck.h"
205e5c12b0Sopenharmony_ci#include "node.h"
215e5c12b0Sopenharmony_ci#include "quotaio.h"
225e5c12b0Sopenharmony_ci
235e5c12b0Sopenharmony_ciint reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
245e5c12b0Sopenharmony_ci			struct f2fs_summary *sum, int type, bool is_inode)
255e5c12b0Sopenharmony_ci{
265e5c12b0Sopenharmony_ci	struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
275e5c12b0Sopenharmony_ci	struct seg_entry *se;
285e5c12b0Sopenharmony_ci	u64 blkaddr, offset;
295e5c12b0Sopenharmony_ci	u64 old_blkaddr = *to;
305e5c12b0Sopenharmony_ci	bool is_node = IS_NODESEG(type);
315e5c12b0Sopenharmony_ci	int left = 0;
325e5c12b0Sopenharmony_ci
335e5c12b0Sopenharmony_ci	if (old_blkaddr == NULL_ADDR) {
345e5c12b0Sopenharmony_ci		if (c.func == FSCK) {
355e5c12b0Sopenharmony_ci			if (fsck->chk.valid_blk_cnt >= sbi->user_block_count) {
365e5c12b0Sopenharmony_ci				ERR_MSG("Not enough space\n");
375e5c12b0Sopenharmony_ci				return -ENOSPC;
385e5c12b0Sopenharmony_ci			}
395e5c12b0Sopenharmony_ci			if (is_node && fsck->chk.valid_node_cnt >=
405e5c12b0Sopenharmony_ci					sbi->total_valid_node_count) {
415e5c12b0Sopenharmony_ci				ERR_MSG("Not enough space for node block\n");
425e5c12b0Sopenharmony_ci				return -ENOSPC;
435e5c12b0Sopenharmony_ci			}
445e5c12b0Sopenharmony_ci		} else {
455e5c12b0Sopenharmony_ci			if (sbi->total_valid_block_count >=
465e5c12b0Sopenharmony_ci						sbi->user_block_count) {
475e5c12b0Sopenharmony_ci				ERR_MSG("Not enough space\n");
485e5c12b0Sopenharmony_ci				return -ENOSPC;
495e5c12b0Sopenharmony_ci			}
505e5c12b0Sopenharmony_ci			if (is_node && sbi->total_valid_node_count >=
515e5c12b0Sopenharmony_ci						sbi->total_node_count) {
525e5c12b0Sopenharmony_ci				ERR_MSG("Not enough space for node block\n");
535e5c12b0Sopenharmony_ci				return -ENOSPC;
545e5c12b0Sopenharmony_ci			}
555e5c12b0Sopenharmony_ci		}
565e5c12b0Sopenharmony_ci	}
575e5c12b0Sopenharmony_ci
585e5c12b0Sopenharmony_ci	blkaddr = SM_I(sbi)->main_blkaddr;
595e5c12b0Sopenharmony_ci
605e5c12b0Sopenharmony_ci	if (sbi->raw_super->feature & cpu_to_le32(F2FS_FEATURE_RO)) {
615e5c12b0Sopenharmony_ci		if (IS_NODESEG(type)) {
625e5c12b0Sopenharmony_ci			type = CURSEG_HOT_NODE;
635e5c12b0Sopenharmony_ci			blkaddr = __end_block_addr(sbi);
645e5c12b0Sopenharmony_ci			left = 1;
655e5c12b0Sopenharmony_ci		} else if (IS_DATASEG(type)) {
665e5c12b0Sopenharmony_ci			type = CURSEG_HOT_DATA;
675e5c12b0Sopenharmony_ci			blkaddr = SM_I(sbi)->main_blkaddr;
685e5c12b0Sopenharmony_ci			left = 0;
695e5c12b0Sopenharmony_ci		}
705e5c12b0Sopenharmony_ci	}
715e5c12b0Sopenharmony_ci
725e5c12b0Sopenharmony_ci	if (find_next_free_block(sbi, &blkaddr, left, type, false)) {
735e5c12b0Sopenharmony_ci		ERR_MSG("Can't find free block");
745e5c12b0Sopenharmony_ci		ASSERT(0);
755e5c12b0Sopenharmony_ci	}
765e5c12b0Sopenharmony_ci
775e5c12b0Sopenharmony_ci	se = get_seg_entry(sbi, GET_SEGNO(sbi, blkaddr));
785e5c12b0Sopenharmony_ci	offset = OFFSET_IN_SEG(sbi, blkaddr);
795e5c12b0Sopenharmony_ci	se->type = type;
805e5c12b0Sopenharmony_ci	se->valid_blocks++;
815e5c12b0Sopenharmony_ci	f2fs_set_bit(offset, (char *)se->cur_valid_map);
825e5c12b0Sopenharmony_ci	if (need_fsync_data_record(sbi)) {
835e5c12b0Sopenharmony_ci		se->ckpt_type = type;
845e5c12b0Sopenharmony_ci		se->ckpt_valid_blocks++;
855e5c12b0Sopenharmony_ci		f2fs_set_bit(offset, (char *)se->ckpt_valid_map);
865e5c12b0Sopenharmony_ci	}
875e5c12b0Sopenharmony_ci	if (c.func == FSCK) {
885e5c12b0Sopenharmony_ci		f2fs_set_main_bitmap(sbi, blkaddr, type);
895e5c12b0Sopenharmony_ci		f2fs_set_sit_bitmap(sbi, blkaddr);
905e5c12b0Sopenharmony_ci	}
915e5c12b0Sopenharmony_ci
925e5c12b0Sopenharmony_ci	if (old_blkaddr == NULL_ADDR) {
935e5c12b0Sopenharmony_ci		sbi->total_valid_block_count++;
945e5c12b0Sopenharmony_ci		if (is_node) {
955e5c12b0Sopenharmony_ci			sbi->total_valid_node_count++;
965e5c12b0Sopenharmony_ci			if (is_inode)
975e5c12b0Sopenharmony_ci				sbi->total_valid_inode_count++;
985e5c12b0Sopenharmony_ci		}
995e5c12b0Sopenharmony_ci		if (c.func == FSCK) {
1005e5c12b0Sopenharmony_ci			fsck->chk.valid_blk_cnt++;
1015e5c12b0Sopenharmony_ci			if (is_node) {
1025e5c12b0Sopenharmony_ci				fsck->chk.valid_node_cnt++;
1035e5c12b0Sopenharmony_ci				if (is_inode)
1045e5c12b0Sopenharmony_ci					fsck->chk.valid_inode_cnt++;
1055e5c12b0Sopenharmony_ci			}
1065e5c12b0Sopenharmony_ci		}
1075e5c12b0Sopenharmony_ci	}
1085e5c12b0Sopenharmony_ci	se->dirty = 1;
1095e5c12b0Sopenharmony_ci
1105e5c12b0Sopenharmony_ci	/* read/write SSA */
1115e5c12b0Sopenharmony_ci	*to = (block_t)blkaddr;
1125e5c12b0Sopenharmony_ci	update_sum_entry(sbi, *to, sum);
1135e5c12b0Sopenharmony_ci
1145e5c12b0Sopenharmony_ci	return 0;
1155e5c12b0Sopenharmony_ci}
1165e5c12b0Sopenharmony_ci
1175e5c12b0Sopenharmony_ciint new_data_block(struct f2fs_sb_info *sbi, void *block,
1185e5c12b0Sopenharmony_ci				struct dnode_of_data *dn, int type)
1195e5c12b0Sopenharmony_ci{
1205e5c12b0Sopenharmony_ci	struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
1215e5c12b0Sopenharmony_ci	struct f2fs_summary sum;
1225e5c12b0Sopenharmony_ci	struct node_info ni;
1235e5c12b0Sopenharmony_ci	unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node);
1245e5c12b0Sopenharmony_ci	int ret;
1255e5c12b0Sopenharmony_ci
1265e5c12b0Sopenharmony_ci	if ((get_sb(feature) & cpu_to_le32(F2FS_FEATURE_RO)) &&
1275e5c12b0Sopenharmony_ci					type != CURSEG_HOT_DATA)
1285e5c12b0Sopenharmony_ci		type = CURSEG_HOT_DATA;
1295e5c12b0Sopenharmony_ci
1305e5c12b0Sopenharmony_ci	ASSERT(dn->node_blk);
1315e5c12b0Sopenharmony_ci	memset(block, 0, BLOCK_SZ);
1325e5c12b0Sopenharmony_ci
1335e5c12b0Sopenharmony_ci	get_node_info(sbi, dn->nid, &ni);
1345e5c12b0Sopenharmony_ci	set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
1355e5c12b0Sopenharmony_ci
1365e5c12b0Sopenharmony_ci	dn->data_blkaddr = blkaddr;
1375e5c12b0Sopenharmony_ci	ret = reserve_new_block(sbi, &dn->data_blkaddr, &sum, type, 0);
1385e5c12b0Sopenharmony_ci	if (ret) {
1395e5c12b0Sopenharmony_ci		c.alloc_failed = 1;
1405e5c12b0Sopenharmony_ci		return ret;
1415e5c12b0Sopenharmony_ci	}
1425e5c12b0Sopenharmony_ci
1435e5c12b0Sopenharmony_ci	if (blkaddr == NULL_ADDR)
1445e5c12b0Sopenharmony_ci		inc_inode_blocks(dn);
1455e5c12b0Sopenharmony_ci	else if (blkaddr == NEW_ADDR)
1465e5c12b0Sopenharmony_ci		dn->idirty = 1;
1475e5c12b0Sopenharmony_ci	set_data_blkaddr(dn);
1485e5c12b0Sopenharmony_ci	return 0;
1495e5c12b0Sopenharmony_ci}
1505e5c12b0Sopenharmony_ci
1515e5c12b0Sopenharmony_ciu64 f2fs_quota_size(struct quota_file *qf)
1525e5c12b0Sopenharmony_ci{
1535e5c12b0Sopenharmony_ci	struct node_info ni;
1545e5c12b0Sopenharmony_ci	struct f2fs_node *inode;
1555e5c12b0Sopenharmony_ci	u64 filesize;
1565e5c12b0Sopenharmony_ci
1575e5c12b0Sopenharmony_ci	inode = (struct f2fs_node *) calloc(BLOCK_SZ, 1);
1585e5c12b0Sopenharmony_ci	ASSERT(inode);
1595e5c12b0Sopenharmony_ci
1605e5c12b0Sopenharmony_ci	/* Read inode */
1615e5c12b0Sopenharmony_ci	get_node_info(qf->sbi, qf->ino, &ni);
1625e5c12b0Sopenharmony_ci	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
1635e5c12b0Sopenharmony_ci	ASSERT(S_ISREG(le16_to_cpu(inode->i.i_mode)));
1645e5c12b0Sopenharmony_ci
1655e5c12b0Sopenharmony_ci	filesize = le64_to_cpu(inode->i.i_size);
1665e5c12b0Sopenharmony_ci	free(inode);
1675e5c12b0Sopenharmony_ci	return filesize;
1685e5c12b0Sopenharmony_ci}
1695e5c12b0Sopenharmony_ci
1705e5c12b0Sopenharmony_ciu64 f2fs_read(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
1715e5c12b0Sopenharmony_ci					u64 count, pgoff_t offset)
1725e5c12b0Sopenharmony_ci{
1735e5c12b0Sopenharmony_ci	struct dnode_of_data dn;
1745e5c12b0Sopenharmony_ci	struct node_info ni;
1755e5c12b0Sopenharmony_ci	struct f2fs_node *inode;
1765e5c12b0Sopenharmony_ci	char *blk_buffer;
1775e5c12b0Sopenharmony_ci	u64 filesize;
1785e5c12b0Sopenharmony_ci	u64 off_in_blk;
1795e5c12b0Sopenharmony_ci	u64 len_in_blk;
1805e5c12b0Sopenharmony_ci	u64 read_count;
1815e5c12b0Sopenharmony_ci	u64 remained_blkentries;
1825e5c12b0Sopenharmony_ci	block_t blkaddr;
1835e5c12b0Sopenharmony_ci	void *index_node = NULL;
1845e5c12b0Sopenharmony_ci
1855e5c12b0Sopenharmony_ci	memset(&dn, 0, sizeof(dn));
1865e5c12b0Sopenharmony_ci
1875e5c12b0Sopenharmony_ci	/* Memory allocation for block buffer and inode. */
1885e5c12b0Sopenharmony_ci	blk_buffer = calloc(BLOCK_SZ, 2);
1895e5c12b0Sopenharmony_ci	ASSERT(blk_buffer);
1905e5c12b0Sopenharmony_ci	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
1915e5c12b0Sopenharmony_ci
1925e5c12b0Sopenharmony_ci	/* Read inode */
1935e5c12b0Sopenharmony_ci	get_node_info(sbi, ino, &ni);
1945e5c12b0Sopenharmony_ci	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
1955e5c12b0Sopenharmony_ci	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
1965e5c12b0Sopenharmony_ci	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
1975e5c12b0Sopenharmony_ci
1985e5c12b0Sopenharmony_ci	/* Adjust count with file length. */
1995e5c12b0Sopenharmony_ci	filesize = le64_to_cpu(inode->i.i_size);
2005e5c12b0Sopenharmony_ci	if (offset > filesize)
2015e5c12b0Sopenharmony_ci		count = 0;
2025e5c12b0Sopenharmony_ci	else if (count + offset > filesize)
2035e5c12b0Sopenharmony_ci		count = filesize - offset;
2045e5c12b0Sopenharmony_ci
2055e5c12b0Sopenharmony_ci	/* Main loop for file blocks */
2065e5c12b0Sopenharmony_ci	read_count = remained_blkentries = 0;
2075e5c12b0Sopenharmony_ci	while (count > 0) {
2085e5c12b0Sopenharmony_ci		if (remained_blkentries == 0) {
2095e5c12b0Sopenharmony_ci			set_new_dnode(&dn, inode, NULL, ino);
2105e5c12b0Sopenharmony_ci			get_dnode_of_data(sbi, &dn, F2FS_BYTES_TO_BLK(offset),
2115e5c12b0Sopenharmony_ci					LOOKUP_NODE);
2125e5c12b0Sopenharmony_ci			if (index_node)
2135e5c12b0Sopenharmony_ci				free(index_node);
2145e5c12b0Sopenharmony_ci			index_node = (dn.node_blk == dn.inode_blk) ?
2155e5c12b0Sopenharmony_ci							NULL : dn.node_blk;
2165e5c12b0Sopenharmony_ci			remained_blkentries = ADDRS_PER_PAGE(sbi,
2175e5c12b0Sopenharmony_ci						dn.node_blk, dn.inode_blk);
2185e5c12b0Sopenharmony_ci		}
2195e5c12b0Sopenharmony_ci		ASSERT(remained_blkentries > 0);
2205e5c12b0Sopenharmony_ci
2215e5c12b0Sopenharmony_ci		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
2225e5c12b0Sopenharmony_ci		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR)
2235e5c12b0Sopenharmony_ci			break;
2245e5c12b0Sopenharmony_ci
2255e5c12b0Sopenharmony_ci		off_in_blk = offset % BLOCK_SZ;
2265e5c12b0Sopenharmony_ci		len_in_blk = BLOCK_SZ - off_in_blk;
2275e5c12b0Sopenharmony_ci		if (len_in_blk > count)
2285e5c12b0Sopenharmony_ci			len_in_blk = count;
2295e5c12b0Sopenharmony_ci
2305e5c12b0Sopenharmony_ci		/* Read data from single block. */
2315e5c12b0Sopenharmony_ci		if (len_in_blk < BLOCK_SZ) {
2325e5c12b0Sopenharmony_ci			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
2335e5c12b0Sopenharmony_ci			memcpy(buffer, blk_buffer + off_in_blk, len_in_blk);
2345e5c12b0Sopenharmony_ci		} else {
2355e5c12b0Sopenharmony_ci			/* Direct read */
2365e5c12b0Sopenharmony_ci			ASSERT(dev_read_block(buffer, blkaddr) >= 0);
2375e5c12b0Sopenharmony_ci		}
2385e5c12b0Sopenharmony_ci
2395e5c12b0Sopenharmony_ci		offset += len_in_blk;
2405e5c12b0Sopenharmony_ci		count -= len_in_blk;
2415e5c12b0Sopenharmony_ci		buffer += len_in_blk;
2425e5c12b0Sopenharmony_ci		read_count += len_in_blk;
2435e5c12b0Sopenharmony_ci
2445e5c12b0Sopenharmony_ci		dn.ofs_in_node++;
2455e5c12b0Sopenharmony_ci		remained_blkentries--;
2465e5c12b0Sopenharmony_ci	}
2475e5c12b0Sopenharmony_ci	if (index_node)
2485e5c12b0Sopenharmony_ci		free(index_node);
2495e5c12b0Sopenharmony_ci	free(blk_buffer);
2505e5c12b0Sopenharmony_ci
2515e5c12b0Sopenharmony_ci	return read_count;
2525e5c12b0Sopenharmony_ci}
2535e5c12b0Sopenharmony_ci
2545e5c12b0Sopenharmony_ci/*
2555e5c12b0Sopenharmony_ci * Do not call this function directly.  Instead, call one of the following:
2565e5c12b0Sopenharmony_ci *     u64 f2fs_write();
2575e5c12b0Sopenharmony_ci *     u64 f2fs_write_compress_data();
2585e5c12b0Sopenharmony_ci *     u64 f2fs_write_addrtag();
2595e5c12b0Sopenharmony_ci */
2605e5c12b0Sopenharmony_cistatic u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
2615e5c12b0Sopenharmony_ci		u64 count, pgoff_t offset, enum wr_addr_type addr_type)
2625e5c12b0Sopenharmony_ci{
2635e5c12b0Sopenharmony_ci	struct dnode_of_data dn;
2645e5c12b0Sopenharmony_ci	struct node_info ni;
2655e5c12b0Sopenharmony_ci	struct f2fs_node *inode;
2665e5c12b0Sopenharmony_ci	char *blk_buffer;
2675e5c12b0Sopenharmony_ci	u64 off_in_blk;
2685e5c12b0Sopenharmony_ci	u64 len_in_blk;
2695e5c12b0Sopenharmony_ci	u64 written_count;
2705e5c12b0Sopenharmony_ci	u64 remained_blkentries;
2715e5c12b0Sopenharmony_ci	block_t blkaddr;
2725e5c12b0Sopenharmony_ci	void* index_node = NULL;
2735e5c12b0Sopenharmony_ci	int idirty = 0;
2745e5c12b0Sopenharmony_ci	int err;
2755e5c12b0Sopenharmony_ci	bool has_data = (addr_type == WR_NORMAL
2765e5c12b0Sopenharmony_ci			|| addr_type == WR_COMPRESS_DATA);
2775e5c12b0Sopenharmony_ci
2785e5c12b0Sopenharmony_ci	if (count == 0)
2795e5c12b0Sopenharmony_ci		return 0;
2805e5c12b0Sopenharmony_ci
2815e5c12b0Sopenharmony_ci	/*
2825e5c12b0Sopenharmony_ci	 * Enforce calling from f2fs_write(), f2fs_write_compress_data(),
2835e5c12b0Sopenharmony_ci	 * and f2fs_write_addrtag().   Beside, check if is properly called.
2845e5c12b0Sopenharmony_ci	 */
2855e5c12b0Sopenharmony_ci	ASSERT((!has_data && buffer == NULL) || (has_data && buffer != NULL));
2865e5c12b0Sopenharmony_ci	if (addr_type != WR_NORMAL)
2875e5c12b0Sopenharmony_ci		ASSERT(offset % F2FS_BLKSIZE == 0); /* block boundary only */
2885e5c12b0Sopenharmony_ci
2895e5c12b0Sopenharmony_ci	/* Memory allocation for block buffer and inode. */
2905e5c12b0Sopenharmony_ci	blk_buffer = calloc(BLOCK_SZ, 2);
2915e5c12b0Sopenharmony_ci	ASSERT(blk_buffer);
2925e5c12b0Sopenharmony_ci	inode = (struct f2fs_node*)(blk_buffer + BLOCK_SZ);
2935e5c12b0Sopenharmony_ci
2945e5c12b0Sopenharmony_ci	/* Read inode */
2955e5c12b0Sopenharmony_ci	get_node_info(sbi, ino, &ni);
2965e5c12b0Sopenharmony_ci	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
2975e5c12b0Sopenharmony_ci	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
2985e5c12b0Sopenharmony_ci	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
2995e5c12b0Sopenharmony_ci
3005e5c12b0Sopenharmony_ci	/* Main loop for file blocks */
3015e5c12b0Sopenharmony_ci	written_count = remained_blkentries = 0;
3025e5c12b0Sopenharmony_ci	while (count > 0) {
3035e5c12b0Sopenharmony_ci		if (remained_blkentries == 0) {
3045e5c12b0Sopenharmony_ci			set_new_dnode(&dn, inode, NULL, ino);
3055e5c12b0Sopenharmony_ci			err = get_dnode_of_data(sbi, &dn,
3065e5c12b0Sopenharmony_ci					F2FS_BYTES_TO_BLK(offset), ALLOC_NODE);
3075e5c12b0Sopenharmony_ci			if (err)
3085e5c12b0Sopenharmony_ci				break;
3095e5c12b0Sopenharmony_ci			idirty |= dn.idirty;
3105e5c12b0Sopenharmony_ci			free(index_node);
3115e5c12b0Sopenharmony_ci			index_node = (dn.node_blk == dn.inode_blk) ?
3125e5c12b0Sopenharmony_ci					NULL : dn.node_blk;
3135e5c12b0Sopenharmony_ci			remained_blkentries = ADDRS_PER_PAGE(sbi,
3145e5c12b0Sopenharmony_ci					dn.node_blk, dn.inode_blk) -
3155e5c12b0Sopenharmony_ci					dn.ofs_in_node;
3165e5c12b0Sopenharmony_ci		}
3175e5c12b0Sopenharmony_ci		ASSERT(remained_blkentries > 0);
3185e5c12b0Sopenharmony_ci
3195e5c12b0Sopenharmony_ci		if (!has_data) {
3205e5c12b0Sopenharmony_ci			dn.data_blkaddr = addr_type;
3215e5c12b0Sopenharmony_ci			set_data_blkaddr(&dn);
3225e5c12b0Sopenharmony_ci			idirty |= dn.idirty;
3235e5c12b0Sopenharmony_ci			if (dn.ndirty)
3245e5c12b0Sopenharmony_ci				ASSERT(dev_write_block(dn.node_blk,
3255e5c12b0Sopenharmony_ci						dn.node_blkaddr) >= 0);
3265e5c12b0Sopenharmony_ci			written_count = 0;
3275e5c12b0Sopenharmony_ci			break;
3285e5c12b0Sopenharmony_ci		}
3295e5c12b0Sopenharmony_ci
3305e5c12b0Sopenharmony_ci		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
3315e5c12b0Sopenharmony_ci		if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
3325e5c12b0Sopenharmony_ci			err = new_data_block(sbi, blk_buffer,
3335e5c12b0Sopenharmony_ci						&dn, CURSEG_WARM_DATA);
3345e5c12b0Sopenharmony_ci			if (err)
3355e5c12b0Sopenharmony_ci				break;
3365e5c12b0Sopenharmony_ci			blkaddr = dn.data_blkaddr;
3375e5c12b0Sopenharmony_ci			idirty |= dn.idirty;
3385e5c12b0Sopenharmony_ci		}
3395e5c12b0Sopenharmony_ci
3405e5c12b0Sopenharmony_ci		off_in_blk = offset % BLOCK_SZ;
3415e5c12b0Sopenharmony_ci		len_in_blk = BLOCK_SZ - off_in_blk;
3425e5c12b0Sopenharmony_ci		if (len_in_blk > count)
3435e5c12b0Sopenharmony_ci			len_in_blk = count;
3445e5c12b0Sopenharmony_ci
3455e5c12b0Sopenharmony_ci		/* Write data to single block. */
3465e5c12b0Sopenharmony_ci		if (len_in_blk < BLOCK_SZ) {
3475e5c12b0Sopenharmony_ci			ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
3485e5c12b0Sopenharmony_ci			memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
3495e5c12b0Sopenharmony_ci			ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
3505e5c12b0Sopenharmony_ci		} else {
3515e5c12b0Sopenharmony_ci			/* Direct write */
3525e5c12b0Sopenharmony_ci			ASSERT(dev_write_block(buffer, blkaddr) >= 0);
3535e5c12b0Sopenharmony_ci		}
3545e5c12b0Sopenharmony_ci
3555e5c12b0Sopenharmony_ci		offset += len_in_blk;
3565e5c12b0Sopenharmony_ci		count -= len_in_blk;
3575e5c12b0Sopenharmony_ci		buffer += len_in_blk;
3585e5c12b0Sopenharmony_ci		written_count += len_in_blk;
3595e5c12b0Sopenharmony_ci
3605e5c12b0Sopenharmony_ci		dn.ofs_in_node++;
3615e5c12b0Sopenharmony_ci		if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
3625e5c12b0Sopenharmony_ci			ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr)
3635e5c12b0Sopenharmony_ci					>= 0);
3645e5c12b0Sopenharmony_ci	}
3655e5c12b0Sopenharmony_ci	if (addr_type == WR_NORMAL && offset > le64_to_cpu(inode->i.i_size)) {
3665e5c12b0Sopenharmony_ci		inode->i.i_size = cpu_to_le64(offset);
3675e5c12b0Sopenharmony_ci		idirty = 1;
3685e5c12b0Sopenharmony_ci	}
3695e5c12b0Sopenharmony_ci	if (idirty) {
3705e5c12b0Sopenharmony_ci		ASSERT(inode == dn.inode_blk);
3715e5c12b0Sopenharmony_ci		ASSERT(write_inode(inode, ni.blk_addr) >= 0);
3725e5c12b0Sopenharmony_ci	}
3735e5c12b0Sopenharmony_ci
3745e5c12b0Sopenharmony_ci	free(index_node);
3755e5c12b0Sopenharmony_ci	free(blk_buffer);
3765e5c12b0Sopenharmony_ci
3775e5c12b0Sopenharmony_ci	return written_count;
3785e5c12b0Sopenharmony_ci}
3795e5c12b0Sopenharmony_ci
3805e5c12b0Sopenharmony_ciu64 f2fs_write(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
3815e5c12b0Sopenharmony_ci					u64 count, pgoff_t offset)
3825e5c12b0Sopenharmony_ci{
3835e5c12b0Sopenharmony_ci	return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_NORMAL);
3845e5c12b0Sopenharmony_ci}
3855e5c12b0Sopenharmony_ci
3865e5c12b0Sopenharmony_ciu64 f2fs_write_compress_data(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
3875e5c12b0Sopenharmony_ci					u64 count, pgoff_t offset)
3885e5c12b0Sopenharmony_ci{
3895e5c12b0Sopenharmony_ci	return f2fs_write_ex(sbi, ino, buffer, count, offset, WR_COMPRESS_DATA);
3905e5c12b0Sopenharmony_ci}
3915e5c12b0Sopenharmony_ci
3925e5c12b0Sopenharmony_ciu64 f2fs_write_addrtag(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset,
3935e5c12b0Sopenharmony_ci		unsigned int addrtag)
3945e5c12b0Sopenharmony_ci{
3955e5c12b0Sopenharmony_ci	ASSERT(addrtag == COMPRESS_ADDR || addrtag == NEW_ADDR
3965e5c12b0Sopenharmony_ci			|| addrtag == NULL_ADDR);
3975e5c12b0Sopenharmony_ci	return f2fs_write_ex(sbi, ino, NULL, F2FS_BLKSIZE, offset, addrtag);
3985e5c12b0Sopenharmony_ci}
3995e5c12b0Sopenharmony_ci
4005e5c12b0Sopenharmony_ci/* This function updates only inode->i.i_size */
4015e5c12b0Sopenharmony_civoid f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)
4025e5c12b0Sopenharmony_ci{
4035e5c12b0Sopenharmony_ci	struct node_info ni;
4045e5c12b0Sopenharmony_ci	struct f2fs_node *inode;
4055e5c12b0Sopenharmony_ci
4065e5c12b0Sopenharmony_ci	inode = calloc(BLOCK_SZ, 1);
4075e5c12b0Sopenharmony_ci	ASSERT(inode);
4085e5c12b0Sopenharmony_ci	get_node_info(sbi, ino, &ni);
4095e5c12b0Sopenharmony_ci
4105e5c12b0Sopenharmony_ci	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
4115e5c12b0Sopenharmony_ci	ASSERT(!S_ISDIR(le16_to_cpu(inode->i.i_mode)));
4125e5c12b0Sopenharmony_ci	ASSERT(!S_ISLNK(le16_to_cpu(inode->i.i_mode)));
4135e5c12b0Sopenharmony_ci
4145e5c12b0Sopenharmony_ci	inode->i.i_size = cpu_to_le64(filesize);
4155e5c12b0Sopenharmony_ci
4165e5c12b0Sopenharmony_ci	ASSERT(write_inode(inode, ni.blk_addr) >= 0);
4175e5c12b0Sopenharmony_ci	free(inode);
4185e5c12b0Sopenharmony_ci}
4195e5c12b0Sopenharmony_ci
4205e5c12b0Sopenharmony_ci#define MAX_BULKR_RETRY 5
4215e5c12b0Sopenharmony_ciint bulkread(int fd, void *rbuf, size_t rsize, bool *eof)
4225e5c12b0Sopenharmony_ci{
4235e5c12b0Sopenharmony_ci	int n = 0;
4245e5c12b0Sopenharmony_ci	int retry = MAX_BULKR_RETRY;
4255e5c12b0Sopenharmony_ci	int cur;
4265e5c12b0Sopenharmony_ci
4275e5c12b0Sopenharmony_ci	if (!rsize)
4285e5c12b0Sopenharmony_ci		return 0;
4295e5c12b0Sopenharmony_ci
4305e5c12b0Sopenharmony_ci	if (eof != NULL)
4315e5c12b0Sopenharmony_ci		*eof = false;
4325e5c12b0Sopenharmony_ci	while (rsize && (cur = read(fd, rbuf, rsize)) != 0) {
4335e5c12b0Sopenharmony_ci		if (cur == -1) {
4345e5c12b0Sopenharmony_ci			if (errno == EINTR && retry--)
4355e5c12b0Sopenharmony_ci				continue;
4365e5c12b0Sopenharmony_ci			return -1;
4375e5c12b0Sopenharmony_ci		}
4385e5c12b0Sopenharmony_ci		retry = MAX_BULKR_RETRY;
4395e5c12b0Sopenharmony_ci
4405e5c12b0Sopenharmony_ci		rsize -= cur;
4415e5c12b0Sopenharmony_ci		n += cur;
4425e5c12b0Sopenharmony_ci	}
4435e5c12b0Sopenharmony_ci	if (eof != NULL)
4445e5c12b0Sopenharmony_ci		*eof = (cur == 0);
4455e5c12b0Sopenharmony_ci	return n;
4465e5c12b0Sopenharmony_ci}
4475e5c12b0Sopenharmony_ci
4485e5c12b0Sopenharmony_ciu64 f2fs_fix_mutable(struct f2fs_sb_info *sbi, nid_t ino, pgoff_t offset,
4495e5c12b0Sopenharmony_ci		unsigned int compressed)
4505e5c12b0Sopenharmony_ci{
4515e5c12b0Sopenharmony_ci	unsigned int i;
4525e5c12b0Sopenharmony_ci	u64 wlen;
4535e5c12b0Sopenharmony_ci
4545e5c12b0Sopenharmony_ci	if (c.compress.readonly)
4555e5c12b0Sopenharmony_ci		return 0;
4565e5c12b0Sopenharmony_ci
4575e5c12b0Sopenharmony_ci	for (i = 0; i < compressed - 1; i++) {
4585e5c12b0Sopenharmony_ci		wlen = f2fs_write_addrtag(sbi, ino,
4595e5c12b0Sopenharmony_ci				offset + (i << F2FS_BLKSIZE_BITS), NEW_ADDR);
4605e5c12b0Sopenharmony_ci		if (wlen)
4615e5c12b0Sopenharmony_ci			return wlen;
4625e5c12b0Sopenharmony_ci	}
4635e5c12b0Sopenharmony_ci	return 0;
4645e5c12b0Sopenharmony_ci}
4655e5c12b0Sopenharmony_ci
4665e5c12b0Sopenharmony_cistatic inline int is_consecutive(u32 prev_addr, u32 cur_addr)
4675e5c12b0Sopenharmony_ci{
4685e5c12b0Sopenharmony_ci	if (is_valid_data_blkaddr(cur_addr) && (cur_addr == prev_addr + 1))
4695e5c12b0Sopenharmony_ci		return 1;
4705e5c12b0Sopenharmony_ci	return 0;
4715e5c12b0Sopenharmony_ci}
4725e5c12b0Sopenharmony_ci
4735e5c12b0Sopenharmony_cistatic inline void copy_extent_info(struct extent_info *t_ext,
4745e5c12b0Sopenharmony_ci				struct extent_info *s_ext)
4755e5c12b0Sopenharmony_ci{
4765e5c12b0Sopenharmony_ci	t_ext->fofs = s_ext->fofs;
4775e5c12b0Sopenharmony_ci	t_ext->blk = s_ext->blk;
4785e5c12b0Sopenharmony_ci	t_ext->len = s_ext->len;
4795e5c12b0Sopenharmony_ci}
4805e5c12b0Sopenharmony_ci
4815e5c12b0Sopenharmony_cistatic inline void update_extent_info(struct f2fs_node *inode,
4825e5c12b0Sopenharmony_ci				struct extent_info *ext)
4835e5c12b0Sopenharmony_ci{
4845e5c12b0Sopenharmony_ci	inode->i.i_ext.fofs = cpu_to_le32(ext->fofs);
4855e5c12b0Sopenharmony_ci	inode->i.i_ext.blk_addr = cpu_to_le32(ext->blk);
4865e5c12b0Sopenharmony_ci	inode->i.i_ext.len = cpu_to_le32(ext->len);
4875e5c12b0Sopenharmony_ci}
4885e5c12b0Sopenharmony_ci
4895e5c12b0Sopenharmony_cistatic void update_largest_extent(struct f2fs_sb_info *sbi, nid_t ino)
4905e5c12b0Sopenharmony_ci{
4915e5c12b0Sopenharmony_ci	struct dnode_of_data dn;
4925e5c12b0Sopenharmony_ci	struct node_info ni;
4935e5c12b0Sopenharmony_ci	struct f2fs_node *inode;
4945e5c12b0Sopenharmony_ci	u32 blkaddr, prev_blkaddr, cur_blk = 0, end_blk;
4955e5c12b0Sopenharmony_ci	struct extent_info largest_ext, cur_ext;
4965e5c12b0Sopenharmony_ci	u64 remained_blkentries = 0;
4975e5c12b0Sopenharmony_ci	u32 cluster_size;
4985e5c12b0Sopenharmony_ci	int count;
4995e5c12b0Sopenharmony_ci	void *index_node = NULL;
5005e5c12b0Sopenharmony_ci
5015e5c12b0Sopenharmony_ci	memset(&dn, 0, sizeof(dn));
5025e5c12b0Sopenharmony_ci	largest_ext.len = cur_ext.len = 0;
5035e5c12b0Sopenharmony_ci
5045e5c12b0Sopenharmony_ci	inode = (struct f2fs_node *) calloc(BLOCK_SZ, 1);
5055e5c12b0Sopenharmony_ci	ASSERT(inode);
5065e5c12b0Sopenharmony_ci
5075e5c12b0Sopenharmony_ci	/* Read inode info */
5085e5c12b0Sopenharmony_ci	get_node_info(sbi, ino, &ni);
5095e5c12b0Sopenharmony_ci	ASSERT(dev_read_block(inode, ni.blk_addr) >= 0);
5105e5c12b0Sopenharmony_ci	cluster_size = 1 << inode->i.i_log_cluster_size;
5115e5c12b0Sopenharmony_ci
5125e5c12b0Sopenharmony_ci	if (inode->i.i_inline & F2FS_INLINE_DATA)
5135e5c12b0Sopenharmony_ci		goto exit;
5145e5c12b0Sopenharmony_ci
5155e5c12b0Sopenharmony_ci	end_blk  = f2fs_max_file_offset(&inode->i) >> F2FS_BLKSIZE_BITS;
5165e5c12b0Sopenharmony_ci
5175e5c12b0Sopenharmony_ci	while (cur_blk <= end_blk) {
5185e5c12b0Sopenharmony_ci		if (remained_blkentries == 0) {
5195e5c12b0Sopenharmony_ci			set_new_dnode(&dn, inode, NULL, ino);
5205e5c12b0Sopenharmony_ci			get_dnode_of_data(sbi, &dn, cur_blk, LOOKUP_NODE);
5215e5c12b0Sopenharmony_ci			if (index_node)
5225e5c12b0Sopenharmony_ci				free(index_node);
5235e5c12b0Sopenharmony_ci			index_node = (dn.node_blk == dn.inode_blk) ?
5245e5c12b0Sopenharmony_ci				NULL : dn.node_blk;
5255e5c12b0Sopenharmony_ci			remained_blkentries = ADDRS_PER_PAGE(sbi,
5265e5c12b0Sopenharmony_ci					dn.node_blk, dn.inode_blk);
5275e5c12b0Sopenharmony_ci		}
5285e5c12b0Sopenharmony_ci		ASSERT(remained_blkentries > 0);
5295e5c12b0Sopenharmony_ci
5305e5c12b0Sopenharmony_ci		blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
5315e5c12b0Sopenharmony_ci		if (cur_ext.len > 0) {
5325e5c12b0Sopenharmony_ci			if (is_consecutive(prev_blkaddr, blkaddr))
5335e5c12b0Sopenharmony_ci				cur_ext.len++;
5345e5c12b0Sopenharmony_ci			else {
5355e5c12b0Sopenharmony_ci				if (cur_ext.len > largest_ext.len)
5365e5c12b0Sopenharmony_ci					copy_extent_info(&largest_ext,
5375e5c12b0Sopenharmony_ci							&cur_ext);
5385e5c12b0Sopenharmony_ci				cur_ext.len = 0;
5395e5c12b0Sopenharmony_ci			}
5405e5c12b0Sopenharmony_ci		}
5415e5c12b0Sopenharmony_ci
5425e5c12b0Sopenharmony_ci		if (cur_ext.len == 0 && is_valid_data_blkaddr(blkaddr)) {
5435e5c12b0Sopenharmony_ci			cur_ext.fofs = cur_blk;
5445e5c12b0Sopenharmony_ci			cur_ext.len = 1;
5455e5c12b0Sopenharmony_ci			cur_ext.blk = blkaddr;
5465e5c12b0Sopenharmony_ci		}
5475e5c12b0Sopenharmony_ci
5485e5c12b0Sopenharmony_ci		prev_blkaddr = blkaddr;
5495e5c12b0Sopenharmony_ci		count = blkaddr == COMPRESS_ADDR ? cluster_size : 1;
5505e5c12b0Sopenharmony_ci		cur_blk += count;
5515e5c12b0Sopenharmony_ci		dn.ofs_in_node += count;
5525e5c12b0Sopenharmony_ci		remained_blkentries -= count;
5535e5c12b0Sopenharmony_ci	}
5545e5c12b0Sopenharmony_ci
5555e5c12b0Sopenharmony_ciexit:
5565e5c12b0Sopenharmony_ci	if (cur_ext.len > largest_ext.len)
5575e5c12b0Sopenharmony_ci		copy_extent_info(&largest_ext, &cur_ext);
5585e5c12b0Sopenharmony_ci	if (largest_ext.len > 0) {
5595e5c12b0Sopenharmony_ci		update_extent_info(inode, &largest_ext);
5605e5c12b0Sopenharmony_ci		ASSERT(write_inode(inode, ni.blk_addr) >= 0);
5615e5c12b0Sopenharmony_ci	}
5625e5c12b0Sopenharmony_ci
5635e5c12b0Sopenharmony_ci	if (index_node)
5645e5c12b0Sopenharmony_ci		free(index_node);
5655e5c12b0Sopenharmony_ci	free(inode);
5665e5c12b0Sopenharmony_ci}
5675e5c12b0Sopenharmony_ci
5685e5c12b0Sopenharmony_ciint f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
5695e5c12b0Sopenharmony_ci{
5705e5c12b0Sopenharmony_ci	int fd, n = -1;
5715e5c12b0Sopenharmony_ci	pgoff_t off = 0;
5725e5c12b0Sopenharmony_ci	u8 buffer[BLOCK_SZ];
5735e5c12b0Sopenharmony_ci	struct node_info ni;
5745e5c12b0Sopenharmony_ci	struct f2fs_node *node_blk;
5755e5c12b0Sopenharmony_ci
5765e5c12b0Sopenharmony_ci	if (de->ino == 0)
5775e5c12b0Sopenharmony_ci		return -1;
5785e5c12b0Sopenharmony_ci
5795e5c12b0Sopenharmony_ci	if (de->from_devino) {
5805e5c12b0Sopenharmony_ci		struct hardlink_cache_entry *found_hardlink;
5815e5c12b0Sopenharmony_ci
5825e5c12b0Sopenharmony_ci		found_hardlink = f2fs_search_hardlink(sbi, de);
5835e5c12b0Sopenharmony_ci		if (found_hardlink && found_hardlink->to_ino &&
5845e5c12b0Sopenharmony_ci				found_hardlink->nbuild)
5855e5c12b0Sopenharmony_ci			return 0;
5865e5c12b0Sopenharmony_ci
5875e5c12b0Sopenharmony_ci		found_hardlink->nbuild++;
5885e5c12b0Sopenharmony_ci	}
5895e5c12b0Sopenharmony_ci
5905e5c12b0Sopenharmony_ci	fd = open(de->full_path, O_RDONLY);
5915e5c12b0Sopenharmony_ci	if (fd < 0) {
5925e5c12b0Sopenharmony_ci		MSG(0, "Skip: Fail to open %s\n", de->full_path);
5935e5c12b0Sopenharmony_ci		return -1;
5945e5c12b0Sopenharmony_ci	}
5955e5c12b0Sopenharmony_ci
5965e5c12b0Sopenharmony_ci	/* inline_data support */
5975e5c12b0Sopenharmony_ci	if (de->size <= DEF_MAX_INLINE_DATA) {
5985e5c12b0Sopenharmony_ci		int ret;
5995e5c12b0Sopenharmony_ci
6005e5c12b0Sopenharmony_ci		get_node_info(sbi, de->ino, &ni);
6015e5c12b0Sopenharmony_ci
6025e5c12b0Sopenharmony_ci		node_blk = calloc(BLOCK_SZ, 1);
6035e5c12b0Sopenharmony_ci		ASSERT(node_blk);
6045e5c12b0Sopenharmony_ci
6055e5c12b0Sopenharmony_ci		ret = dev_read_block(node_blk, ni.blk_addr);
6065e5c12b0Sopenharmony_ci		ASSERT(ret >= 0);
6075e5c12b0Sopenharmony_ci
6085e5c12b0Sopenharmony_ci		node_blk->i.i_inline |= F2FS_INLINE_DATA;
6095e5c12b0Sopenharmony_ci		node_blk->i.i_inline |= F2FS_DATA_EXIST;
6105e5c12b0Sopenharmony_ci
6115e5c12b0Sopenharmony_ci		if (c.feature & cpu_to_le32(F2FS_FEATURE_EXTRA_ATTR)) {
6125e5c12b0Sopenharmony_ci			node_blk->i.i_inline |= F2FS_EXTRA_ATTR;
6135e5c12b0Sopenharmony_ci			node_blk->i.i_extra_isize =
6145e5c12b0Sopenharmony_ci					cpu_to_le16(calc_extra_isize());
6155e5c12b0Sopenharmony_ci		}
6165e5c12b0Sopenharmony_ci		n = read(fd, buffer, BLOCK_SZ);
6175e5c12b0Sopenharmony_ci		ASSERT((unsigned long)n == de->size);
6185e5c12b0Sopenharmony_ci		memcpy(inline_data_addr(node_blk), buffer, de->size);
6195e5c12b0Sopenharmony_ci		node_blk->i.i_size = cpu_to_le64(de->size);
6205e5c12b0Sopenharmony_ci		ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
6215e5c12b0Sopenharmony_ci		free(node_blk);
6225e5c12b0Sopenharmony_ci#ifdef WITH_SLOAD
6235e5c12b0Sopenharmony_ci	} else if (c.func == SLOAD && c.compress.enabled &&
6245e5c12b0Sopenharmony_ci			c.compress.filter_ops->filter(de->full_path)) {
6255e5c12b0Sopenharmony_ci		bool eof = false;
6265e5c12b0Sopenharmony_ci		u8 *rbuf = c.compress.cc.rbuf;
6275e5c12b0Sopenharmony_ci		unsigned int cblocks = 0;
6285e5c12b0Sopenharmony_ci
6295e5c12b0Sopenharmony_ci		node_blk = calloc(BLOCK_SZ, 1);
6305e5c12b0Sopenharmony_ci		ASSERT(node_blk);
6315e5c12b0Sopenharmony_ci
6325e5c12b0Sopenharmony_ci		/* read inode */
6335e5c12b0Sopenharmony_ci		get_node_info(sbi, de->ino, &ni);
6345e5c12b0Sopenharmony_ci		ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0);
6355e5c12b0Sopenharmony_ci		/* update inode meta */
6365e5c12b0Sopenharmony_ci		node_blk->i.i_compress_algrithm = c.compress.alg;
6375e5c12b0Sopenharmony_ci		node_blk->i.i_log_cluster_size =
6385e5c12b0Sopenharmony_ci				c.compress.cc.log_cluster_size;
6395e5c12b0Sopenharmony_ci		node_blk->i.i_flags = cpu_to_le32(F2FS_COMPR_FL);
6405e5c12b0Sopenharmony_ci		if (c.compress.readonly)
6415e5c12b0Sopenharmony_ci			node_blk->i.i_inline |= F2FS_COMPRESS_RELEASED;
6425e5c12b0Sopenharmony_ci		ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
6435e5c12b0Sopenharmony_ci
6445e5c12b0Sopenharmony_ci		while (!eof && (n = bulkread(fd, rbuf, c.compress.cc.rlen,
6455e5c12b0Sopenharmony_ci				&eof)) > 0) {
6465e5c12b0Sopenharmony_ci			int ret = c.compress.ops->compress(&c.compress.cc);
6475e5c12b0Sopenharmony_ci			u64 wlen;
6485e5c12b0Sopenharmony_ci			u32 csize = ALIGN_UP(c.compress.cc.clen +
6495e5c12b0Sopenharmony_ci					COMPRESS_HEADER_SIZE, BLOCK_SZ);
6505e5c12b0Sopenharmony_ci			unsigned int cur_cblk;
6515e5c12b0Sopenharmony_ci
6525e5c12b0Sopenharmony_ci			if (ret || n < c.compress.cc.rlen ||
6535e5c12b0Sopenharmony_ci				n < (int)(csize + BLOCK_SZ *
6545e5c12b0Sopenharmony_ci						c.compress.min_blocks)) {
6555e5c12b0Sopenharmony_ci				wlen = f2fs_write(sbi, de->ino, rbuf, n, off);
6565e5c12b0Sopenharmony_ci				ASSERT((int)wlen == n);
6575e5c12b0Sopenharmony_ci			} else {
6585e5c12b0Sopenharmony_ci				wlen = f2fs_write_addrtag(sbi, de->ino, off,
6595e5c12b0Sopenharmony_ci						WR_COMPRESS_ADDR);
6605e5c12b0Sopenharmony_ci				ASSERT(!wlen);
6615e5c12b0Sopenharmony_ci				wlen = f2fs_write_compress_data(sbi, de->ino,
6625e5c12b0Sopenharmony_ci						(u8 *)c.compress.cc.cbuf,
6635e5c12b0Sopenharmony_ci						csize, off + BLOCK_SZ);
6645e5c12b0Sopenharmony_ci				ASSERT(wlen == csize);
6655e5c12b0Sopenharmony_ci				c.compress.ops->reset(&c.compress.cc);
6665e5c12b0Sopenharmony_ci				cur_cblk = (c.compress.cc.rlen - csize) /
6675e5c12b0Sopenharmony_ci								BLOCK_SZ;
6685e5c12b0Sopenharmony_ci				cblocks += cur_cblk;
6695e5c12b0Sopenharmony_ci				wlen = f2fs_fix_mutable(sbi, de->ino,
6705e5c12b0Sopenharmony_ci						off + BLOCK_SZ + csize,
6715e5c12b0Sopenharmony_ci						cur_cblk);
6725e5c12b0Sopenharmony_ci				ASSERT(!wlen);
6735e5c12b0Sopenharmony_ci			}
6745e5c12b0Sopenharmony_ci			off += n;
6755e5c12b0Sopenharmony_ci		}
6765e5c12b0Sopenharmony_ci		if (n == -1) {
6775e5c12b0Sopenharmony_ci			fprintf(stderr, "Load file '%s' failed: ",
6785e5c12b0Sopenharmony_ci					de->full_path);
6795e5c12b0Sopenharmony_ci			perror(NULL);
6805e5c12b0Sopenharmony_ci		}
6815e5c12b0Sopenharmony_ci		/* read inode */
6825e5c12b0Sopenharmony_ci		get_node_info(sbi, de->ino, &ni);
6835e5c12b0Sopenharmony_ci		ASSERT(dev_read_block(node_blk, ni.blk_addr) >= 0);
6845e5c12b0Sopenharmony_ci		/* update inode meta */
6855e5c12b0Sopenharmony_ci		node_blk->i.i_size = cpu_to_le64(off);
6865e5c12b0Sopenharmony_ci		if (!c.compress.readonly) {
6875e5c12b0Sopenharmony_ci			node_blk->i.i_compr_blocks = cpu_to_le64(cblocks);
6885e5c12b0Sopenharmony_ci			node_blk->i.i_blocks += cpu_to_le64(cblocks);
6895e5c12b0Sopenharmony_ci		}
6905e5c12b0Sopenharmony_ci		ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
6915e5c12b0Sopenharmony_ci		free(node_blk);
6925e5c12b0Sopenharmony_ci
6935e5c12b0Sopenharmony_ci		if (!c.compress.readonly) {
6945e5c12b0Sopenharmony_ci			sbi->total_valid_block_count += cblocks;
6955e5c12b0Sopenharmony_ci			if (sbi->total_valid_block_count >=
6965e5c12b0Sopenharmony_ci					sbi->user_block_count) {
6975e5c12b0Sopenharmony_ci				ERR_MSG("Not enough space\n");
6985e5c12b0Sopenharmony_ci				ASSERT(0);
6995e5c12b0Sopenharmony_ci			}
7005e5c12b0Sopenharmony_ci		}
7015e5c12b0Sopenharmony_ci#endif
7025e5c12b0Sopenharmony_ci	} else {
7035e5c12b0Sopenharmony_ci		while ((n = read(fd, buffer, BLOCK_SZ)) > 0) {
7045e5c12b0Sopenharmony_ci			f2fs_write(sbi, de->ino, buffer, n, off);
7055e5c12b0Sopenharmony_ci			off += n;
7065e5c12b0Sopenharmony_ci		}
7075e5c12b0Sopenharmony_ci	}
7085e5c12b0Sopenharmony_ci
7095e5c12b0Sopenharmony_ci	close(fd);
7105e5c12b0Sopenharmony_ci	if (n < 0)
7115e5c12b0Sopenharmony_ci		return -1;
7125e5c12b0Sopenharmony_ci
7135e5c12b0Sopenharmony_ci	if (!c.compress.enabled || (c.feature & cpu_to_le32(F2FS_FEATURE_RO)))
7145e5c12b0Sopenharmony_ci		update_largest_extent(sbi, de->ino);
7155e5c12b0Sopenharmony_ci	update_free_segments(sbi);
7165e5c12b0Sopenharmony_ci
7175e5c12b0Sopenharmony_ci	MSG(1, "Info: Create %s -> %s\n"
7185e5c12b0Sopenharmony_ci		"  -- ino=%x, type=%x, mode=%x, uid=%x, "
7195e5c12b0Sopenharmony_ci		"gid=%x, cap=%"PRIx64", size=%lu, pino=%x\n",
7205e5c12b0Sopenharmony_ci		de->full_path, de->path,
7215e5c12b0Sopenharmony_ci		de->ino, de->file_type, de->mode,
7225e5c12b0Sopenharmony_ci		de->uid, de->gid, de->capabilities, de->size, de->pino);
7235e5c12b0Sopenharmony_ci	return 0;
7245e5c12b0Sopenharmony_ci}
725