2023-11-30 19:02:30

by Daeho Jeong

[permalink] [raw]
Subject: [PATCH] f2fs-tools: support zoned ufs devices

From: Daeho Jeong <[email protected]>

Support zoned ufs devices.
1. implemented out-place updates
2. keep roll forward recovery intact
3. open block device files with O_SYNC to comply with zoned device's
write rules

Signed-off-by: Daeho Jeong <[email protected]>
---
fsck/defrag.c | 2 +-
fsck/dir.c | 47 +++++++++++----
fsck/f2fs.h | 3 +-
fsck/fsck.c | 96 +++++++++++++++++++------------
fsck/fsck.h | 31 +++++++---
fsck/main.c | 3 +
fsck/mount.c | 151 ++++++++++++++++++++++++++++++++++++++++---------
fsck/node.c | 30 ++++++++--
fsck/node.h | 1 +
fsck/resize.c | 2 +-
fsck/segment.c | 120 ++++++++++++++++++++++++++++++++++-----
fsck/xattr.c | 7 ++-
lib/libf2fs.c | 32 +++++++----
13 files changed, 405 insertions(+), 120 deletions(-)

diff --git a/fsck/defrag.c b/fsck/defrag.c
index 90c2962..361fe73 100644
--- a/fsck/defrag.c
+++ b/fsck/defrag.c
@@ -49,7 +49,7 @@ static int migrate_block(struct f2fs_sb_info *sbi, u64 from, u64 to)
/* if data block, read node and update node block */
if (IS_DATASEG(type))
update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
- le16_to_cpu(sum.ofs_in_node), to);
+ le16_to_cpu(sum.ofs_in_node), to, NULL);
else
update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), to);

diff --git a/fsck/dir.c b/fsck/dir.c
index d51176a..3fac850 100644
--- a/fsck/dir.c
+++ b/fsck/dir.c
@@ -220,7 +220,7 @@ static void f2fs_update_dentry(nid_t ino, int file_type,
*/
int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent,
const unsigned char *name, int name_len, nid_t ino,
- int file_type, block_t p_blkaddr, int inc_link)
+ int file_type, block_t *p_blkaddr, int inc_link)
{
int level = 0, current_depth, bit_pos;
int nbucket, nblock, bidx, block;
@@ -232,6 +232,7 @@ int f2fs_add_link(struct f2fs_sb_info *sbi, struct f2fs_node *parent,
nid_t pino;
unsigned int dir_level;
int ret;
+ bool datablk_alloced = false;

if (parent == NULL)
return -EINVAL;
@@ -278,6 +279,7 @@ start:

if (dn.data_blkaddr == NULL_ADDR) {
new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
+ datablk_alloced = true;
} else {
ret = dev_read_block(dentry_blk, dn.data_blkaddr);
ASSERT(ret >= 0);
@@ -295,7 +297,20 @@ add_dentry:
make_dentry_ptr(&d, NULL, (void *)dentry_blk, 1);
f2fs_update_dentry(ino, file_type, &d, name, name_len, dentry_hash, bit_pos);

- ret = dev_write_block(dentry_blk, dn.data_blkaddr);
+ if (c.zoned_model == F2FS_ZONED_HM) {
+ if (datablk_alloced) {
+ ret = dev_write_block(dentry_blk, dn.data_blkaddr);
+ } else {
+ ret = update_block(sbi, dentry_blk, &dn.data_blkaddr,
+ dn.node_blk);
+ if (dn.inode_blk == dn.node_blk)
+ dn.idirty = 1;
+ else
+ dn.ndirty = 1;
+ }
+ } else {
+ ret = dev_write_block(dentry_blk, dn.data_blkaddr);
+ }
ASSERT(ret >= 0);

/*
@@ -321,13 +336,15 @@ add_dentry:
}

if (dn.ndirty) {
- ret = dev_write_block(dn.node_blk, dn.node_blkaddr);
+ ret = dn.alloced ?
+ dev_write_block(dn.node_blk, dn.node_blkaddr) :
+ update_block(sbi, dn.node_blk, &dn.node_blkaddr, NULL);
ASSERT(ret >= 0);
}

if (dn.idirty) {
ASSERT(parent == dn.inode_blk);
- ret = write_inode(dn.inode_blk, p_blkaddr);
+ ret = update_inode(sbi, dn.inode_blk, p_blkaddr);
ASSERT(ret >= 0);
}

@@ -552,7 +569,7 @@ static void init_inode_block(struct f2fs_sb_info *sbi,
}

int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
- block_t p_blkaddr)
+ block_t *p_blkaddr)
{
struct f2fs_inode *inode = &(node->i);
unsigned int dir_level = node->i.i_dir_level;
@@ -562,6 +579,7 @@ int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
struct f2fs_dentry_ptr d;
unsigned long bit_pos = 0;
int ret = 0;
+ bool datablk_alloced = false;

if (!(inode->i_inline & F2FS_INLINE_DENTRY))
return 0;
@@ -570,7 +588,7 @@ int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
memset(inline_data_addr(node), 0, MAX_INLINE_DATA(node));
inode->i_inline &= ~F2FS_INLINE_DENTRY;

- ret = dev_write_block(node, p_blkaddr);
+ ret = update_block(sbi, node, p_blkaddr, NULL);
ASSERT(ret >= 0);

memset(&dn, 0, sizeof(dn));
@@ -583,8 +601,10 @@ int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,

set_new_dnode(&dn, node, NULL, ino);
get_dnode_of_data(sbi, &dn, 0, ALLOC_NODE);
- if (dn.data_blkaddr == NULL_ADDR)
+ if (dn.data_blkaddr == NULL_ADDR) {
new_data_block(sbi, dentry_blk, &dn, CURSEG_HOT_DATA);
+ datablk_alloced = true;
+ }

make_dentry_ptr(&src, node, (void *)inline_data, 2);
make_dentry_ptr(&dst, NULL, (void *)dentry_blk, 1);
@@ -597,7 +617,9 @@ int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
memcpy(dst.dentry, src.dentry, SIZE_OF_DIR_ENTRY * src.max);
memcpy(dst.filename, src.filename, src.max * F2FS_SLOT_LEN);

- ret = dev_write_block(dentry_blk, dn.data_blkaddr);
+ ret = datablk_alloced ?
+ dev_write_block(dentry_blk, dn.data_blkaddr) :
+ update_block(sbi, dentry_blk, &dn.data_blkaddr, NULL);
ASSERT(ret >= 0);

MSG(1, "%s: copy inline entry to block\n", __func__);
@@ -687,6 +709,7 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
struct f2fs_summary sum;
block_t blkaddr = NULL_ADDR;
int ret;
+ bool nodeblk_alloced = false;

/* Find if there is a */
get_node_info(sbi, de->pino, &ni);
@@ -705,7 +728,7 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
ASSERT(ret >= 0);

/* Must convert inline dentry before the following opertions */
- ret = convert_inline_dentry(sbi, parent, ni.blk_addr);
+ ret = convert_inline_dentry(sbi, parent, &ni.blk_addr);
if (ret) {
MSG(0, "Convert inline dentry for pino=%x failed.\n", de->pino);
ret = -1;
@@ -753,7 +776,7 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
le32_to_cpu(child->i.i_namelen),
le32_to_cpu(F2FS_NODE_FOOTER(child)->ino),
map_de_type(le16_to_cpu(child->i.i_mode)),
- ni.blk_addr, 1);
+ &ni.blk_addr, 1);
if (ret) {
MSG(0, "Skip the existing \"%s\" pino=%x ERR=%d\n",
de->name, de->pino, ret);
@@ -788,13 +811,15 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
/* write child */
set_summary(&sum, de->ino, 0, ni.version);
ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE, 1);
+ nodeblk_alloced = true;
ASSERT(!ret);

/* update nat info */
update_nat_blkaddr(sbi, de->ino, de->ino, blkaddr);

write_child_dir:
- ret = dev_write_block(child, blkaddr);
+ ret = nodeblk_alloced ? dev_write_block(child, blkaddr) :
+ update_block(sbi, child, &blkaddr, NULL);
ASSERT(ret >= 0);

update_free_segments(sbi);
diff --git a/fsck/f2fs.h b/fsck/f2fs.h
index b073a94..e31be22 100644
--- a/fsck/f2fs.h
+++ b/fsck/f2fs.h
@@ -189,6 +189,7 @@ struct curseg_info {
struct f2fs_sm_info {
struct sit_info *sit_info;
struct curseg_info *curseg_array;
+ struct curseg_info saved_curseg_warm_node;

block_t seg0_blkaddr;
block_t main_blkaddr;
@@ -238,7 +239,7 @@ struct dnode_of_data {
unsigned int ofs_in_node;
block_t data_blkaddr;
block_t node_blkaddr;
- int idirty, ndirty;
+ int idirty, ndirty, alloced;
};

struct hardlink_cache_entry {
diff --git a/fsck/fsck.c b/fsck/fsck.c
index f40b4cd..8acb822 100644
--- a/fsck/fsck.c
+++ b/fsck/fsck.c
@@ -45,7 +45,7 @@ static inline int f2fs_test_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
fsck->main_area_bitmap);
}

-static inline int f2fs_clear_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+int f2fs_clear_main_bitmap(struct f2fs_sb_info *sbi, u32 blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);

@@ -67,7 +67,7 @@ int f2fs_set_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
return f2fs_set_bit(BLKOFF_FROM_MAIN(sbi, blk), fsck->sit_area_bitmap);
}

-static inline int f2fs_clear_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
+int f2fs_clear_sit_bitmap(struct f2fs_sb_info *sbi, u32 blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);

@@ -1182,7 +1182,9 @@ check_next:
blkaddr,
&child, (i_blocks == *blk_cnt),
ftype, nid, idx, ni->version,
- file_is_encrypt(&node_blk->i));
+ file_is_encrypt(&node_blk->i), node_blk);
+ if (blkaddr != le32_to_cpu(node_blk->i.i_addr[ofs + idx]))
+ need_fix = 1;
if (!ret) {
*blk_cnt = *blk_cnt + 1;
if (cur_qtype != -1 && blkaddr != NEW_ADDR)
@@ -1398,7 +1400,9 @@ skip_blkcnt_fix:
}

