From bfe88863cf3063204fc49a04307fa6635554d6e3 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Tue, 19 Oct 2021 17:30:16 -0400 Subject: [PATCH] bcachefs: New on disk format to fix reflink_p pointers We had a bug where reflink_p pointers weren't being initialized to 0, and when we started using the second word, things broke badly. This patch revs the on disk format version and adds cleanup code to zero out the second word of reflink_p pointers before we start using it. Signed-off-by: Kent Overstreet --- fs/bcachefs/bcachefs_format.h | 8 ++--- fs/bcachefs/fsck.c | 68 ++++++++++++++++++++++++++++++++++- fs/bcachefs/recovery.c | 8 ++--- 3 files changed, 73 insertions(+), 11 deletions(-) diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h index 54023edc995e4..579acb69115d4 100644 --- a/fs/bcachefs/bcachefs_format.h +++ b/fs/bcachefs/bcachefs_format.h @@ -917,10 +917,7 @@ struct bch_stripe { struct bch_reflink_p { struct bch_val v; __le64 idx; - - __le32 reservation_generation; - __u8 nr_replicas; - __u8 pad[3]; + __le64 v2; }; struct bch_reflink_v { @@ -1263,7 +1260,8 @@ enum bcachefs_metadata_version { bcachefs_metadata_version_inode_backpointers = 13, bcachefs_metadata_version_btree_ptr_sectors_written = 14, bcachefs_metadata_version_snapshot_2 = 15, - bcachefs_metadata_version_max = 16, + bcachefs_metadata_version_reflink_p_fix = 16, + bcachefs_metadata_version_max = 17, }; #define bcachefs_metadata_version_current (bcachefs_metadata_version_max - 1) diff --git a/fs/bcachefs/fsck.c b/fs/bcachefs/fsck.c index a36bc840a62c5..b43c31b95dfff 100644 --- a/fs/bcachefs/fsck.c +++ b/fs/bcachefs/fsck.c @@ -2154,6 +2154,71 @@ static int check_nlinks(struct bch_fs *c) return ret; } +static int fix_reflink_p_key(struct btree_trans *trans, struct btree_iter *iter) +{ + struct bkey_s_c k; + struct bkey_s_c_reflink_p p; + struct bkey_i_reflink_p *u; + int ret; + + k = bch2_btree_iter_peek(iter); + if (!k.k) + return 0; + + ret = bkey_err(k); + if (ret) + return ret; + + if (k.k->type != KEY_TYPE_reflink_p) + return 0; + + p = bkey_s_c_to_reflink_p(k); + + if (!p.v->v2) + return 0; + + u = bch2_trans_kmalloc(trans, sizeof(*u)); + ret = PTR_ERR_OR_ZERO(u); + if (ret) + return ret; + + bkey_reassemble(&u->k_i, k); + u->v.v2 = 0; + + return bch2_trans_update(trans, iter, &u->k_i, 0); +} + +static int fix_reflink_p(struct bch_fs *c) +{ + struct btree_trans trans; + struct btree_iter iter; + struct bkey_s_c k; + int ret; + + if (c->sb.version >= bcachefs_metadata_version_reflink_p_fix) + return 0; + + bch2_trans_init(&trans, c, BTREE_ITER_MAX, 0); + + for_each_btree_key(&trans, iter, BTREE_ID_extents, POS_MIN, + BTREE_ITER_INTENT| + BTREE_ITER_PREFETCH| + BTREE_ITER_ALL_SNAPSHOTS, k, ret) { + if (k.k->type == KEY_TYPE_reflink_p) { + ret = __bch2_trans_do(&trans, NULL, NULL, + BTREE_INSERT_NOFAIL| + BTREE_INSERT_LAZY_RW, + fix_reflink_p_key(&trans, &iter)); + if (ret) + break; + } + } + bch2_trans_iter_exit(&trans, &iter); + + bch2_trans_exit(&trans); + return ret; +} + /* * Checks for inconsistencies that shouldn't happen, unless we have a bug. * Doesn't fix them yet, mainly because they haven't yet been observed: @@ -2168,7 +2233,8 @@ int bch2_fsck_full(struct bch_fs *c) check_xattrs(c) ?: check_root(c) ?: check_directory_structure(c) ?: - check_nlinks(c); + check_nlinks(c) ?: + fix_reflink_p(c); } int bch2_fsck_walk_inodes_only(struct bch_fs *c) diff --git a/fs/bcachefs/recovery.c b/fs/bcachefs/recovery.c index 6afb37a2e1b04..8c53b1e977d1b 100644 --- a/fs/bcachefs/recovery.c +++ b/fs/bcachefs/recovery.c @@ -1086,12 +1086,10 @@ int bch2_fs_recovery(struct bch_fs *c) c->opts.version_upgrade = true; c->opts.fsck = true; c->opts.fix_errors = FSCK_OPT_YES; - } else if (c->sb.version < bcachefs_metadata_version_btree_ptr_sectors_written) { - bch_info(c, "version prior to btree_ptr_sectors_written, upgrade required"); - c->opts.version_upgrade = true; - } else if (c->sb.version < bcachefs_metadata_version_snapshot_2) { - bch_info(c, "filesystem version is prior to snapshots - upgrading"); + } else if (c->sb.version < bcachefs_metadata_version_reflink_p_fix) { + bch_info(c, "filesystem version is prior to reflink_p fix - upgrading"); c->opts.version_upgrade = true; + c->opts.fsck = true; } ret = bch2_blacklist_table_initialize(c); -- 2.30.2