diff options
Diffstat (limited to 'fs/bcachefs/btree_update.c')
-rw-r--r-- | fs/bcachefs/btree_update.c | 181 |
1 files changed, 80 insertions, 101 deletions
diff --git a/fs/bcachefs/btree_update.c b/fs/bcachefs/btree_update.c index ff7b53c6b0fb..f59f018fe0d8 100644 --- a/fs/bcachefs/btree_update.c +++ b/fs/bcachefs/btree_update.c @@ -12,6 +12,7 @@ #include "extents.h" #include "keylist.h" #include "snapshot.h" +#include "super-io.h" #include "trace.h" #include <linux/string_helpers.h> @@ -95,7 +96,6 @@ static noinline int extent_back_merge(struct btree_trans *trans, static int need_whiteout_for_snapshot(struct btree_trans *trans, enum btree_id btree_id, struct bpos pos) { - struct btree_iter iter; struct bkey_s_c k; u32 snapshot = pos.snapshot; int ret; @@ -117,7 +117,6 @@ static int need_whiteout_for_snapshot(struct btree_trans *trans, break; } } - bch2_trans_iter_exit(trans, &iter); return ret; } @@ -131,10 +130,8 @@ int __bch2_insert_snapshot_whiteouts(struct btree_trans *trans, darray_for_each(*s, id) { pos.snapshot = *id; - struct btree_iter iter; - struct bkey_s_c k = bch2_bkey_get_iter(trans, &iter, btree, pos, - BTREE_ITER_not_extents| - BTREE_ITER_intent); + CLASS(btree_iter, iter)(trans, btree, pos, BTREE_ITER_not_extents|BTREE_ITER_intent); + struct bkey_s_c k = bch2_btree_iter_peek_slot(&iter); ret = bkey_err(k); if (ret) break; @@ -143,7 +140,6 @@ int __bch2_insert_snapshot_whiteouts(struct btree_trans *trans, struct bkey_i *update = bch2_trans_kmalloc(trans, sizeof(struct bkey_i)); ret = PTR_ERR_OR_ZERO(update); if (ret) { - bch2_trans_iter_exit(trans, &iter); break; } @@ -154,7 +150,6 @@ int __bch2_insert_snapshot_whiteouts(struct btree_trans *trans, ret = bch2_trans_update(trans, &iter, update, BTREE_UPDATE_internal_snapshot_node); } - bch2_trans_iter_exit(trans, &iter); if (ret) break; @@ -164,7 +159,7 @@ int __bch2_insert_snapshot_whiteouts(struct btree_trans *trans, return ret; } -static inline enum bch_bkey_type extent_whiteout_type(enum btree_id btree, const struct bkey *k) +static inline enum bch_bkey_type extent_whiteout_type(struct bch_fs *c, enum btree_id btree, const struct bkey *k) { /* * KEY_TYPE_extent_whiteout indicates that there isn't a real extent @@ -172,7 +167,9 @@ static inline enum bch_bkey_type extent_whiteout_type(enum btree_id btree, const * KEY_TYPE_extent_whiteout (but not KEY_TYPE_whiteout) are * monotonically increasing */ - return btree_id_is_extents_snapshots(btree) && bkey_deleted(k) + return btree_id_is_extents_snapshots(btree) && + bkey_deleted(k) && + !bch2_request_incompat_feature(c, bcachefs_metadata_version_extent_snapshot_whiteouts) ? KEY_TYPE_extent_whiteout : KEY_TYPE_whiteout; } @@ -234,7 +231,7 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans, return ret; } - if (bkey_le(old.k->p, new.k->p)) { + if (!back_split) { update = bch2_trans_kmalloc(trans, sizeof(*update)); if ((ret = PTR_ERR_OR_ZERO(update))) return ret; @@ -243,23 +240,21 @@ int bch2_trans_update_extent_overwrite(struct btree_trans *trans, update->k.p = old.k->p; update->k.p.snapshot = new.k->p.snapshot; - if (new.k->p.snapshot != old.k->p.snapshot) { - update->k.type = extent_whiteout_type(iter->btree_id, new.k); - } else if (btree_type_has_snapshots(btree_id)) { - ret = need_whiteout_for_snapshot(trans, btree_id, update->k.p); + if (btree_type_has_snapshots(btree_id)) { + ret = new.k->p.snapshot != old.k->p.snapshot + ? 1 + : need_whiteout_for_snapshot(trans, btree_id, update->k.p); if (ret < 0) return ret; if (ret) - update->k.type = extent_whiteout_type(iter->btree_id, new.k); + update->k.type = extent_whiteout_type(trans->c, iter->btree_id, new.k); } ret = bch2_btree_insert_nonextent(trans, btree_id, update, BTREE_UPDATE_internal_snapshot_node|flags); if (ret) return ret; - } - - if (back_split) { + } else { update = bch2_bkey_make_mut_noupdate(trans, old); if ((ret = PTR_ERR_OR_ZERO(update))) return ret; @@ -281,19 +276,17 @@ static int bch2_trans_update_extent(struct btree_trans *trans, struct bkey_i *insert, enum btree_iter_update_trigger_flags flags) { - struct btree_iter iter; - struct bkey_s_c k; enum btree_id btree_id = orig_iter->btree_id; - int ret = 0; - bch2_trans_iter_init(trans, &iter, btree_id, bkey_start_pos(&insert->k), - BTREE_ITER_intent| - BTREE_ITER_with_updates| - BTREE_ITER_not_extents| - BTREE_ITER_nofilter_whiteouts); - k = bch2_btree_iter_peek_max(trans, &iter, POS(insert->k.p.inode, U64_MAX)); - if ((ret = bkey_err(k))) - goto err; + CLASS(btree_iter, iter)(trans, btree_id, bkey_start_pos(&insert->k), + BTREE_ITER_intent| + BTREE_ITER_with_updates| + BTREE_ITER_not_extents| + BTREE_ITER_nofilter_whiteouts); + struct bkey_s_c k = bch2_btree_iter_peek_max(&iter, POS(insert->k.p.inode, U64_MAX)); + int ret = bkey_err(k); + if (ret) + return ret; if (!k.k) goto out; @@ -301,47 +294,54 @@ static int bch2_trans_update_extent(struct btree_trans *trans, if (bch2_bkey_maybe_mergable(k.k, &insert->k)) { ret = extent_front_merge(trans, &iter, k, &insert, flags); if (ret) - goto err; + return ret; } goto next; } while (true) { - if (k.k->type == KEY_TYPE_whiteout && - bkey_lt(insert->k.p, k.k->p)) - continue; + BUG_ON(bkey_le(k.k->p, bkey_start_pos(&insert->k))); - if (bkey_le(insert->k.p, bkey_start_pos(k.k))) + /* + * When KEY_TYPE_whiteout is included, bkey_start_pos is not + * monotonically increasing + */ + if (k.k->type != KEY_TYPE_whiteout && bkey_le(insert->k.p, bkey_start_pos(k.k))) break; + bool done = k.k->type != KEY_TYPE_whiteout && bkey_lt(insert->k.p, k.k->p); + if (bkey_extent_whiteout(k.k)) { - enum bch_bkey_type whiteout_type = extent_whiteout_type(btree_id, &insert->k); - if (k.k->type != whiteout_type) { - struct bkey_i *update = bch2_bkey_make_mut(trans, &iter, &k, 0); + enum bch_bkey_type whiteout_type = extent_whiteout_type(trans->c, btree_id, &insert->k); + + if (bkey_le(k.k->p, insert->k.p) && + k.k->type != whiteout_type) { + struct bkey_i *update = bch2_bkey_make_mut_noupdate(trans, k); ret = PTR_ERR_OR_ZERO(update); if (ret) - goto err; + return ret; + update->k.p.snapshot = iter.snapshot; update->k.type = whiteout_type; - } - goto next; + ret = bch2_trans_update(trans, &iter, update, 0); + if (ret) + return ret; + } + } else { + ret = bch2_trans_update_extent_overwrite(trans, &iter, flags, k, bkey_i_to_s_c(insert)); + if (ret) + return ret; } - bool done = bkey_lt(insert->k.p, k.k->p); - - ret = bch2_trans_update_extent_overwrite(trans, &iter, flags, k, bkey_i_to_s_c(insert)); - if (ret) - goto err; - if (done) goto out; next: - bch2_btree_iter_advance(trans, &iter); - k = bch2_btree_iter_peek_max(trans, &iter, POS(insert->k.p.inode, U64_MAX)); + bch2_btree_iter_advance(&iter); + k = bch2_btree_iter_peek_max(&iter, POS(insert->k.p.inode, U64_MAX)); if ((ret = bkey_err(k))) - goto err; + return ret; if (!k.k) goto out; } @@ -349,15 +349,12 @@ next: if (bch2_bkey_maybe_mergable(&insert->k, k.k)) { ret = extent_back_merge(trans, &iter, insert, k); if (ret) - goto err; + return ret; } out: - if (!bkey_deleted(&insert->k)) - ret = bch2_btree_insert_nonextent(trans, btree_id, insert, flags); -err: - bch2_trans_iter_exit(trans, &iter); - - return ret; + return !bkey_deleted(&insert->k) + ? bch2_btree_insert_nonextent(trans, btree_id, insert, flags) + : 0; } static inline struct btree_insert_entry * @@ -560,7 +557,7 @@ int __must_check bch2_trans_update_ip(struct btree_trans *trans, struct btree_it return ret; if (ret) - k->k.type = extent_whiteout_type(iter->btree_id, &k->k); + k->k.type = KEY_TYPE_whiteout; } /* @@ -629,13 +626,13 @@ int bch2_bkey_get_empty_slot(struct btree_trans *trans, struct btree_iter *iter, enum btree_id btree, struct bpos end) { bch2_trans_iter_init(trans, iter, btree, end, BTREE_ITER_intent); - struct bkey_s_c k = bch2_btree_iter_peek_prev(trans, iter); + struct bkey_s_c k = bch2_btree_iter_peek_prev(iter); int ret = bkey_err(k); if (ret) goto err; - bch2_btree_iter_advance(trans, iter); - k = bch2_btree_iter_peek_slot(trans, iter); + bch2_btree_iter_advance(iter); + k = bch2_btree_iter_peek_slot(iter); ret = bkey_err(k); if (ret) goto err; @@ -649,7 +646,7 @@ int bch2_bkey_get_empty_slot(struct btree_trans *trans, struct btree_iter *iter, return 0; err: - bch2_trans_iter_exit(trans, iter); + bch2_trans_iter_exit(iter); return ret; } @@ -664,29 +661,21 @@ int bch2_btree_insert_nonextent(struct btree_trans *trans, enum btree_id btree, struct bkey_i *k, enum btree_iter_update_trigger_flags flags) { - struct btree_iter iter; - int ret; - - bch2_trans_iter_init(trans, &iter, btree, k->k.p, - BTREE_ITER_cached| - BTREE_ITER_not_extents| - BTREE_ITER_intent); - ret = bch2_btree_iter_traverse(trans, &iter) ?: + CLASS(btree_iter, iter)(trans, btree, k->k.p, + BTREE_ITER_cached| + BTREE_ITER_not_extents| + BTREE_ITER_intent); + return bch2_btree_iter_traverse(&iter) ?: bch2_trans_update(trans, &iter, k, flags); - bch2_trans_iter_exit(trans, &iter); - return ret; } -int bch2_btree_insert_trans(struct btree_trans *trans, enum btree_id id, +int bch2_btree_insert_trans(struct btree_trans *trans, enum btree_id btree, struct bkey_i *k, enum btree_iter_update_trigger_flags flags) { - struct btree_iter iter; - bch2_trans_iter_init(trans, &iter, id, bkey_start_pos(&k->k), - BTREE_ITER_intent|flags); - int ret = bch2_btree_iter_traverse(trans, &iter) ?: - bch2_trans_update(trans, &iter, k, flags); - bch2_trans_iter_exit(trans, &iter); - return ret; + CLASS(btree_iter, iter)(trans, btree, bkey_start_pos(&k->k), + BTREE_ITER_intent|flags); + return bch2_btree_iter_traverse(&iter) ?: + bch2_trans_update(trans, &iter, k, flags); } /** @@ -728,31 +717,25 @@ int bch2_btree_delete(struct btree_trans *trans, enum btree_id btree, struct bpos pos, enum btree_iter_update_trigger_flags flags) { - struct btree_iter iter; - int ret; - - bch2_trans_iter_init(trans, &iter, btree, pos, - BTREE_ITER_cached| - BTREE_ITER_intent); - ret = bch2_btree_iter_traverse(trans, &iter) ?: + CLASS(btree_iter, iter)(trans, btree, pos, + BTREE_ITER_cached| + BTREE_ITER_intent); + return bch2_btree_iter_traverse(&iter) ?: bch2_btree_delete_at(trans, &iter, flags); - bch2_trans_iter_exit(trans, &iter); - - return ret; } -int bch2_btree_delete_range_trans(struct btree_trans *trans, enum btree_id id, +int bch2_btree_delete_range_trans(struct btree_trans *trans, enum btree_id btree, struct bpos start, struct bpos end, enum btree_iter_update_trigger_flags flags, u64 *journal_seq) { u32 restart_count = trans->restart_count; - struct btree_iter iter; struct bkey_s_c k; int ret = 0; - bch2_trans_iter_init(trans, &iter, id, start, BTREE_ITER_intent|flags); - while ((k = bch2_btree_iter_peek_max(trans, &iter, end)).k) { + CLASS(btree_iter, iter)(trans, btree, start, BTREE_ITER_intent|flags); + + while ((k = bch2_btree_iter_peek_max(&iter, end)).k) { struct disk_reservation disk_res = bch2_disk_reservation_init(trans->c, 0); struct bkey_i delete; @@ -802,7 +785,6 @@ err: if (ret) break; } - bch2_trans_iter_exit(trans, &iter); return ret ?: trans_was_restarted(trans, restart_count); } @@ -843,13 +825,10 @@ int bch2_btree_bit_mod_iter(struct btree_trans *trans, struct btree_iter *iter, int bch2_btree_bit_mod(struct btree_trans *trans, enum btree_id btree, struct bpos pos, bool set) { - struct btree_iter iter; - bch2_trans_iter_init(trans, &iter, btree, pos, BTREE_ITER_intent); + CLASS(btree_iter, iter)(trans, btree, pos, BTREE_ITER_intent); - int ret = bch2_btree_iter_traverse(trans, &iter) ?: - bch2_btree_bit_mod_iter(trans, &iter, set); - bch2_trans_iter_exit(trans, &iter); - return ret; + return bch2_btree_iter_traverse(&iter) ?: + bch2_btree_bit_mod_iter(trans, &iter, set); } int bch2_btree_bit_mod_buffered(struct btree_trans *trans, enum btree_id btree, |