if (need_fix && f2fs_dev_is_writable()) {
- ret = dev_write_block(node_blk, ni->blk_addr);
+ if (c.zoned_model == F2FS_ZONED_HM)
+ node_blk->i.i_ext.len = 0;
+ ret = update_block(sbi, node_blk, &ni->blk_addr, NULL);
ASSERT(ret >= 0);
}
}
@@ -1450,7 +1454,9 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
blkaddr, child,
le64_to_cpu(inode->i_blocks) == *blk_cnt, ftype,
nid, idx, ni->version,
- file_is_encrypt(inode));
+ file_is_encrypt(inode), node_blk);
+ if (blkaddr != le32_to_cpu(node_blk->dn.addr[idx]))
+ need_fix = 1;
if (!ret) {
*blk_cnt = *blk_cnt + 1;
if (cur_qtype != -1 && blkaddr != NEW_ADDR)
@@ -1462,7 +1468,7 @@ int fsck_chk_dnode_blk(struct f2fs_sb_info *sbi, struct f2fs_inode *inode,
}
}
if (need_fix && f2fs_dev_is_writable()) {
- ret = dev_write_block(node_blk, ni->blk_addr);
+ ret = update_block(sbi, node_blk, &ni->blk_addr, NULL);
ASSERT(ret >= 0);
}
return 0;
@@ -1504,7 +1510,7 @@ skip:
nid_t nid = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid);

get_node_info(sbi, nid, &ni);
- ret = dev_write_block(node_blk, ni.blk_addr);
+ ret = update_block(sbi, node_blk, &ni.blk_addr, NULL);
ASSERT(ret >= 0);
}

@@ -1546,7 +1552,7 @@ skip:
nid_t nid = le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->nid);

get_node_info(sbi, nid, &ni);
- ret = dev_write_block(node_blk, ni.blk_addr);
+ ret = update_block(sbi, node_blk, &ni.blk_addr, NULL);
ASSERT(ret >= 0);
}

@@ -2004,7 +2010,8 @@ int fsck_chk_inline_dentries(struct f2fs_sb_info *sbi,
}

int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, int casefolded, u32 blk_addr,
- struct child_info *child, int last_blk, int enc_name)
+ struct child_info *child, int last_blk, int enc_name,
+ struct f2fs_node *node_blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
struct f2fs_dentry_block *de_blk;
@@ -2032,7 +2039,7 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, int casefolded, u32 blk_addr,
NR_DENTRY_IN_BLOCK, last_blk, enc_name);

