Commit bfe88863 authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet

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: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent b71717da
......@@ -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)
......
......@@ -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)
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment