X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Fsnapshot.c;h=4982468bfe1182910fa6a03e3b691bf7ce8be758;hb=6a34032417d9bb90ead6f3b7bf891347bc4a1ed3;hp=03ae280aee3a668e67179a9d8a675291996020e7;hpb=63c8f14756921c1d1d6a99082a679b92aef288c1;p=bcachefs-tools-debian diff --git a/libbcachefs/snapshot.c b/libbcachefs/snapshot.c index 03ae280..4982468 100644 --- a/libbcachefs/snapshot.c +++ b/libbcachefs/snapshot.c @@ -163,8 +163,7 @@ static noinline struct snapshot_t *__snapshot_t_mut(struct bch_fs *c, u32 id) rcu_assign_pointer(c->snapshots, new); c->snapshot_table_size = new_size; - if (old) - kvfree_rcu(old); + kvfree_rcu_mightsleep(old); return &rcu_dereference_protected(c->snapshots, true)->s[idx]; } @@ -344,7 +343,7 @@ int bch2_snapshot_lookup(struct btree_trans *trans, u32 id, BTREE_ITER_WITH_UPDATES, snapshot, s); } -int bch2_snapshot_live(struct btree_trans *trans, u32 id) +static int bch2_snapshot_live(struct btree_trans *trans, u32 id) { struct bch_snapshot v; int ret; @@ -371,7 +370,7 @@ int bch2_snapshot_live(struct btree_trans *trans, u32 id) * it's part of such a linear chain: this correctly sets equivalence classes on * startup if we run leaf to root (i.e. in natural key order). */ -int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k) +static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k) { struct bch_fs *c = trans->c; unsigned i, nr_live = 0, live_idx = 0; @@ -488,18 +487,18 @@ static int bch2_snapshot_tree_master_subvol(struct btree_trans *trans, bch2_trans_iter_exit(trans, &iter); if (!ret && !found) { - struct bkey_i_subvolume *s; + struct bkey_i_subvolume *u; *subvol_id = bch2_snapshot_tree_oldest_subvol(c, snapshot_root); - s = bch2_bkey_get_mut_typed(trans, &iter, + u = bch2_bkey_get_mut_typed(trans, &iter, BTREE_ID_subvolumes, POS(0, *subvol_id), 0, subvolume); - ret = PTR_ERR_OR_ZERO(s); + ret = PTR_ERR_OR_ZERO(u); if (ret) return ret; - SET_BCH_SUBVOLUME_SNAP(&s->v, false); + SET_BCH_SUBVOLUME_SNAP(&u->v, false); } return ret; @@ -591,11 +590,11 @@ int bch2_check_snapshot_trees(struct bch_fs *c) int ret; ret = bch2_trans_run(c, - for_each_btree_key_commit(&trans, iter, + for_each_btree_key_commit(trans, iter, BTREE_ID_snapshot_trees, POS_MIN, BTREE_ITER_PREFETCH, k, NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, - check_snapshot_tree(&trans, &iter, k))); + check_snapshot_tree(trans, &iter, k))); if (ret) bch_err(c, "error %i checking snapshot trees", ret); @@ -864,11 +863,11 @@ int bch2_check_snapshots(struct bch_fs *c) * the parent's depth already be correct: */ ret = bch2_trans_run(c, - for_each_btree_key_reverse_commit(&trans, iter, + for_each_btree_key_reverse_commit(trans, iter, BTREE_ID_snapshots, POS_MAX, BTREE_ITER_PREFETCH, k, NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, - check_snapshot(&trans, &iter, k))); + check_snapshot(trans, &iter, k))); if (ret) bch_err_fn(c, ret); return ret; @@ -911,7 +910,7 @@ static inline void normalize_snapshot_child_pointers(struct bch_snapshot *s) swap(s->children[0], s->children[1]); } -int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) +static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) { struct bch_fs *c = trans->c; struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; @@ -1072,6 +1071,10 @@ static int create_snapids(struct btree_trans *trans, u32 parent, u32 tree, goto err; new_snapids[i] = iter.pos.offset; + + mutex_lock(&c->snapshot_table_lock); + snapshot_t_mut(c, new_snapids[i])->equiv = new_snapids[i]; + mutex_unlock(&c->snapshot_table_lock); } err: bch2_trans_iter_exit(trans, &iter); @@ -1285,6 +1288,9 @@ static inline u32 bch2_snapshot_nth_parent_skip(struct bch_fs *c, u32 id, u32 n, snapshot_id_list *skip) { rcu_read_lock(); + while (snapshot_list_has_id(skip, id)) + id = __bch2_snapshot_parent(c, id); + while (n--) { do { id = __bch2_snapshot_parent(c, id); @@ -1354,7 +1360,7 @@ static int bch2_fix_child_of_deleted_snapshot(struct btree_trans *trans, int bch2_delete_dead_snapshots(struct bch_fs *c) { - struct btree_trans trans; + struct btree_trans *trans; struct btree_iter iter; struct bkey_s_c k; struct bkey_s_c_snapshot snap; @@ -1366,35 +1372,35 @@ int bch2_delete_dead_snapshots(struct bch_fs *c) if (!test_bit(BCH_FS_STARTED, &c->flags)) { ret = bch2_fs_read_write_early(c); if (ret) { - bch_err(c, "error deleleting dead snapshots: error going rw: %s", bch2_err_str(ret)); + bch_err_msg(c, ret, "deleting dead snapshots: error going rw"); return ret; } } - bch2_trans_init(&trans, c, 0, 0); + trans = bch2_trans_get(c); /* * For every snapshot node: If we have no live children and it's not * pointed to by a subvolume, delete it: */ - ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, + ret = for_each_btree_key_commit(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, NULL, NULL, 0, - bch2_delete_redundant_snapshot(&trans, &iter, k)); + bch2_delete_redundant_snapshot(trans, &iter, k)); if (ret) { - bch_err(c, "error deleting redundant snapshots: %s", bch2_err_str(ret)); + bch_err_msg(c, ret, "deleting redundant snapshots"); goto err; } - for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, - POS_MIN, 0, k, - bch2_snapshot_set_equiv(&trans, k)); + ret = for_each_btree_key2(trans, iter, BTREE_ID_snapshots, + POS_MIN, 0, k, + bch2_snapshot_set_equiv(trans, k)); if (ret) { - bch_err(c, "error in bch2_snapshots_set_equiv: %s", bch2_err_str(ret)); + bch_err_msg(c, ret, "in bch2_snapshots_set_equiv"); goto err; } - for_each_btree_key(&trans, iter, BTREE_ID_snapshots, + for_each_btree_key(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, ret) { if (k.k->type != KEY_TYPE_snapshot) continue; @@ -1406,7 +1412,7 @@ int bch2_delete_dead_snapshots(struct bch_fs *c) break; } } - bch2_trans_iter_exit(&trans, &iter); + bch2_trans_iter_exit(trans, &iter); if (ret) { bch_err_msg(c, ret, "walking snapshots"); @@ -1421,16 +1427,16 @@ int bch2_delete_dead_snapshots(struct bch_fs *c) if (!btree_type_has_snapshots(id)) continue; - ret = for_each_btree_key_commit(&trans, iter, + ret = for_each_btree_key_commit(trans, iter, id, POS_MIN, BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, &res, NULL, BTREE_INSERT_NOFAIL, - snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos)) ?: - for_each_btree_key_commit(&trans, iter, + snapshot_delete_key(trans, &iter, k, &deleted, &equiv_seen, &last_pos)) ?: + for_each_btree_key_commit(trans, iter, id, POS_MIN, BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, &res, NULL, BTREE_INSERT_NOFAIL, - move_key_to_correct_snapshot(&trans, &iter, k)); + move_key_to_correct_snapshot(trans, &iter, k)); bch2_disk_reservation_put(c, &res); darray_exit(&equiv_seen); @@ -1441,7 +1447,9 @@ int bch2_delete_dead_snapshots(struct bch_fs *c) } } - for_each_btree_key(&trans, iter, BTREE_ID_snapshots, + down_write(&c->snapshot_create_lock); + + for_each_btree_key(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, ret) { u32 snapshot = k.k->p.offset; u32 equiv = bch2_snapshot_equiv(c, snapshot); @@ -1449,43 +1457,48 @@ int bch2_delete_dead_snapshots(struct bch_fs *c) if (equiv != snapshot) snapshot_list_add(c, &deleted_interior, snapshot); } - bch2_trans_iter_exit(&trans, &iter); + bch2_trans_iter_exit(trans, &iter); + + if (ret) + goto err_create_lock; /* * Fixing children of deleted snapshots can't be done completely * atomically, if we crash between here and when we delete the interior * nodes some depth fields will be off: */ - ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, POS_MIN, + ret = for_each_btree_key_commit(trans, iter, BTREE_ID_snapshots, POS_MIN, BTREE_ITER_INTENT, k, NULL, NULL, BTREE_INSERT_NOFAIL, - bch2_fix_child_of_deleted_snapshot(&trans, &iter, k, &deleted_interior)); + bch2_fix_child_of_deleted_snapshot(trans, &iter, k, &deleted_interior)); if (ret) - goto err; + goto err_create_lock; darray_for_each(deleted, i) { - ret = commit_do(&trans, NULL, NULL, 0, - bch2_snapshot_node_delete(&trans, *i)); + ret = commit_do(trans, NULL, NULL, 0, + bch2_snapshot_node_delete(trans, *i)); if (ret) { bch_err_msg(c, ret, "deleting snapshot %u", *i); - goto err; + goto err_create_lock; } } darray_for_each(deleted_interior, i) { - ret = commit_do(&trans, NULL, NULL, 0, - bch2_snapshot_node_delete(&trans, *i)); + ret = commit_do(trans, NULL, NULL, 0, + bch2_snapshot_node_delete(trans, *i)); if (ret) { bch_err_msg(c, ret, "deleting snapshot %u", *i); - goto err; + goto err_create_lock; } } clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); +err_create_lock: + up_write(&c->snapshot_create_lock); err: darray_exit(&deleted_interior); darray_exit(&deleted); - bch2_trans_exit(&trans); + bch2_trans_put(trans); if (ret) bch_err_fn(c, ret); return ret; @@ -1618,7 +1631,8 @@ int bch2_propagate_key_to_snapshot_leaves(struct btree_trans *trans, { struct bch_fs *c = trans->c; struct bkey_buf sk; - int ret; + u32 restart_count = trans->restart_count; + int ret = 0; bch2_bkey_buf_init(&sk); bch2_bkey_buf_reassemble(&sk, c, k); @@ -1632,15 +1646,22 @@ int bch2_propagate_key_to_snapshot_leaves(struct btree_trans *trans, if (!bch2_snapshot_is_ancestor(c, id, k.k->p.snapshot) || !bch2_snapshot_is_leaf(c, id)) continue; +again: + ret = btree_trans_too_many_iters(trans) ?: + bch2_propagate_key_to_snapshot_leaf(trans, btree, k, id, new_min_pos) ?: + bch2_trans_commit(trans, NULL, NULL, 0); + if (ret && bch2_err_matches(ret, BCH_ERR_transaction_restart)) { + bch2_trans_begin(trans); + goto again; + } - ret = commit_do(trans, NULL, NULL, 0, - bch2_propagate_key_to_snapshot_leaf(trans, btree, k, id, new_min_pos)); if (ret) break; } bch2_bkey_buf_exit(&sk, c); - return ret; + + return ret ?: trans_was_restarted(trans, restart_count); } int bch2_snapshots_read(struct bch_fs *c) @@ -1650,11 +1671,11 @@ int bch2_snapshots_read(struct bch_fs *c) int ret = 0; ret = bch2_trans_run(c, - for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, + for_each_btree_key2(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, - bch2_mark_snapshot(&trans, BTREE_ID_snapshots, 0, bkey_s_c_null, k, 0) ?: - bch2_snapshot_set_equiv(&trans, k)) ?: - for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, + bch2_mark_snapshot(trans, BTREE_ID_snapshots, 0, bkey_s_c_null, k, 0) ?: + bch2_snapshot_set_equiv(trans, k)) ?: + for_each_btree_key2(trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, (set_is_ancestor_bitmap(c, k.k->p.offset), 0))); if (ret)