if (dentries < 0 && f2fs_dev_is_writable()) {
- ret = dev_write_block(de_blk, blk_addr);
+ ret = update_block(sbi, de_blk, &blk_addr, node_blk);
ASSERT(ret >= 0);
DBG(1, "[%3d] Dentry Block [0x%x] Fixed hash_codes\n\n",
fsck->dentry_depth, blk_addr);
@@ -2054,7 +2061,7 @@ int fsck_chk_dentry_blk(struct f2fs_sb_info *sbi, int casefolded, u32 blk_addr,
int fsck_chk_data_blk(struct f2fs_sb_info *sbi, int casefolded,
u32 blk_addr, struct child_info *child, int last_blk,
enum FILE_TYPE ftype, u32 parent_nid, u16 idx_in_node, u8 ver,
- int enc_name)
+ int enc_name, struct f2fs_node *node_blk)
{
struct f2fs_fsck *fsck = F2FS_FSCK(sbi);

@@ -2088,7 +2095,7 @@ int fsck_chk_data_blk(struct f2fs_sb_info *sbi, int casefolded,
if (ftype == F2FS_FT_DIR) {
f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_HOT_DATA);
return fsck_chk_dentry_blk(sbi, casefolded, blk_addr, child,
- last_blk, enc_name);
+ last_blk, enc_name, node_blk);
} else {
f2fs_set_main_bitmap(sbi, blk_addr, CURSEG_WARM_DATA);
}
@@ -2456,7 +2463,7 @@ static void fix_hard_links(struct f2fs_sb_info *sbi)
FIX_MSG("File: 0x%x i_links= 0x%x -> 0x%x",
node->nid, node->links, node->actual_links);

- ret = dev_write_block(node_blk, ni.blk_addr);
+ ret = update_block(sbi, node_blk, &ni.blk_addr, NULL);
ASSERT(ret >= 0);
tmp = node;
node = node->next;
@@ -2640,13 +2647,8 @@ static int last_vblk_off_in_zone(struct f2fs_sb_info *sbi,
for (s = segs_per_zone - 1; s >= 0; s--) {
se = get_seg_entry(sbi, zone_segno + s);

- /*
- * Refer not cur_valid_map but ckpt_valid_map which reflects
- * fsync data.
- */
- ASSERT(se->ckpt_valid_map);
for (b = sbi->blocks_per_seg - 1; b >= 0; b--)
- if (f2fs_test_bit(b, (const char*)se->ckpt_valid_map))
+ if (f2fs_test_bit(b, (const char *)se->cur_valid_map))
return b + (s << sbi->log_blocks_per_seg);
}

@@ -2663,6 +2665,9 @@ static int check_curseg_write_pointer(struct f2fs_sb_info *sbi, int type)
int i, ret;
int log_sectors_per_block = sbi->log_blocksize - SECTOR_SHIFT;

+ if (!is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG))
+ return -EINVAL;
+
/* get the device the curseg points to */
cs_block = START_BLOCK(sbi, curseg->segno) + curseg->next_blkoff;
for (i = 0; i < MAX_DEVICES; i++) {
@@ -2695,12 +2700,7 @@ static int check_curseg_write_pointer(struct f2fs_sb_info *sbi, int type)
wp_sector = blk_zone_wp_sector(&blkz);

if (cs_sector == wp_sector) {
- if (is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG))
- return 0;
- MSG(0, "Correct write pointer. But, we can't trust it, "
- "since the previous mount wasn't safely unmounted: "
- "curseg %d[0x%x,0x%x]\n",
- type, curseg->segno, curseg->next_blkoff);
+ return 0;
} else if (cs_sector > wp_sector) {
MSG(0, "Inconsistent write pointer with curseg %d: "
"curseg %d[0x%x,0x%x] > wp[0x%x,0x%x]\n",
@@ -2851,7 +2851,7 @@ static struct f2fs_node *fsck_get_lpf(struct f2fs_sb_info *sbi)
}

/* Must convert inline dentry before adding inodes */
- err = convert_inline_dentry(sbi, node, ni.blk_addr);
+ err = convert_inline_dentry(sbi, node, &ni.blk_addr);
if (err) {
MSG(0, "Convert inline dentry for ino=%x failed.\n",
lpf_ino);
@@ -2913,7 +2913,7 @@ static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi,
get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(lpf)->ino), &ni);
ftype = map_de_type(le16_to_cpu(fnode->i.i_mode));
ret = f2fs_add_link(sbi, lpf, (unsigned char *)name, namelen,
- ino, ftype, ni.blk_addr, 0);
+ ino, ftype, &ni.blk_addr, 0);
if (ret) {
ASSERT_MSG("Failed to add inode [0x%x] to lost+found", ino);
return -EINVAL;
@@ -2924,7 +2924,7 @@ static int fsck_do_reconnect_file(struct f2fs_sb_info *sbi,
fnode->i.i_namelen = cpu_to_le32(namelen);
fnode->i.i_pino = c.lpf_ino;
get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(fnode)->ino), &ni);
- ret = dev_write_block(fnode, ni.blk_addr);
+ ret = update_block(sbi, fnode, &ni.blk_addr, NULL);
ASSERT(ret >= 0);

DBG(1, "Reconnect inode [0x%x] to lost+found\n", ino);
@@ -2964,6 +2964,8 @@ static inline void release_block(struct f2fs_sb_info *sbi, u64 blkaddr,
offset = OFFSET_IN_SEG(sbi, blkaddr);
se->valid_blocks--;
f2fs_clear_bit(offset, (char *)se->cur_valid_map);
+ if (need_fsync_data_record(sbi))
+ f2fs_clear_bit(offset, (char *)se->ckpt_valid_map);
se->dirty = 1;
f2fs_clear_sit_bitmap(sbi, blkaddr);
}
@@ -3381,12 +3383,16 @@ void fsck_chk_and_fix_write_pointers(struct f2fs_sb_info *sbi)
if (c.zoned_model != F2FS_ZONED_HM)
return;

- if (check_curseg_offsets(sbi, true) && c.fix_on) {
- fix_curseg_info(sbi, true);
+ if (c.fix_on) {
+ flush_nat_journal_entries(sbi);
+ flush_sit_journal_entries(sbi);
+
+ if (check_curseg_offsets(sbi, true))
+ fix_curseg_info(sbi, true);
+
+ fix_wp_sit_alignment(sbi);
fsck->chk.wp_fixed = 1;
}
-
- fix_wp_sit_alignment(sbi);
}

int fsck_chk_curseg_info(struct f2fs_sb_info *sbi)
@@ -3623,13 +3629,31 @@ int fsck_verify(struct f2fs_sb_info *sbi)
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);

if (force || c.bug_on || c.bug_nat_bits || c.quota_fixed) {
- /* flush nats to write_nit_bits below */
- flush_journal_entries(sbi);
+ if (c.zoned_model != F2FS_ZONED_HM) {
+ /* flush nats to write_nit_bits below */
+ flush_journal_entries(sbi);
+ }
fix_hard_links(sbi);
fix_nat_entries(sbi);
rewrite_sit_area_bitmap(sbi);
- fix_wp_sit_alignment(sbi);
- fix_curseg_info(sbi, false);
+ if (c.zoned_model == F2FS_ZONED_HM) {
+ struct curseg_info *curseg;
+ u64 ssa_blk;
+
+ for (i = 0; i < NO_CHECK_TYPE; i++) {
+ curseg = CURSEG_I(sbi, i);
+ ssa_blk = GET_SUM_BLKADDR(sbi,
+ curseg->segno);
+ ret = dev_write_block(curseg->sum_blk,
+ ssa_blk);
+ ASSERT(ret >= 0);
+ }
+ if (c.roll_forward)
+ restore_curseg_warm_node_info(sbi);
+ write_curseg_info(sbi);
+ } else {
+ fix_curseg_info(sbi, false);
+ }
fix_checksum(sbi);
fix_checkpoints(sbi);
} else if (is_set_ckpt_flags(cp, CP_FSCK_FLAG) ||
diff --git a/fsck/fsck.h b/fsck/fsck.h
index d6abf18..f5282e2 100644
--- a/fsck/fsck.h
+++ b/fsck/fsck.h
@@ -153,8 +153,7 @@ struct selabel_handle;

static inline bool need_fsync_data_record(struct f2fs_sb_info *sbi)
{
- return !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG) ||
- c.zoned_model == F2FS_ZONED_HM;
+ return !is_set_ckpt_flags(F2FS_CKPT(sbi), CP_UMOUNT_FLAG);
}

extern int fsck_chk_orphan_node(struct f2fs_sb_info *);
@@ -181,9 +180,10 @@ extern int fsck_chk_didnode_blk(struct f2fs_sb_info *, struct f2fs_inode *,
enum FILE_TYPE, struct f2fs_node *, u32 *,
struct f2fs_compr_blk_cnt *, struct child_info *);
extern int fsck_chk_data_blk(struct f2fs_sb_info *, int,
- u32, struct child_info *, int, enum FILE_TYPE, u32, u16, u8, int);
+ u32, struct child_info *, int, enum FILE_TYPE, u32, u16, u8,
+ int, struct f2fs_node *);
extern int fsck_chk_dentry_blk(struct f2fs_sb_info *, int,
- u32, struct child_info *, int, int);
+ u32, struct child_info *, int, int, struct f2fs_node *);
int fsck_chk_inline_dentries(struct f2fs_sb_info *, struct f2fs_node *,
struct child_info *);
void fsck_chk_checkpoint(struct f2fs_sb_info *sbi);
@@ -209,7 +209,9 @@ extern void rewrite_sit_area_bitmap(struct f2fs_sb_info *);
extern void build_nat_area_bitmap(struct f2fs_sb_info *);
extern void build_sit_area_bitmap(struct f2fs_sb_info *);
extern int f2fs_set_main_bitmap(struct f2fs_sb_info *, u32, int);
+extern int f2fs_clear_main_bitmap(struct f2fs_sb_info *, u32);
extern int f2fs_set_sit_bitmap(struct f2fs_sb_info *, u32);
+extern int f2fs_clear_sit_bitmap(struct f2fs_sb_info *, u32);
extern void fsck_init(struct f2fs_sb_info *);
extern int fsck_verify(struct f2fs_sb_info *);
extern void fsck_free(struct f2fs_sb_info *);
@@ -225,13 +227,18 @@ extern void update_curseg_info(struct f2fs_sb_info *, int);
extern void zero_journal_entries(struct f2fs_sb_info *);
extern void flush_sit_entries(struct f2fs_sb_info *);
extern void move_curseg_info(struct f2fs_sb_info *, u64, int);
+extern void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left,
+ int i);
extern void write_curseg_info(struct f2fs_sb_info *);
+extern void save_curseg_warm_node_info(struct f2fs_sb_info *);
+extern void restore_curseg_warm_node_info(struct f2fs_sb_info *);
extern int find_next_free_block(struct f2fs_sb_info *, u64 *, int, int, bool);
extern void duplicate_checkpoint(struct f2fs_sb_info *);
extern void write_checkpoint(struct f2fs_sb_info *);
extern void write_checkpoints(struct f2fs_sb_info *);
extern void update_superblock(struct f2fs_super_block *, int);
-extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t);
+extern void update_data_blkaddr(struct f2fs_sb_info *, nid_t, u16, block_t,
+ struct f2fs_node *);
extern void update_nat_blkaddr(struct f2fs_sb_info *, nid_t, nid_t, block_t);

extern void print_raw_sb_info(struct f2fs_super_block *);
@@ -294,6 +301,8 @@ void set_data_blkaddr(struct dnode_of_data *);
block_t new_node_block(struct f2fs_sb_info *,
struct dnode_of_data *, unsigned int);
int f2fs_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype);
+int update_block(struct f2fs_sb_info *sbi, void *buf, u32 *blkaddr,
+ struct f2fs_node *node_blk);

/* segment.c */
struct quota_file;
@@ -321,7 +330,7 @@ int inode_set_selinux(struct f2fs_sb_info *, u32, const char *);
int f2fs_find_path(struct f2fs_sb_info *, char *, nid_t *);
nid_t f2fs_lookup(struct f2fs_sb_info *, struct f2fs_node *, u8 *, int);
int f2fs_add_link(struct f2fs_sb_info *, struct f2fs_node *,
- const unsigned char *, int, nid_t, int, block_t, int);
+ const unsigned char *, int, nid_t, int, block_t *, int);
struct hardlink_cache_entry *f2fs_search_hardlink(struct f2fs_sb_info *sbi,
struct dentry *de);

@@ -332,6 +341,14 @@ void write_all_xattrs(struct f2fs_sb_info *sbi,

/* dir.c */
int convert_inline_dentry(struct f2fs_sb_info *sbi, struct f2fs_node *node,
- block_t p_blkaddr);
+ block_t *p_blkaddr);
+
+/* node.c */
+int update_inode(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
+ u32 *blkaddr);
+
+/* mount.c */
+int flush_nat_journal_entries(struct f2fs_sb_info *sbi);
+int flush_sit_journal_entries(struct f2fs_sb_info *sbi);

#endif /* _FSCK_H_ */
diff --git a/fsck/main.c b/fsck/main.c
index 6d48d40..1affa72 100644
--- a/fsck/main.c
+++ b/fsck/main.c
@@ -834,6 +834,9 @@ static int do_fsck(struct f2fs_sb_info *sbi)

print_cp_state(flag);

+ if (c.roll_forward && c.zoned_model == F2FS_ZONED_HM)
+ save_curseg_warm_node_info(sbi);
+
fsck_chk_and_fix_write_pointers(sbi);

fsck_chk_curseg_info(sbi);
diff --git a/fsck/mount.c b/fsck/mount.c
index 72516f4..1e9762e 100644
--- a/fsck/mount.c
+++ b/fsck/mount.c
@@ -1986,7 +1986,7 @@ void reset_curseg(struct f2fs_sb_info *sbi, int type)
if (IS_NODESEG(type))
SET_SUM_TYPE(curseg->sum_blk, SUM_TYPE_NODE);
se = get_seg_entry(sbi, curseg->segno);
- se->type = type;
+ se->type = se->orig_type = type;
se->dirty = 1;
}

@@ -2327,7 +2327,6 @@ unsigned char get_seg_type(struct f2fs_sb_info *sbi, struct seg_entry *se)
struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *sbi,
unsigned int segno, int *ret_type)
{
- struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
struct f2fs_summary_block *sum_blk;
struct curseg_info *curseg;
int type, ret;
@@ -2337,8 +2336,8 @@ struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *sbi,

ssa_blk = GET_SUM_BLKADDR(sbi, segno);
for (type = 0; type < NR_CURSEG_NODE_TYPE; type++) {
- if (segno == get_cp(cur_node_segno[type])) {
- curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type);
+ curseg = CURSEG_I(sbi, CURSEG_HOT_NODE + type);
+ if (segno == curseg->segno) {
if (!IS_SUM_NODE_SEG(curseg->sum_blk)) {
ASSERT_MSG("segno [0x%x] indicates a data "
"segment, but should be node",
@@ -2352,8 +2351,8 @@ struct f2fs_summary_block *get_sum_block(struct f2fs_sb_info *sbi,
}

for (type = 0; type < NR_CURSEG_DATA_TYPE; type++) {
- if (segno == get_cp(cur_data_segno[type])) {
- curseg = CURSEG_I(sbi, type);
+ curseg = CURSEG_I(sbi, type);
+ if (segno == curseg->segno) {
if (IS_SUM_NODE_SEG(curseg->sum_blk)) {
ASSERT_MSG("segno [0x%x] indicates a node "
"segment, but should be data",
@@ -2425,21 +2424,24 @@ static void get_nat_entry(struct f2fs_sb_info *sbi, nid_t nid,
}

void update_data_blkaddr(struct f2fs_sb_info *sbi, nid_t nid,
- u16 ofs_in_node, block_t newaddr)
+ u16 ofs_in_node, block_t newaddr, struct f2fs_node *node_blk)
{
- struct f2fs_node *node_blk = NULL;
struct node_info ni;
block_t oldaddr, startaddr, endaddr;
+ bool node_blk_alloced = false;
int ret;

- node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1);
- ASSERT(node_blk);
+ if (node_blk == NULL) {
+ node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1);
+ ASSERT(node_blk);

- get_node_info(sbi, nid, &ni);
+ get_node_info(sbi, nid, &ni);

- /* read node_block */
- ret = dev_read_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ /* read node_block */
+ ret = dev_read_block(node_blk, ni.blk_addr);
+ ASSERT(ret >= 0);
+ node_blk_alloced = true;
+ }

/* check its block address */
if (IS_INODE(node_blk)) {
@@ -2447,33 +2449,46 @@ void update_data_blkaddr(struct f2fs_sb_info *sbi, nid_t nid,

oldaddr = le32_to_cpu(node_blk->i.i_addr[ofs + ofs_in_node]);
node_blk->i.i_addr[ofs + ofs_in_node] = cpu_to_le32(newaddr);
- ret = write_inode(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
+ if (node_blk_alloced) {
+ ret = update_inode(sbi, node_blk, &ni.blk_addr);
+ ASSERT(ret >= 0);
+ }
} else {
oldaddr = le32_to_cpu(node_blk->dn.addr[ofs_in_node]);
node_blk->dn.addr[ofs_in_node] = cpu_to_le32(newaddr);
- ret = dev_write_block(node_blk, ni.blk_addr);
- ASSERT(ret >= 0);
- }
+ if (node_blk_alloced) {
+ ret = update_block(sbi, node_blk, &ni.blk_addr, NULL);
+ ASSERT(ret >= 0);
+ }

- /* check extent cache entry */
- if (!IS_INODE(node_blk)) {
- get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino), &ni);
+ /* change node_blk with inode to update extent cache entry */
+ get_node_info(sbi, le32_to_cpu(F2FS_NODE_FOOTER(node_blk)->ino),
+ &ni);

/* read inode block */
+ if (!node_blk_alloced) {
+ node_blk = (struct f2fs_node *)calloc(F2FS_BLKSIZE, 1);
+ ASSERT(node_blk);
+
+ node_blk_alloced = true;
+ }
ret = dev_read_block(node_blk, ni.blk_addr);
ASSERT(ret >= 0);
}

+ /* check extent cache entry */
startaddr = le32_to_cpu(node_blk->i.i_ext.blk_addr);
endaddr = startaddr + le32_to_cpu(node_blk->i.i_ext.len);
if (oldaddr >= startaddr && oldaddr < endaddr) {
node_blk->i.i_ext.len = 0;

/* update inode block */
- ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
+ if (node_blk_alloced)
+ ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0);
}
- free(node_blk);
+
+ if (node_blk_alloced)
+ free(node_blk);
}

void update_nat_blkaddr(struct f2fs_sb_info *sbi, nid_t ino,
@@ -2744,7 +2759,7 @@ void rewrite_sit_area_bitmap(struct f2fs_sb_info *sbi)
free(sit_blk);
}

-static int flush_sit_journal_entries(struct f2fs_sb_info *sbi)
+int flush_sit_journal_entries(struct f2fs_sb_info *sbi)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_COLD_DATA);
struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk);
@@ -2778,7 +2793,7 @@ static int flush_sit_journal_entries(struct f2fs_sb_info *sbi)
return i;
}

-static int flush_nat_journal_entries(struct f2fs_sb_info *sbi)
+int flush_nat_journal_entries(struct f2fs_sb_info *sbi)
{
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_HOT_DATA);
struct f2fs_journal *journal = F2FS_SUMMARY_BLOCK_JOURNAL(curseg->sum_blk);
@@ -2893,7 +2908,8 @@ void set_section_type(struct f2fs_sb_info *sbi, unsigned int segno, int type)
for (i = 0; i < sbi->segs_per_sec; i++) {
struct seg_entry *se = get_seg_entry(sbi, segno + i);

- se->type = type;
+ se->type = se->orig_type = type;
+ se->dirty = 1;
}
}

@@ -2943,6 +2959,17 @@ static bool write_pointer_at_zone_start(struct f2fs_sb_info *UNUSED(sbi),

#endif

+static void zero_journal_entries_with_type(struct f2fs_sb_info *sbi, int type)
+{
+ struct f2fs_journal *journal =
+ F2FS_SUMMARY_BLOCK_JOURNAL(CURSEG_I(sbi, type)->sum_blk);
+
+ if (type == CURSEG_HOT_DATA)
+ journal->n_nats = 0;
+ else if (type == CURSEG_COLD_DATA)
+ journal->n_sits = 0;
+}
+
int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left,
int want_type, bool new_sec)
{
@@ -2954,6 +2981,49 @@ int find_next_free_block(struct f2fs_sb_info *sbi, u64 *to, int left,
u64 end_blkaddr = (get_sb(segment_count_main) <<
get_sb(log_blocks_per_seg)) + get_sb(main_blkaddr);

+ if (c.zoned_model == F2FS_ZONED_HM && !new_sec) {
+ struct curseg_info *curseg = CURSEG_I(sbi, want_type);
+ unsigned int segs_per_zone = sbi->segs_per_sec * sbi->secs_per_zone;
+ char buf[F2FS_BLKSIZE];
+ u64 ssa_blk;
+ int ret;
+
+ *to = NEXT_FREE_BLKADDR(sbi, curseg);
+ curseg->next_blkoff++;
+
+ if (curseg->next_blkoff == sbi->blocks_per_seg) {
+ segno = curseg->segno + 1;
+ if (!(segno % segs_per_zone)) {
+ u64 new_blkaddr = SM_I(sbi)->main_blkaddr;
+
+ ret = find_next_free_block(sbi, &new_blkaddr, 0,
+ want_type, true);
+ if (ret)
+ return ret;
+ segno = GET_SEGNO(sbi, new_blkaddr);
+ }
+
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_write_block(curseg->sum_blk, ssa_blk);
+ ASSERT(ret >= 0);
+
+ curseg->segno = segno;
+ curseg->next_blkoff = 0;
+ curseg->alloc_type = LFS;
+
+ ssa_blk = GET_SUM_BLKADDR(sbi, curseg->segno);
+ ret = dev_read_block(&buf, ssa_blk);
+ ASSERT(ret >= 0);
+
+ memcpy(curseg->sum_blk, &buf, SUM_ENTRIES_SIZE);
+
+ reset_curseg(sbi, want_type);
+ zero_journal_entries_with_type(sbi, want_type);
+ }
+
+ return 0;
+ }
+
if (*to > 0)
*to -= left;
if (SM_I(sbi)->free_segments <= SM_I(sbi)->reserved_segments + 1)
@@ -3013,7 +3083,7 @@ next_segment:
return -1;
}

-static void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left,
+void move_one_curseg_info(struct f2fs_sb_info *sbi, u64 from, int left,
int i)
{
struct f2fs_super_block *sb = F2FS_RAW_SUPER(sbi);
@@ -3061,6 +3131,8 @@ bypass_ssa:

/* update se->types */
reset_curseg(sbi, i);
+ if (c.zoned_model == F2FS_ZONED_HM)
+ zero_journal_entries_with_type(sbi, i);

FIX_MSG("Move curseg[%d] %x -> %x after %"PRIx64"\n",
i, old_segno, curseg->segno, from);
@@ -3111,6 +3183,26 @@ void write_curseg_info(struct f2fs_sb_info *sbi)
}
}

+void save_curseg_warm_node_info(struct f2fs_sb_info *sbi)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+ struct curseg_info *saved_curseg = &SM_I(sbi)->saved_curseg_warm_node;
+
+ saved_curseg->alloc_type = curseg->alloc_type;
+ saved_curseg->segno = curseg->segno;
+ saved_curseg->next_blkoff = curseg->next_blkoff;
+}
+
+void restore_curseg_warm_node_info(struct f2fs_sb_info *sbi)
+{
+ struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
+ struct curseg_info *saved_curseg = &SM_I(sbi)->saved_curseg_warm_node;
+
+ curseg->alloc_type = saved_curseg->alloc_type;
+ curseg->segno = saved_curseg->segno;
+ curseg->next_blkoff = saved_curseg->next_blkoff;
+}
+
int lookup_nat_in_journal(struct f2fs_sb_info *sbi, u32 nid,
struct f2fs_nat_entry *raw_nat)
{
@@ -3280,6 +3372,9 @@ void write_checkpoint(struct f2fs_sb_info *sbi)
struct curseg_info *curseg = CURSEG_I(sbi, i);
u64 ssa_blk;

+ if (!(flags & CP_UMOUNT_FLAG) && IS_NODESEG(i))
+ continue;
+
ret = dev_write_block(curseg->sum_blk, cp_blk_no++);
ASSERT(ret >= 0);

diff --git a/fsck/node.c b/fsck/node.c
index d53756d..7f062f0 100644
--- a/fsck/node.c
+++ b/fsck/node.c
@@ -69,6 +69,8 @@ int f2fs_rebuild_qf_inode(struct f2fs_sb_info *sbi, int qtype)
F2FS_NODE_FOOTER(raw_node)->cp_ver = cpu_to_le64(cp_ver);

get_node_info(sbi, ino, &ni);
+ if (ni.ino != ino)
+ ni.version = 0;
set_summary(&sum, ino, 0, ni.version);
ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE, 1);
if (ret) {
@@ -255,6 +257,7 @@ int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
block_t nblk[4];
struct node_info ni;
int level, i;
+ bool parent_alloced = false;
int ret;

level = get_node_path(dn->inode_blk, index, offset, noffset);
@@ -274,6 +277,14 @@ int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
f2fs_alloc_nid(sbi, &nids[i]);

dn->nid = nids[i];
+ set_nid(parent, offset[i - 1], nids[i], i == 1);
+
+ /* Parent node has changed */
+ if (!parent_alloced)
+ ret = update_block(sbi, parent, &nblk[i - 1], NULL);
+ else
+ ret = dev_write_block(parent, nblk[i - 1]);
+ ASSERT(ret >= 0);

/* Function new_node_blk get a new f2fs_node blk and update*/
/* We should make sure that dn->node_blk == NULL*/
@@ -284,7 +295,9 @@ int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
return -EINVAL;
}

- set_nid(parent, offset[i - 1], nids[i], i == 1);
+ parent_alloced = true;
+ if (i == level)
+ dn->alloced = 1;
} else {
/* If Sparse file no read API, */
struct node_info ni;
@@ -299,11 +312,6 @@ int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
nblk[i] = ni.blk_addr;
}

