diff options
author | Hongbo Li <lihongbo22@huawei.com> | 2025-01-07 13:18:41 +0000 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2025-01-13 14:58:38 -0500 |
commit | c72deb03ff0426596c69c294afa1572d2748c589 (patch) | |
tree | c8ad677227672ed06dc4e868409de368c5a8a324 | |
parent | e614a6c52d32c9c7ff545ca842eb2de4aeb1d2d9 (diff) |
bcachefs: bcachefs_metadata_version_directory_size
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>
-rw-r--r-- | fs/bcachefs/bcachefs_format.h | 3 | ||||
-rw-r--r-- | fs/bcachefs/fsck.c | 41 | ||||
-rw-r--r-- | fs/bcachefs/sb-downgrade.c | 5 | ||||
-rw-r--r-- | fs/bcachefs/sb-errors_format.h | 3 |
4 files changed, 49 insertions, 3 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index 0680930508a3..f70f0108401f 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -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, diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index 3917d75f3c98..8fcf7c8e5ede 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -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); diff --git a/fs/bcachefs/sb-downgrade.c b/fs/bcachefs/sb-downgrade.c index 051214fdc735..14f6b6a5fb38 100644 --- a/fs/bcachefs/sb-downgrade.c +++ b/fs/bcachefs/sb-downgrade.c @@ -90,7 +90,10 @@ 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, \ diff --git a/fs/bcachefs/sb-errors_format.h b/fs/bcachefs/sb-errors_format.h index 80b6d589808b..0b4fe899209b 100644 --- a/fs/bcachefs/sb-errors_format.h +++ b/fs/bcachefs/sb-errors_format.h @@ -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, |