After checking one inode item, we should get the actual nbytes of the
inode item.
Introduce function 'repair_inode_nbytes_lowmem' to set nbytes in struct
btrfs_inode_item to the actual nbytes. After call of the function, the
wrong nbytes should have been corrected.

Signed-off-by: Su Yue <suy.f...@cn.fujitsu.com>
---
 cmds-check.c | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 73 insertions(+), 3 deletions(-)

diff --git a/cmds-check.c b/cmds-check.c
index ad7c81b2..2797ab9e 100644
--- a/cmds-check.c
+++ b/cmds-check.c
@@ -1922,6 +1922,9 @@ static int process_one_leaf_v2(struct btrfs_root *root, 
struct btrfs_path *path,
 again:
        err |= check_inode_item(root, path, ext_ref);
 
+       /* modified cur since check_inode_item may change path */
+       cur = path->nodes[0];
+
        if (err & LAST_ITEM)
                goto out;
 
@@ -2271,6 +2274,7 @@ static int walk_down_tree_v2(struct btrfs_root *root, 
struct btrfs_path *path,
                        }
                        ret = process_one_leaf_v2(root, path, nrefs,
                                                  level, ext_ref);
+                       cur = path->nodes[*level];
                        break;
                } else {
                        ret = btrfs_check_node(root, NULL, cur);
@@ -4854,10 +4858,69 @@ static int check_file_extent(struct btrfs_root *root, 
struct btrfs_key *fkey,
 }
 
 /*
+ * Set inode item nbytes to @nbytes
+ *
+ * Returns <0  means on error
+ * Returns  0  means successful repair
+ */
+static int repair_inode_nbytes_lowmem(struct btrfs_root *root,
+                                     struct btrfs_path *path,
+                                     u64 ino, u64 nbytes)
+{
+       struct btrfs_trans_handle *trans;
+       struct btrfs_inode_item *ii;
+       struct btrfs_key key;
+       struct btrfs_key research_key;
+       int ret;
+       int ret2;
+
+       key.objectid = ino;
+       key.type = BTRFS_INODE_ITEM_KEY;
+       key.offset = 0;
+       btrfs_item_key_to_cpu(path->nodes[0], &research_key, path->slots[0]);
+       btrfs_release_path(path);
+
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans)) {
+               ret = PTR_ERR(trans);
+               goto out;
+       }
+
+       ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
+       if (ret < 0)
+               goto out;
+       if (ret > 0) {
+               ret = -ENOENT;
+               goto out;
+       }
+
+       ii = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                           struct btrfs_inode_item);
+       btrfs_set_inode_nbytes(path->nodes[0], ii, nbytes);
+       btrfs_mark_buffer_dirty(path->nodes[0]);
+
+       printf("reset nbytes for inode %llu root %llu\n", ino,
+              root->root_key.objectid);
+
+       btrfs_commit_transaction(trans, root);
+out:
+       if (ret < 0)
+               error("failed to reset nbytes for inode %llu root %llu due to 
%s",
+                     ino, root->root_key.objectid, strerror(-ret));
+
+       /* research path */
+       btrfs_release_path(path);
+       ret2 = btrfs_search_slot(NULL, root, &research_key, path, 0, 0);
+       return ret2 < 0 ? ret2 : ret;
+}
+
+/*
  * Check INODE_ITEM and related ITEMs (the same inode number)
  * 1. check link count
  * 2. check inode ref/extref
  * 3. check dir item/index
+ * Be Careful, if repair is enable, @path may be changed.
+ * Remember to reassign any context about @path in repair mode.
  *
  * @ext_ref:   the EXTENDED_IREF feature
  *
@@ -5007,9 +5070,16 @@ out:
                }
 
                if (nbytes != extent_size) {
-                       err |= NBYTES_ERROR;
-                       error("root %llu INODE[%llu] nbytes(%llu) not equal to 
extent_size(%llu)",
-                             root->objectid, inode_id, nbytes, extent_size);
+                       if (repair) {
+                               ret = repair_inode_nbytes_lowmem(root, path,
+                                                       inode_id, extent_size);
+                       }
+                       if (!repair || ret) {
+                               err |= NBYTES_ERROR;
+                               error("root %llu INODE[%llu] nbytes(%llu) not 
equal to extent_size(%llu)",
+                                     root->objectid, inode_id, nbytes,
+                                     extent_size);
+                       }
                }
        }
 
-- 
2.13.0



--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to