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];
}
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;
* 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;
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;
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);
* 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;
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 };
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);
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);
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;
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;
break;
}
}
- bch2_trans_iter_exit(&trans, &iter);
+ bch2_trans_iter_exit(trans, &iter);
if (ret) {
bch_err_msg(c, ret, "walking snapshots");
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);
}
}
- 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);
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;
{
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);
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)
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)