- if (mode == ALLOC_NODE){
- /* Parent node may have changed */
- ret = dev_write_block(parent, nblk[i - 1]);
- ASSERT(ret >= 0);
- }
if (i != 1)
free(parent);

@@ -319,3 +327,13 @@ int get_dnode_of_data(struct f2fs_sb_info *sbi, struct dnode_of_data *dn,
dn->node_blkaddr = nblk[level];
return 0;
}
+
+int update_inode(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
+ u32 *blkaddr)
+{
+ if (c.feature & cpu_to_le32(F2FS_FEATURE_INODE_CHKSUM))
+ inode->i.i_inode_checksum =
+ cpu_to_le32(f2fs_inode_chksum(inode));
+ return update_block(sbi, inode, blkaddr, NULL);
+}
+
diff --git a/fsck/node.h b/fsck/node.h
index ac0e7b3..19f1e57 100644
--- a/fsck/node.h
+++ b/fsck/node.h
@@ -99,6 +99,7 @@ static inline void set_new_dnode(struct dnode_of_data *dn,
dn->nid = nid;
dn->idirty = 0;
dn->ndirty = 0;
+ dn->alloced = 0;
}

static inline void inc_inode_blocks(struct dnode_of_data *dn)
diff --git a/fsck/resize.c b/fsck/resize.c
index a3424b4..049ddd3 100644
--- a/fsck/resize.c
+++ b/fsck/resize.c
@@ -196,7 +196,7 @@ static void migrate_main(struct f2fs_sb_info *sbi, unsigned int offset)

