f2fs-tools: fix to check total valid block count before block allocation
authorChao Yu <yuchao0@huawei.com>
Mon, 15 Apr 2019 09:14:38 +0000 (17:14 +0800)
committerJaegeuk Kim <jaegeuk@kernel.org>
Tue, 20 Aug 2019 18:23:51 +0000 (11:23 -0700)
Now, kernel can catch incorrect total valid block count which is exceed
max user block count of image.

Then, generic/051,476 of fstest reports below message:

Apr 15 11:08:03 szvp000201624 kernel: [ 2533.515813] F2FS-fs (zram1): Wrong valid_user_blocks: 469505, user_block_count: 469504
Apr 15 11:08:03 szvp000201624 kernel: [ 2533.519166] F2FS-fs (zram1): Failed to get valid F2FS checkpoint

The reason is that when fsck repairs corrupted quota sysfile, it didn't
check max user block count when allocating new block for quota sysfile,
so ckpt.valid_block_count can exceed max user block count, result in
mount failure later.

Adding upper boundary check of block count in reserve_new_block() to
fix this issue.

Signed-off-by: Chao Yu <yuchao0@huawei.com>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
fsck/dir.c
fsck/fsck.h
fsck/node.c
fsck/segment.c

index d20c18c..592d9db 100644 (file)
@@ -360,7 +360,8 @@ static void make_empty_dir(struct f2fs_sb_info *sbi, struct f2fs_node *inode)
        test_and_set_bit_le(1, dent_blk->dentry_bitmap);
 
        set_summary(&sum, ino, 0, ni.version);
-       reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_DATA);
+       ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_DATA);
+       ASSERT(!ret);
 
        ret = dev_write_block(dent_blk, blkaddr);
        ASSERT(ret >= 0);
@@ -395,7 +396,8 @@ static void page_symlink(struct f2fs_sb_info *sbi, struct f2fs_node *inode,
        memcpy(data_blk, symname, symlen);
 
        set_summary(&sum, ino, 0, ni.version);
-       reserve_new_block(sbi, &blkaddr, &sum, CURSEG_WARM_DATA);
+       ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_WARM_DATA);
+       ASSERT(!ret);
 
        ret = dev_write_block(data_blk, blkaddr);
        ASSERT(ret >= 0);
@@ -630,7 +632,8 @@ int f2fs_create(struct f2fs_sb_info *sbi, struct dentry *de)
 
        /* write child */
        set_summary(&sum, de->ino, 0, ni.version);
-       reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE);
+       ret = reserve_new_block(sbi, &blkaddr, &sum, CURSEG_HOT_NODE);
+       ASSERT(!ret);
 
        /* update nat info */
        update_nat_blkaddr(sbi, de->ino, de->ino, blkaddr);
index f00036e..d38e8de 100644 (file)
@@ -238,7 +238,7 @@ int f2fs_resize(struct f2fs_sb_info *);
 int f2fs_sload(struct f2fs_sb_info *);
 
 /* segment.c */
-void reserve_new_block(struct f2fs_sb_info *, block_t *,
+int reserve_new_block(struct f2fs_sb_info *, block_t *,
                                        struct f2fs_summary *, int);
 int new_data_block(struct f2fs_sb_info *, void *,
                                        struct dnode_of_data *, int);
index 18dd186..882f355 100644 (file)
@@ -65,6 +65,7 @@ block_t new_node_block(struct f2fs_sb_info *sbi,
        struct node_info ni;
        block_t blkaddr = NULL_ADDR;
        int type;
+       int ret;
 
        f2fs_inode = dn->inode_blk;
 
@@ -86,7 +87,11 @@ block_t new_node_block(struct f2fs_sb_info *sbi,
 
        get_node_info(sbi, dn->nid, &ni);
        set_summary(&sum, dn->nid, 0, ni.version);
-       reserve_new_block(sbi, &blkaddr, &sum, type);
+       ret = reserve_new_block(sbi, &blkaddr, &sum, type);
+       if (ret) {
+               free(node_blk);
+               return 0;
+       }
 
        /* update nat info */
        update_nat_blkaddr(sbi, le32_to_cpu(f2fs_inode->footer.ino),
index 98c836e..f26e623 100644 (file)
@@ -24,7 +24,7 @@ static void write_inode(u64 blkaddr, struct f2fs_node *inode)
        ASSERT(dev_write_block(inode, blkaddr) >= 0);
 }
 
-void reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
+int reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
                        struct f2fs_summary *sum, int type)
 {
        struct f2fs_fsck *fsck = F2FS_FSCK(sbi);
@@ -32,10 +32,25 @@ void reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
        u64 blkaddr, offset;
        u64 old_blkaddr = *to;
 
+       if (old_blkaddr == NULL_ADDR) {
+               if (c.func == FSCK) {
+                       if (fsck->chk.valid_blk_cnt >= sbi->user_block_count) {
+                               ERR_MSG("Not enough space");
+                               return -ENOSPC;
+                       }
+               } else {
+                       if (sbi->total_valid_block_count >=
+                                               sbi->user_block_count) {
+                               ERR_MSG("Not enough space");
+                               return -ENOSPC;
+                       }
+               }
+       }
+
        blkaddr = SM_I(sbi)->main_blkaddr;
 
        if (find_next_free_block(sbi, &blkaddr, 0, type)) {
-               ERR_MSG("Not enough space to allocate blocks");
+               ERR_MSG("Can't find free block");
                ASSERT(0);
        }
 
@@ -59,6 +74,8 @@ void reserve_new_block(struct f2fs_sb_info *sbi, block_t *to,
        /* read/write SSA */
        *to = (block_t)blkaddr;
        update_sum_entry(sbi, *to, sum);
+
+       return 0;
 }
 
 int new_data_block(struct f2fs_sb_info *sbi, void *block,
@@ -68,6 +85,7 @@ int new_data_block(struct f2fs_sb_info *sbi, void *block,
        struct node_info ni;
        unsigned int blkaddr = datablock_addr(dn->node_blk, dn->ofs_in_node);
        struct f2fs_checkpoint *cp = F2FS_CKPT(sbi);
+       int ret;
 
        if (!is_set_ckpt_flags(cp, CP_UMOUNT_FLAG)) {
                c.alloc_failed = 1;
@@ -79,7 +97,11 @@ int new_data_block(struct f2fs_sb_info *sbi, void *block,
 
        get_node_info(sbi, dn->nid, &ni);
        set_summary(&sum, dn->nid, dn->ofs_in_node, ni.version);
-       reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
+       ret = reserve_new_block(sbi, &dn->data_blkaddr, &sum, type);
+       if (ret) {
+               c.alloc_failed = 1;
+               return ret;
+       }
 
        if (blkaddr == NULL_ADDR)
                inc_inode_blocks(dn);