bcachefs: New on disk format to fix reflink_p pointers
authorKent Overstreet <kent.overstreet@gmail.com>
Tue, 19 Oct 2021 21:30:16 +0000 (17:30 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:09:14 +0000 (17:09 -0400)
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>
fs/bcachefs/bcachefs_format.h
fs/bcachefs/fsck.c
fs/bcachefs/recovery.c

index 54023edc995e4e33e66fd897edeab01e2867df2c..579acb69115d4eadf5ba2d0979756e54b6405f75 100644 (file)
@@ -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)
index a36bc840a62c56e2828b2b3152647f299a9d8b60..b43c31b95dfff339b25b03ba85b2f06cd1cee944 100644 (file)
@@ -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)
index 6afb37a2e1b04a07bb92111857dfe62f700d3185..8c53b1e977d1bf2d272e05e52be8dc812a8fcf4b 100644 (file)
@@ -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);