if (IS_DATASEG(se->type))
update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
- le16_to_cpu(sum.ofs_in_node), to);
+ le16_to_cpu(sum.ofs_in_node), to, NULL);
else
update_nat_blkaddr(sbi, 0,
le32_to_cpu(sum.nid), to);
diff --git a/fsck/segment.c b/fsck/segment.c
index 934004e..9bea105 100644
--- a/fsck/segment.c
+++ b/fsck/segment.c
@@ -267,6 +267,7 @@ static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
struct node_info ni;
struct f2fs_node *inode;
char *blk_buffer;
+ void *wbuf;
u64 off_in_blk;
u64 len_in_blk;
u64 written_count;
@@ -274,7 +275,8 @@ static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
block_t blkaddr;
void* index_node = NULL;
int idirty = 0;
- int err;
+ int err, ret;
+ bool datablk_alloced = false;
bool has_data = (addr_type == WR_NORMAL
|| addr_type == WR_COMPRESS_DATA);

@@ -323,13 +325,18 @@ static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
dn.data_blkaddr = addr_type;
set_data_blkaddr(&dn);
idirty |= dn.idirty;
- if (dn.ndirty)
- ASSERT(dev_write_block(dn.node_blk,
- dn.node_blkaddr) >= 0);
+ if (dn.ndirty) {
+ ret = dn.alloced ? dev_write_block(dn.node_blk,
+ dn.node_blkaddr) :
+ update_block(sbi, dn.node_blk,
+ &dn.node_blkaddr, NULL);
+ ASSERT(ret >= 0);
+ }
written_count = 0;
break;
}

+ datablk_alloced = false;
blkaddr = datablock_addr(dn.node_blk, dn.ofs_in_node);
if (blkaddr == NULL_ADDR || blkaddr == NEW_ADDR) {
err = new_data_block(sbi, blk_buffer,
@@ -338,6 +345,7 @@ static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
break;
blkaddr = dn.data_blkaddr;
idirty |= dn.idirty;
+ datablk_alloced = true;
}

off_in_blk = offset % F2FS_BLKSIZE;
@@ -349,29 +357,50 @@ static u64 f2fs_write_ex(struct f2fs_sb_info *sbi, nid_t ino, u8 *buffer,
if (len_in_blk < F2FS_BLKSIZE) {
ASSERT(dev_read_block(blk_buffer, blkaddr) >= 0);
memcpy(blk_buffer + off_in_blk, buffer, len_in_blk);
- ASSERT(dev_write_block(blk_buffer, blkaddr) >= 0);
+ wbuf = blk_buffer;
} else {
/* Direct write */
- ASSERT(dev_write_block(buffer, blkaddr) >= 0);
+ wbuf = buffer;
}

+ if (c.zoned_model == F2FS_ZONED_HM) {
+ if (datablk_alloced) {
+ ret = dev_write_block(wbuf, blkaddr);
+ } else {
+ ret = update_block(sbi, wbuf, &blkaddr,
+ dn.node_blk);
+ if (dn.inode_blk == dn.node_blk)
+ idirty = 1;
+ else
+ dn.ndirty = 1;
+ }
+ } else {
+ ret = dev_write_block(wbuf, blkaddr);
+ }
+ ASSERT(ret >= 0);
+
offset += len_in_blk;
count -= len_in_blk;
buffer += len_in_blk;
written_count += len_in_blk;

dn.ofs_in_node++;
- if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty))
- ASSERT(dev_write_block(dn.node_blk, dn.node_blkaddr)
- >= 0);
+ if ((--remained_blkentries == 0 || count == 0) && (dn.ndirty)) {
+ ret = dn.alloced ?
+ dev_write_block(dn.node_blk, dn.node_blkaddr) :
+ update_block(sbi, dn.node_blk, &dn.node_blkaddr, NULL);
+ ASSERT(ret >= 0);
+ }
}
+
if (addr_type == WR_NORMAL && offset > le64_to_cpu(inode->i.i_size)) {
inode->i.i_size = cpu_to_le64(offset);
idirty = 1;
}
if (idirty) {
+ get_node_info(sbi, ino, &ni);
ASSERT(inode == dn.inode_blk);
- ASSERT(write_inode(inode, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0);
}

free(index_node);
@@ -416,7 +445,7 @@ void f2fs_filesize_update(struct f2fs_sb_info *sbi, nid_t ino, u64 filesize)

inode->i.i_size = cpu_to_le64(filesize);

- ASSERT(write_inode(inode, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0);
free(inode);
}

@@ -560,7 +589,7 @@ exit:
copy_extent_info(&largest_ext, &cur_ext);
if (largest_ext.len > 0) {
update_extent_info(inode, &largest_ext);
- ASSERT(write_inode(inode, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0);
}

if (index_node)
@@ -620,7 +649,7 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
ASSERT((unsigned long)n == de->size);
memcpy(inline_data_addr(node_blk), buffer, de->size);
node_blk->i.i_size = cpu_to_le64(de->size);
- ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0);
free(node_blk);
#ifdef WITH_SLOAD
} else if (c.func == SLOAD && c.compress.enabled &&
@@ -642,7 +671,7 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
node_blk->i.i_flags = cpu_to_le32(F2FS_COMPR_FL);
if (c.compress.readonly)
node_blk->i.i_inline |= F2FS_COMPRESS_RELEASED;
- ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0);

while (!eof && (n = bulkread(fd, rbuf, c.compress.cc.rlen,
&eof)) > 0) {
@@ -690,7 +719,7 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
node_blk->i.i_compr_blocks = cpu_to_le64(cblocks);
node_blk->i.i_blocks += cpu_to_le64(cblocks);
}
- ASSERT(write_inode(node_blk, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, node_blk, &ni.blk_addr) >= 0);
free(node_blk);

if (!c.compress.readonly) {
@@ -725,3 +754,64 @@ int f2fs_build_file(struct f2fs_sb_info *sbi, struct dentry *de)
de->uid, de->gid, de->capabilities, de->size, de->pino);
return 0;
}
+
+int update_block(struct f2fs_sb_info *sbi, void *buf, u32 *blkaddr,
+ struct f2fs_node *node_blk)
+{
+ struct seg_entry *se;
+ struct f2fs_summary sum;
+ u64 new_blkaddr, old_blkaddr = *blkaddr, offset;
+ int ret, type;
+
+ if (c.zoned_model != F2FS_ZONED_HM)
+ return dev_write_block(buf, old_blkaddr);
+
+ /* update sit bitmap & valid_blocks && se->type for old block*/
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, old_blkaddr));
+ offset = OFFSET_IN_SEG(sbi, old_blkaddr);
+ type = se->type;
+ se->valid_blocks--;
+ f2fs_clear_bit(offset, (char *)se->cur_valid_map);
+ if (need_fsync_data_record(sbi))
+ f2fs_clear_bit(offset, (char *)se->ckpt_valid_map);
+ se->dirty = 1;
+ f2fs_clear_main_bitmap(sbi, old_blkaddr);
+ f2fs_clear_sit_bitmap(sbi, old_blkaddr);
+
+ new_blkaddr = SM_I(sbi)->main_blkaddr;
+ if (find_next_free_block(sbi, &new_blkaddr, 0, type, false)) {
+ ERR_MSG("Can't find free block for the update");
+ ASSERT(0);
+ }
+
+ ret = dev_write_block(buf, new_blkaddr);
+ ASSERT(ret >= 0);
+
+ *blkaddr = new_blkaddr;
+
+ /* update sit bitmap & valid_blocks && se->type for new block */
+ se = get_seg_entry(sbi, GET_SEGNO(sbi, new_blkaddr));
+ offset = OFFSET_IN_SEG(sbi, new_blkaddr);
+ se->type = se->orig_type = type;
+ se->valid_blocks++;
+ f2fs_set_bit(offset, (char *)se->cur_valid_map);
+ if (need_fsync_data_record(sbi))
+ f2fs_set_bit(offset, (char *)se->ckpt_valid_map);
+ se->dirty = 1;
+ f2fs_set_main_bitmap(sbi, new_blkaddr, type);
+ f2fs_set_sit_bitmap(sbi, new_blkaddr);
+
+ /* update SSA */
+ get_sum_entry(sbi, old_blkaddr, &sum);
+ update_sum_entry(sbi, new_blkaddr, &sum);
+
+ if (IS_DATASEG(type)) {
+ update_data_blkaddr(sbi, le32_to_cpu(sum.nid),
+ le16_to_cpu(sum.ofs_in_node), new_blkaddr, node_blk);
+ } else
+ update_nat_blkaddr(sbi, 0, le32_to_cpu(sum.nid), new_blkaddr);
+
+ DBG(1, "Update %s block %"PRIx64" -> %"PRIx64"\n",
+ IS_DATASEG(type) ? "data" : "node", old_blkaddr, new_blkaddr);
+ return ret;
+}
diff --git a/fsck/xattr.c b/fsck/xattr.c
index 3163639..241e339 100644
--- a/fsck/xattr.c
+++ b/fsck/xattr.c
@@ -94,6 +94,7 @@ void write_all_xattrs(struct f2fs_sb_info *sbi,
nid_t xnid = le32_to_cpu(inode->i.i_xattr_nid);
u64 inline_size = inline_xattr_size(&inode->i);
int ret;
+ bool xattrblk_alloced = false;

memcpy(inline_xattr_addr(&inode->i), txattr_addr, inline_size);

@@ -109,6 +110,7 @@ void write_all_xattrs(struct f2fs_sb_info *sbi,
ASSERT(dn.node_blk);
xattr_node = dn.node_blk;
inode->i.i_xattr_nid = cpu_to_le32(new_nid);
+ xattrblk_alloced = true;
} else {
set_new_dnode(&dn, inode, NULL, xnid);
get_node_info(sbi, xnid, &ni);
@@ -125,7 +127,8 @@ void write_all_xattrs(struct f2fs_sb_info *sbi,
memcpy(xattr_addr, txattr_addr + inline_size,
F2FS_BLKSIZE - sizeof(struct node_footer));

- ret = dev_write_block(xattr_node, blkaddr);
+ ret = xattrblk_alloced ? dev_write_block(xattr_node, blkaddr) :
+ update_block(sbi, xattr_node, &blkaddr, NULL);

free_xattr_node:
free(xattr_node);
@@ -250,7 +253,7 @@ int f2fs_setxattr(struct f2fs_sb_info *sbi, nid_t ino, int index, const char *na
write_all_xattrs(sbi, inode, new_hsize, base_addr);

/* inode need update */
- ASSERT(write_inode(inode, ni.blk_addr) >= 0);
+ ASSERT(update_inode(sbi, inode, &ni.blk_addr) >= 0);
exit:
free(inode);
free(base_addr);
diff --git a/lib/libf2fs.c b/lib/libf2fs.c
index 995e42d..624cf57 100644
--- a/lib/libf2fs.c
+++ b/lib/libf2fs.c
@@ -919,6 +919,7 @@ int get_device_info(int i)
unsigned char model_inq[6] = {MODELINQUIRY};
#endif
struct device_info *dev = c.devices + i;
+ int flags = O_RDWR;

if (c.sparse_mode) {
fd = open(dev->path, O_RDWR | O_CREAT | O_BINARY, 0644);
@@ -934,20 +935,33 @@ int get_device_info(int i)
stat_buf = malloc(sizeof(struct stat));
ASSERT(stat_buf);

- if (!c.sparse_mode) {
- if (stat(dev->path, stat_buf) < 0 ) {
- MSG(0, "\tError: Failed to get the device stat!\n");
+ if (stat(dev->path, stat_buf) < 0) {
+ MSG(0, "\tError: Failed to get the device stat!\n");
+ free(stat_buf);
+ return -1;
+ }
+
+#ifdef __linux__
+ if (S_ISBLK(stat_buf->st_mode)) {
+ if (f2fs_get_zoned_model(i) < 0) {
free(stat_buf);
return -1;
}
+ }
+#endif
+
+ if (!c.sparse_mode) {
+ if (dev->zoned_model == F2FS_ZONED_HM && c.func == FSCK)
+ flags |= O_DSYNC;

if (S_ISBLK(stat_buf->st_mode) &&
!c.force && c.func != DUMP && !c.dry_run) {
- fd = open(dev->path, O_RDWR | O_EXCL);
+ flags |= O_EXCL;
+ fd = open(dev->path, flags);
if (fd < 0)
fd = open_check_fs(dev->path, O_EXCL);
} else {
- fd = open(dev->path, O_RDWR);
+ fd = open(dev->path, flags);
if (fd < 0)
fd = open_check_fs(dev->path, 0);
}
@@ -1047,13 +1061,6 @@ int get_device_info(int i)
}

#ifdef __linux__
- if (S_ISBLK(stat_buf->st_mode)) {
- if (f2fs_get_zoned_model(i) < 0) {
- free(stat_buf);
- return -1;
- }
- }
-
if (dev->zoned_model != F2FS_ZONED_NONE) {

/* Get the number of blocks per zones */
@@ -1104,6 +1111,7 @@ int get_device_info(int i)
}
}
#endif
+
/* adjust wanted_total_sectors */
if (c.wanted_total_sectors != -1) {
MSG(0, "Info: wanted sectors = %"PRIu64" (in %"PRIu64" bytes)\n",
--
2.43.0.rc2.451.g8631bc7472-goog