]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
bcachefs: bcachefs_metadata_version_directory_size
authorHongbo Li <lihongbo22@huawei.com>
Tue, 7 Jan 2025 13:18:41 +0000 (13:18 +0000)
committerKent Overstreet <kent.overstreet@linux.dev>
Mon, 13 Jan 2025 19:58:38 +0000 (14:58 -0500)
This adds another metadata version for accounting directory size.
For the new version of the filesystem, when new subdirectory items
are created or deleted, the parent directory's size will change
accordingly. For the old version of the existed file system, running
fsck will automatically upgrade the metadata version, and it will
do the check and recalculationg of the directory size.

Signed-off-by: Hongbo Li <lihongbo22@huawei.com>
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/fsck.c
fs/bcachefs/sb-downgrade.c
fs/bcachefs/sb-errors_format.h

index 0680930508a36ad14f34f63b1cf307e1d7684bf3..f70f0108401f7f398a2d0edc6abeb39b673c4abe 100644 (file)
@@ -685,7 +685,8 @@ struct bch_sb_field_ext {
        x(reflink_p_may_update_opts,    BCH_VERSION(1, 16))             \
        x(inode_depth,                  BCH_VERSION(1, 17))             \
        x(persistent_inode_cursors,     BCH_VERSION(1, 18))             \
-       x(autofix_errors,               BCH_VERSION(1, 19))
+       x(autofix_errors,               BCH_VERSION(1, 19))             \
+       x(directory_size,               BCH_VERSION(1, 20))
 
 enum bcachefs_metadata_version {
        bcachefs_metadata_version_min = 9,
index 3917d75f3c987e167fa5711ae3082b903afeb6aa..8fcf7c8e5ede7eb5eb778399db3750230dc731a3 100644 (file)
@@ -1116,6 +1116,37 @@ err:
        return ret;
 }
 
+static int check_directory_size(struct btree_trans *trans,
+                               struct bch_inode_unpacked *inode_u,
+                               struct bkey_s_c inode_k, bool *write_inode)
+{
+       struct btree_iter iter;
+       struct bkey_s_c k;
+       u64 new_size = 0;
+       int ret;
+
+       for_each_btree_key_max_norestart(trans, iter, BTREE_ID_dirents,
+                       SPOS(inode_k.k->p.offset, 0, inode_k.k->p.snapshot),
+                       POS(inode_k.k->p.offset, U64_MAX),
+                       0, k, ret) {
+               if (k.k->type != KEY_TYPE_dirent)
+                       continue;
+
+               struct bkey_s_c_dirent dirent = bkey_s_c_to_dirent(k);
+               struct qstr name = bch2_dirent_get_name(dirent);
+
+               new_size += dirent_occupied_size(&name);
+       }
+       bch2_trans_iter_exit(trans, &iter);
+
+       if (!ret && inode_u->bi_size != new_size) {
+               inode_u->bi_size = new_size;
+               *write_inode = true;
+       }
+
+       return ret;
+}
+
 static int check_inode(struct btree_trans *trans,
                       struct btree_iter *iter,
                       struct bkey_s_c k,
@@ -1304,6 +1335,16 @@ static int check_inode(struct btree_trans *trans,
                u.bi_journal_seq = journal_cur_seq(&c->journal);
                do_update = true;
        }
+
+       if (S_ISDIR(u.bi_mode)) {
+               ret = check_directory_size(trans, &u, k, &do_update);
+
+               fsck_err_on(ret,
+                           trans, directory_size_mismatch,
+                           "directory inode %llu:%u with the mismatch directory size",
+                           u.bi_inum, k.k->p.snapshot);
+               ret = 0;
+       }
 do_update:
        if (do_update) {
                ret = __bch2_fsck_write_inode(trans, &u);
index 051214fdc73521dd2ab5b05609fdcc34caa34daa..14f6b6a5fb38389de442706a572f99b01107208b 100644 (file)
          BIT_ULL(BCH_RECOVERY_PASS_check_allocations),         \
          BCH_FSCK_ERR_accounting_mismatch,                     \
          BCH_FSCK_ERR_accounting_key_replicas_nr_devs_0,       \
-         BCH_FSCK_ERR_accounting_key_junk_at_end)
+         BCH_FSCK_ERR_accounting_key_junk_at_end)              \
+       x(directory_size,                                       \
+         BIT_ULL(BCH_RECOVERY_PASS_check_inodes),              \
+         BCH_FSCK_ERR_directory_size_mismatch)                 \
 
 #define DOWNGRADE_TABLE()                                      \
        x(bucket_stripe_sectors,                                \
index 80b6d589808ba84dbdceba7a1ae12f0613e27203..0b4fe899209b886c3dd9e91ad22cd36b3c965f91 100644 (file)
@@ -313,7 +313,8 @@ enum bch_fsck_flags {
        x(logged_op_but_clean,                                  283,    FSCK_AUTOFIX)   \
        x(compression_opt_not_marked_in_sb,                     295,    FSCK_AUTOFIX)   \
        x(compression_type_not_marked_in_sb,                    296,    FSCK_AUTOFIX)   \
-       x(MAX,                                                  303,    0)
+       x(directory_size_mismatch,                              303,    FSCK_AUTOFIX)   \
+       x(MAX,                                                  304,    0)
 
 enum bch_sb_error_id {
 #define x(t, n, ...) BCH_FSCK_ERR_##t = n,