summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-10-19 17:30:16 -0400
committerKent Overstreet <kent.overstreet@gmail.com>2021-10-20 12:06:20 -0400
commitf37bb418d585ff9cc0a428d9ac1461b56a6848c6 (patch)
treeffc6d848542d9908403164a8519bd99905fe22f4
parentdecd5e7ab6d4f5322a1a1e02296fc2b01135ec8e (diff)
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 <kent.overstreet@gmail.com>
-rw-r--r--fs/bcachefs/bcachefs_format.h8
-rw-r--r--fs/bcachefs/fsck.c68
-rw-r--r--fs/bcachefs/recovery.c8
3 files changed, 73 insertions, 11 deletions
diff --git a/fs/bcachefs/bcachefs_format.h b/fs/bcachefs/bcachefs_format.h
index 0b8eabe5eaa4..ed7d12aa317c 100644
--- a/fs/bcachefs/bcachefs_format.h
+++ b/fs/bcachefs/bcachefs_format.h
@@ -913,10 +913,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 {
@@ -1259,7 +1256,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 a36bc840a62c..b43c31b95dff 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 6afb37a2e1b0..8c53b1e977d1 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);