diff options
author | Kent Overstreet <kent.overstreet@linux.dev> | 2023-02-17 07:42:09 +0300 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@linux.dev> | 2023-10-23 00:09:53 +0300 |
commit | f2a53270c7d6bceae5441ed180516d3b76799680 (patch) | |
tree | 07258e950c5ec9771ffe75a0cff325407fe0049c /fs | |
parent | 19d6521964ed0439a7a03776d8cf0451afb63c1d (diff) | |
download | linux-f2a53270c7d6bceae5441ed180516d3b76799680.tar.xz |
bcachefs: Fix insert_snapshot_whiteouts()
- We were failing to set the key type on the whiteouts it was creating,
oops.
- Also, we need to create whiteouts when generating front splits, not
just back splits.
Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/bcachefs/data_update.c | 66 | ||||
-rw-r--r-- | fs/bcachefs/subvolume.h | 7 |
2 files changed, 51 insertions, 22 deletions
diff --git a/fs/bcachefs/data_update.c b/fs/bcachefs/data_update.c index 09a5fff339fe..c3adc7b32e19 100644 --- a/fs/bcachefs/data_update.c +++ b/fs/bcachefs/data_update.c @@ -21,9 +21,10 @@ static int insert_snapshot_whiteouts(struct btree_trans *trans, struct bpos new_pos) { struct bch_fs *c = trans->c; - struct btree_iter iter; - struct bkey_s_c k; + struct btree_iter iter, iter2; + struct bkey_s_c k, k2; snapshot_id_list s; + struct bkey_i *update; int ret; if (!btree_type_has_snapshots(id)) @@ -31,10 +32,7 @@ static int insert_snapshot_whiteouts(struct btree_trans *trans, darray_init(&s); - if (bkey_eq(old_pos, new_pos)) - return 0; - - if (!snapshot_t(c, old_pos.snapshot)->children[0]) + if (!bch2_snapshot_has_children(c, old_pos.snapshot)) return 0; bch2_trans_iter_init(trans, &iter, id, old_pos, @@ -46,27 +44,39 @@ static int insert_snapshot_whiteouts(struct btree_trans *trans, if (ret) break; + if (!k.k) + break; + if (!bkey_eq(old_pos, k.k->p)) break; - if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, old_pos.snapshot)) { - struct bkey_i *update; + if (bch2_snapshot_is_ancestor(c, k.k->p.snapshot, old_pos.snapshot) && + !snapshot_list_has_ancestor(c, &s, k.k->p.snapshot)) { + struct bpos whiteout_pos = new_pos; - if (snapshot_list_has_ancestor(c, &s, k.k->p.snapshot)) - continue; + whiteout_pos.snapshot = k.k->p.snapshot; - update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i)); + bch2_trans_iter_init(trans, &iter2, id, whiteout_pos, + BTREE_ITER_NOT_EXTENTS| + BTREE_ITER_INTENT); + k2 = bch2_btree_iter_peek_slot(&iter2); + ret = bkey_err(k2); - ret = PTR_ERR_OR_ZERO(update); - if (ret) - break; + if (!ret && k2.k->type == KEY_TYPE_deleted) { + update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i)); + ret = PTR_ERR_OR_ZERO(update); + if (ret) + break; - bkey_init(&update->k); - update->k.p = new_pos; - update->k.p.snapshot = k.k->p.snapshot; + bkey_init(&update->k); + update->k.p = whiteout_pos; + update->k.type = KEY_TYPE_whiteout; + + ret = bch2_trans_update(trans, &iter2, update, + BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE); + } + bch2_trans_iter_exit(trans, &iter2); - ret = bch2_btree_insert_nonextent(trans, id, update, - BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE); if (ret) break; @@ -222,9 +232,21 @@ static int __bch2_data_update_index_update(struct btree_trans *trans, next_pos = insert->k.p; - ret = insert_snapshot_whiteouts(trans, m->btree_id, - k.k->p, insert->k.p) ?: - bch2_trans_update(trans, &iter, insert, + if (!bkey_eq(bkey_start_pos(&insert->k), bkey_start_pos(k.k))) { + ret = insert_snapshot_whiteouts(trans, m->btree_id, k.k->p, + bkey_start_pos(&insert->k)); + if (ret) + goto err; + } + + if (!bkey_eq(insert->k.p, k.k->p)) { + ret = insert_snapshot_whiteouts(trans, m->btree_id, + k.k->p, insert->k.p); + if (ret) + goto err; + } + + ret = bch2_trans_update(trans, &iter, insert, BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE) ?: bch2_trans_commit(trans, &op->res, NULL, diff --git a/fs/bcachefs/subvolume.h b/fs/bcachefs/subvolume.h index 65f108a83835..7c488c3d78e0 100644 --- a/fs/bcachefs/subvolume.h +++ b/fs/bcachefs/subvolume.h @@ -68,6 +68,13 @@ static inline bool bch2_snapshot_is_ancestor(struct bch_fs *c, u32 id, u32 ances return id == ancestor; } +static inline bool bch2_snapshot_has_children(struct bch_fs *c, u32 id) +{ + struct snapshot_t *t = snapshot_t(c, id); + + return (t->children[0]|t->children[1]) != 0; +} + static inline bool snapshot_list_has_id(snapshot_id_list *s, u32 id) { u32 *i; |