From a47604de3ee0ecbf79ce9d3fd271562177777ec8 Mon Sep 17 00:00:00 2001 From: Su Yue Date: Tue, 29 Aug 2017 11:33:23 +0800 Subject: [PATCH] btrfs-progs: check: punch_extent_hole in lowmem 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 Signed-off-by: David Sterba --- cmds-check.c | 51 +++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 45 insertions(+), 6 deletions(-) diff --git a/cmds-check.c b/cmds-check.c index ffb3e0ca..edc2726c 100644 --- a/cmds-check.c +++ b/cmds-check.c @@ -5322,6 +5322,34 @@ out: return err; } +/* + * 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) {