btrfs-progs: fsck: fix a infinite loop on discount file extent repair
authorQu Wenruo <quwenruo@cn.fujitsu.com>
Wed, 5 Aug 2015 08:03:13 +0000 (16:03 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 31 Aug 2015 17:25:12 +0000 (19:25 +0200)
For a special case, discount file extent repair function will cause
infinite loop.

The case is, if the file loses all its extents, we won't have a hole
to fill, causing repair function doing nothing. Since the
I_ERR_DISCOUNT doesn't disappear, fsck will do an infinite loop.

For such case, just puch hole to fill the whole range to fix it.

Reported-by: Robert Munteanu <robert.munteanu@gmail.com>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index 31ed58945c7e23ab5c0dcbdff3120a06c0a88b41..4fa8709b4e8ddb9abb805e232082c612f53c839f 100644 (file)
@@ -2665,11 +2665,13 @@ static int repair_inode_discount_extent(struct btrfs_trans_handle *trans,
 {
        struct rb_node *node;
        struct file_extent_hole *hole;
+       int found = 0;
        int ret = 0;
 
        node = rb_first(&rec->holes);
 
        while (node) {
+               found = 1;
                hole = rb_entry(node, struct file_extent_hole, node);
                ret = btrfs_punch_hole(trans, root, rec->ino,
                                       hole->start, hole->len);
@@ -2683,6 +2685,13 @@ static int repair_inode_discount_extent(struct btrfs_trans_handle *trans,
                        rec->errors &= ~I_ERR_FILE_EXTENT_DISCOUNT;
                node = rb_first(&rec->holes);
        }
+       /* special case for a file losing all its file extent */
+       if (!found) {
+               ret = btrfs_punch_hole(trans, root, rec->ino, 0,
+                                      round_up(rec->isize, root->sectorsize));
+               if (ret < 0)
+                       goto out;
+       }
        printf("Fixed discount file extents for inode: %llu in root: %llu\n",
               rec->ino, root->objectid);
 out: