btrfs-progs: check: punch_extent_hole in lowmem
authorSu Yue <suy.fnst@cn.fujitsu.com>
Tue, 29 Aug 2017 03:33:23 +0000 (11:33 +0800)
committerDavid Sterba <dsterba@suse.com>
Mon, 16 Oct 2017 18:33:00 +0000 (20:33 +0200)
While checking file extents, there are two errors that may occur:

1) There is one hole between the last extent end and beginning of the
   current extent but no-holes is disabled.

2) No-holes is disabled, one file's nbytes equals 0 but isize is not 0.

Those both mean the file may have lost some extents.
To avoid btrfsck's error message, fix it by introducing function
'punch_extent_hole' to punch holes.

For case 1, punch a hole extent whose length is
  (current extent begin - last extent end)
while checking one extent.

For case 2, punch a hole extent whose length is
  (file isize - actual file size)
after traversing one entire file.

Then repair_inode_nbytes will set the nbytes to isize.

Signed-off-by: Su Yue <suy.fnst@cn.fujitsu.com>
Signed-off-by: David Sterba <dsterba@suse.com>
cmds-check.c

index ffb3e0c..edc2726 100644 (file)
@@ -5323,6 +5323,34 @@ out:
 }
 
 /*
+ * Wrapper function of btrfs_punch_hole.
+ *
+ * Returns 0 means success.
+ * Returns not 0 means error.
+ */
+static int punch_extent_hole(struct btrfs_root *root, u64 ino, u64 start,
+                            u64 len)
+{
+       struct btrfs_trans_handle *trans;
+       int ret = 0;
+
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       ret = btrfs_punch_hole(trans, root, ino, start, len);
+       if (ret)
+               error("failed to add hole [%llu, %llu] in inode [%llu]",
+                     start, len, ino);
+       else
+               printf("Add a hole [%llu, %llu] in inode [%llu]\n", start, len,
+                      ino);
+
+       btrfs_commit_transaction(trans, root);
+       return ret;
+}
+
+/*
  * Check file extent datasum/hole, update the size of the file extents,
  * check and update the last offset of the file extent.
  *
@@ -5437,9 +5465,14 @@ static int check_file_extent(struct btrfs_root *root, struct btrfs_key *fkey,
 
        /* Check EXTENT_DATA hole */
        if (!no_holes && *end != fkey->offset) {
-               err |= FILE_EXTENT_ERROR;
-               error("root %llu EXTENT_DATA[%llu %llu] interrupt",
-                     root->objectid, fkey->objectid, fkey->offset);
+               if (repair)
+                       ret = punch_extent_hole(root, fkey->objectid,
+                                               *end, fkey->offset - *end);
+               if (!repair || ret) {
+                       err |= FILE_EXTENT_ERROR;
+                       error("root %llu EXTENT_DATA[%llu %llu] interrupt",
+                             root->objectid, fkey->objectid, fkey->offset);
+               }
        }
 
        *end += extent_num_bytes;
@@ -5879,9 +5912,15 @@ out:
                }
 
                if (!nbytes && !no_holes && extent_end < isize) {
-                       err |= NBYTES_ERROR;
-                       error("root %llu INODE[%llu] size (%llu) should have a file extent hole",
-                             root->objectid, inode_id, isize);
+                       if (repair)
+                               ret = punch_extent_hole(root, inode_id,
+                                               extent_end, isize - extent_end);
+                       if (!repair || ret) {
+                               err |= NBYTES_ERROR;
+                               error(
+       "root %llu INODE[%llu] size %llu should have a file extent hole",
+                                     root->objectid, inode_id, isize);
+                       }
                }
 
                if (nbytes != extent_size) {