114b393eeSKent Overstreet // SPDX-License-Identifier: GPL-2.0 214b393eeSKent Overstreet 314b393eeSKent Overstreet #include "bcachefs.h" 414b393eeSKent Overstreet #include "btree_key_cache.h" 514b393eeSKent Overstreet #include "btree_update.h" 614b393eeSKent Overstreet #include "error.h" 72027875bSKent Overstreet #include "fs.h" 814b393eeSKent Overstreet #include "subvolume.h" 914b393eeSKent Overstreet 1014b393eeSKent Overstreet /* Snapshot tree: */ 1114b393eeSKent Overstreet 1214b393eeSKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *); 1314b393eeSKent Overstreet static void bch2_delete_dead_snapshots(struct bch_fs *); 1414b393eeSKent Overstreet 1514b393eeSKent Overstreet void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, 1614b393eeSKent Overstreet struct bkey_s_c k) 1714b393eeSKent Overstreet { 1814b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k); 1914b393eeSKent Overstreet 20*416cc426SKent Overstreet prt_printf(out, "is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u", 2114b393eeSKent Overstreet BCH_SNAPSHOT_SUBVOL(s.v), 2214b393eeSKent Overstreet BCH_SNAPSHOT_DELETED(s.v), 2314b393eeSKent Overstreet le32_to_cpu(s.v->parent), 2414b393eeSKent Overstreet le32_to_cpu(s.v->children[0]), 2514b393eeSKent Overstreet le32_to_cpu(s.v->children[1]), 2614b393eeSKent Overstreet le32_to_cpu(s.v->subvol)); 2714b393eeSKent Overstreet } 2814b393eeSKent Overstreet 29f0ac7df2SKent Overstreet int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, 30275c8426SKent Overstreet int rw, struct printbuf *err) 3114b393eeSKent Overstreet { 3214b393eeSKent Overstreet struct bkey_s_c_snapshot s; 3314b393eeSKent Overstreet u32 i, id; 3414b393eeSKent Overstreet 3514b393eeSKent Overstreet if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 || 36f0ac7df2SKent Overstreet bkey_cmp(k.k->p, POS(0, 1)) < 0) { 37401ec4dbSKent Overstreet prt_printf(err, "bad pos"); 38f0ac7df2SKent Overstreet return -EINVAL; 39f0ac7df2SKent Overstreet } 4014b393eeSKent Overstreet 41f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) { 42401ec4dbSKent Overstreet prt_printf(err, "bad val size (%zu != %zu)", 43f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_snapshot)); 44f0ac7df2SKent Overstreet return -EINVAL; 45f0ac7df2SKent Overstreet } 4614b393eeSKent Overstreet 4714b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 4814b393eeSKent Overstreet 4914b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 50f0ac7df2SKent Overstreet if (id && id <= k.k->p.offset) { 51401ec4dbSKent Overstreet prt_printf(err, "bad parent node (%u <= %llu)", 52f0ac7df2SKent Overstreet id, k.k->p.offset); 53f0ac7df2SKent Overstreet return -EINVAL; 54f0ac7df2SKent Overstreet } 5514b393eeSKent Overstreet 56f0ac7df2SKent Overstreet if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) { 57401ec4dbSKent Overstreet prt_printf(err, "children not normalized"); 58f0ac7df2SKent Overstreet return -EINVAL; 59f0ac7df2SKent Overstreet } 6014b393eeSKent Overstreet 6114b393eeSKent Overstreet if (s.v->children[0] && 62f0ac7df2SKent Overstreet s.v->children[0] == s.v->children[1]) { 63401ec4dbSKent Overstreet prt_printf(err, "duplicate child nodes"); 64f0ac7df2SKent Overstreet return -EINVAL; 65f0ac7df2SKent Overstreet } 6614b393eeSKent Overstreet 6714b393eeSKent Overstreet for (i = 0; i < 2; i++) { 6814b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 6914b393eeSKent Overstreet 70f0ac7df2SKent Overstreet if (id >= k.k->p.offset) { 71401ec4dbSKent Overstreet prt_printf(err, "bad child node (%u >= %llu)", 72f0ac7df2SKent Overstreet id, k.k->p.offset); 73f0ac7df2SKent Overstreet return -EINVAL; 74f0ac7df2SKent Overstreet } 7514b393eeSKent Overstreet } 7614b393eeSKent Overstreet 77f0ac7df2SKent Overstreet return 0; 7814b393eeSKent Overstreet } 7914b393eeSKent Overstreet 80904823deSKent Overstreet int bch2_mark_snapshot(struct btree_trans *trans, 8114b393eeSKent Overstreet struct bkey_s_c old, struct bkey_s_c new, 82904823deSKent Overstreet unsigned flags) 8314b393eeSKent Overstreet { 84904823deSKent Overstreet struct bch_fs *c = trans->c; 8514b393eeSKent Overstreet struct snapshot_t *t; 8614b393eeSKent Overstreet 8714b393eeSKent Overstreet t = genradix_ptr_alloc(&c->snapshots, 8814b393eeSKent Overstreet U32_MAX - new.k->p.offset, 8914b393eeSKent Overstreet GFP_KERNEL); 9014b393eeSKent Overstreet if (!t) 9114b393eeSKent Overstreet return -ENOMEM; 9214b393eeSKent Overstreet 9314b393eeSKent Overstreet if (new.k->type == KEY_TYPE_snapshot) { 9414b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new); 9514b393eeSKent Overstreet 9614b393eeSKent Overstreet t->parent = le32_to_cpu(s.v->parent); 9714b393eeSKent Overstreet t->children[0] = le32_to_cpu(s.v->children[0]); 9814b393eeSKent Overstreet t->children[1] = le32_to_cpu(s.v->children[1]); 9914b393eeSKent Overstreet t->subvol = BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0; 10014b393eeSKent Overstreet } else { 10114b393eeSKent Overstreet t->parent = 0; 10214b393eeSKent Overstreet t->children[0] = 0; 10314b393eeSKent Overstreet t->children[1] = 0; 10414b393eeSKent Overstreet t->subvol = 0; 10514b393eeSKent Overstreet } 10614b393eeSKent Overstreet 10714b393eeSKent Overstreet return 0; 10814b393eeSKent Overstreet } 10914b393eeSKent Overstreet 11014b393eeSKent Overstreet static int snapshot_lookup(struct btree_trans *trans, u32 id, 11114b393eeSKent Overstreet struct bch_snapshot *s) 11214b393eeSKent Overstreet { 11314b393eeSKent Overstreet struct btree_iter iter; 11414b393eeSKent Overstreet struct bkey_s_c k; 11514b393eeSKent Overstreet int ret; 11614b393eeSKent Overstreet 11714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 11814b393eeSKent Overstreet BTREE_ITER_WITH_UPDATES); 11914b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 12014b393eeSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT; 12114b393eeSKent Overstreet 12214b393eeSKent Overstreet if (!ret) 12314b393eeSKent Overstreet *s = *bkey_s_c_to_snapshot(k).v; 12414b393eeSKent Overstreet 12514b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 12614b393eeSKent Overstreet return ret; 12714b393eeSKent Overstreet } 12814b393eeSKent Overstreet 12914b393eeSKent Overstreet static int snapshot_live(struct btree_trans *trans, u32 id) 13014b393eeSKent Overstreet { 13114b393eeSKent Overstreet struct bch_snapshot v; 13214b393eeSKent Overstreet int ret; 13314b393eeSKent Overstreet 13414b393eeSKent Overstreet if (!id) 13514b393eeSKent Overstreet return 0; 13614b393eeSKent Overstreet 13714b393eeSKent Overstreet ret = lockrestart_do(trans, snapshot_lookup(trans, id, &v)); 13814b393eeSKent Overstreet if (ret == -ENOENT) 13914b393eeSKent Overstreet bch_err(trans->c, "snapshot node %u not found", id); 14014b393eeSKent Overstreet if (ret) 14114b393eeSKent Overstreet return ret; 14214b393eeSKent Overstreet 14314b393eeSKent Overstreet return !BCH_SNAPSHOT_DELETED(&v); 14414b393eeSKent Overstreet } 14514b393eeSKent Overstreet 14614b393eeSKent Overstreet static int bch2_snapshots_set_equiv(struct btree_trans *trans) 14714b393eeSKent Overstreet { 14814b393eeSKent Overstreet struct bch_fs *c = trans->c; 14914b393eeSKent Overstreet struct btree_iter iter; 15014b393eeSKent Overstreet struct bkey_s_c k; 15114b393eeSKent Overstreet struct bkey_s_c_snapshot snap; 15214b393eeSKent Overstreet unsigned i; 15314b393eeSKent Overstreet int ret; 15414b393eeSKent Overstreet 15514b393eeSKent Overstreet for_each_btree_key(trans, iter, BTREE_ID_snapshots, 15614b393eeSKent Overstreet POS_MIN, 0, k, ret) { 15714b393eeSKent Overstreet u32 id = k.k->p.offset, child[2]; 15881cdc8f3SKent Overstreet unsigned nr_live = 0, live_idx = 0; 15914b393eeSKent Overstreet 16014b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 16114b393eeSKent Overstreet continue; 16214b393eeSKent Overstreet 16314b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 16414b393eeSKent Overstreet child[0] = le32_to_cpu(snap.v->children[0]); 16514b393eeSKent Overstreet child[1] = le32_to_cpu(snap.v->children[1]); 16614b393eeSKent Overstreet 16714b393eeSKent Overstreet for (i = 0; i < 2; i++) { 16814b393eeSKent Overstreet ret = snapshot_live(trans, child[i]); 16914b393eeSKent Overstreet if (ret < 0) 17081cdc8f3SKent Overstreet goto err; 17114b393eeSKent Overstreet 17214b393eeSKent Overstreet if (ret) 17314b393eeSKent Overstreet live_idx = i; 17414b393eeSKent Overstreet nr_live += ret; 17514b393eeSKent Overstreet } 17614b393eeSKent Overstreet 17714b393eeSKent Overstreet snapshot_t(c, id)->equiv = nr_live == 1 17814b393eeSKent Overstreet ? snapshot_t(c, child[live_idx])->equiv 17914b393eeSKent Overstreet : id; 18014b393eeSKent Overstreet } 18181cdc8f3SKent Overstreet err: 18214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 18314b393eeSKent Overstreet 18414b393eeSKent Overstreet if (ret) 18514b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 18614b393eeSKent Overstreet 18714b393eeSKent Overstreet return ret; 18814b393eeSKent Overstreet } 18914b393eeSKent Overstreet 19014b393eeSKent Overstreet /* fsck: */ 19114b393eeSKent Overstreet static int bch2_snapshot_check(struct btree_trans *trans, 19214b393eeSKent Overstreet struct bkey_s_c_snapshot s) 19314b393eeSKent Overstreet { 19414b393eeSKent Overstreet struct bch_subvolume subvol; 19514b393eeSKent Overstreet struct bch_snapshot v; 19614b393eeSKent Overstreet u32 i, id; 19714b393eeSKent Overstreet int ret; 19814b393eeSKent Overstreet 199*416cc426SKent Overstreet if (!BCH_SNAPSHOT_DELETED(s.v)) { 20014b393eeSKent Overstreet id = le32_to_cpu(s.v->subvol); 20197996ddfSKent Overstreet ret = lockrestart_do(trans, bch2_subvolume_get(trans, id, 0, false, &subvol)); 20214b393eeSKent Overstreet if (ret == -ENOENT) 20314b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent subvolume %u", 20414b393eeSKent Overstreet s.k->p.offset, id); 20514b393eeSKent Overstreet if (ret) 20614b393eeSKent Overstreet return ret; 20714b393eeSKent Overstreet 20814b393eeSKent Overstreet if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) { 20914b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL", 21014b393eeSKent Overstreet s.k->p.offset); 21114b393eeSKent Overstreet return -EINVAL; 21214b393eeSKent Overstreet } 213*416cc426SKent Overstreet } 21414b393eeSKent Overstreet 21514b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 21614b393eeSKent Overstreet if (id) { 21714b393eeSKent Overstreet ret = lockrestart_do(trans, snapshot_lookup(trans, id, &v)); 21814b393eeSKent Overstreet if (ret == -ENOENT) 21914b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent parent %u", 22014b393eeSKent Overstreet s.k->p.offset, id); 22114b393eeSKent Overstreet if (ret) 22214b393eeSKent Overstreet return ret; 22314b393eeSKent Overstreet 22414b393eeSKent Overstreet if (le32_to_cpu(v.children[0]) != s.k->p.offset && 22514b393eeSKent Overstreet le32_to_cpu(v.children[1]) != s.k->p.offset) { 22614b393eeSKent Overstreet bch_err(trans->c, "snapshot parent %u missing pointer to child %llu", 22714b393eeSKent Overstreet id, s.k->p.offset); 22814b393eeSKent Overstreet return -EINVAL; 22914b393eeSKent Overstreet } 23014b393eeSKent Overstreet } 23114b393eeSKent Overstreet 23214b393eeSKent Overstreet for (i = 0; i < 2 && s.v->children[i]; i++) { 23314b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 23414b393eeSKent Overstreet 23514b393eeSKent Overstreet ret = lockrestart_do(trans, snapshot_lookup(trans, id, &v)); 23614b393eeSKent Overstreet if (ret == -ENOENT) 23714b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent child %u", 23814b393eeSKent Overstreet s.k->p.offset, id); 23914b393eeSKent Overstreet if (ret) 24014b393eeSKent Overstreet return ret; 24114b393eeSKent Overstreet 24214b393eeSKent Overstreet if (le32_to_cpu(v.parent) != s.k->p.offset) { 24314b393eeSKent Overstreet bch_err(trans->c, "snapshot child %u has wrong parent (got %u should be %llu)", 24414b393eeSKent Overstreet id, le32_to_cpu(v.parent), s.k->p.offset); 24514b393eeSKent Overstreet return -EINVAL; 24614b393eeSKent Overstreet } 24714b393eeSKent Overstreet } 24814b393eeSKent Overstreet 24914b393eeSKent Overstreet return 0; 25014b393eeSKent Overstreet } 25114b393eeSKent Overstreet 25214b393eeSKent Overstreet int bch2_fs_snapshots_check(struct bch_fs *c) 25314b393eeSKent Overstreet { 25414b393eeSKent Overstreet struct btree_trans trans; 25514b393eeSKent Overstreet struct btree_iter iter; 25614b393eeSKent Overstreet struct bkey_s_c k; 25714b393eeSKent Overstreet struct bch_snapshot s; 25814b393eeSKent Overstreet unsigned id; 25914b393eeSKent Overstreet int ret; 26014b393eeSKent Overstreet 26114b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 26214b393eeSKent Overstreet 26314b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 26414b393eeSKent Overstreet POS_MIN, 0, k, ret) { 26514b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 26614b393eeSKent Overstreet continue; 26714b393eeSKent Overstreet 26814b393eeSKent Overstreet ret = bch2_snapshot_check(&trans, bkey_s_c_to_snapshot(k)); 26914b393eeSKent Overstreet if (ret) 27014b393eeSKent Overstreet break; 27114b393eeSKent Overstreet } 27214b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 27314b393eeSKent Overstreet 27414b393eeSKent Overstreet if (ret) { 27514b393eeSKent Overstreet bch_err(c, "error %i checking snapshots", ret); 27614b393eeSKent Overstreet goto err; 27714b393eeSKent Overstreet } 27814b393eeSKent Overstreet 27914b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_subvolumes, 28014b393eeSKent Overstreet POS_MIN, 0, k, ret) { 28114b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) 28214b393eeSKent Overstreet continue; 28314b393eeSKent Overstreet again_2: 28414b393eeSKent Overstreet id = le32_to_cpu(bkey_s_c_to_subvolume(k).v->snapshot); 28514b393eeSKent Overstreet ret = snapshot_lookup(&trans, id, &s); 28614b393eeSKent Overstreet 28714b393eeSKent Overstreet if (ret == -EINTR) { 28814b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 28914b393eeSKent Overstreet goto again_2; 29014b393eeSKent Overstreet } else if (ret == -ENOENT) 29114b393eeSKent Overstreet bch_err(c, "subvolume %llu points to nonexistent snapshot %u", 29214b393eeSKent Overstreet k.k->p.offset, id); 29314b393eeSKent Overstreet else if (ret) 29414b393eeSKent Overstreet break; 29514b393eeSKent Overstreet } 29614b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 29714b393eeSKent Overstreet err: 29814b393eeSKent Overstreet bch2_trans_exit(&trans); 29914b393eeSKent Overstreet return ret; 30014b393eeSKent Overstreet } 30114b393eeSKent Overstreet 30214b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c) 30314b393eeSKent Overstreet { 30414b393eeSKent Overstreet genradix_free(&c->snapshots); 30514b393eeSKent Overstreet } 30614b393eeSKent Overstreet 30714b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c) 30814b393eeSKent Overstreet { 30914b393eeSKent Overstreet struct btree_trans trans; 31014b393eeSKent Overstreet struct btree_iter iter; 31114b393eeSKent Overstreet struct bkey_s_c k; 31214b393eeSKent Overstreet bool have_deleted = false; 31314b393eeSKent Overstreet int ret = 0; 31414b393eeSKent Overstreet 31514b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 31614b393eeSKent Overstreet 31714b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 31814b393eeSKent Overstreet POS_MIN, 0, k, ret) { 31914b393eeSKent Overstreet if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0) 32014b393eeSKent Overstreet break; 32114b393eeSKent Overstreet 32214b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 32314b393eeSKent Overstreet bch_err(c, "found wrong key type %u in snapshot node table", 32414b393eeSKent Overstreet k.k->type); 32514b393eeSKent Overstreet continue; 32614b393eeSKent Overstreet } 32714b393eeSKent Overstreet 32814b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 32914b393eeSKent Overstreet have_deleted = true; 33014b393eeSKent Overstreet 331904823deSKent Overstreet ret = bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0); 33214b393eeSKent Overstreet if (ret) 33314b393eeSKent Overstreet break; 33414b393eeSKent Overstreet } 33514b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 33614b393eeSKent Overstreet 33714b393eeSKent Overstreet if (ret) 33814b393eeSKent Overstreet goto err; 33914b393eeSKent Overstreet 34014b393eeSKent Overstreet ret = bch2_snapshots_set_equiv(&trans); 34114b393eeSKent Overstreet if (ret) 34214b393eeSKent Overstreet goto err; 34314b393eeSKent Overstreet err: 34414b393eeSKent Overstreet bch2_trans_exit(&trans); 34514b393eeSKent Overstreet 34614b393eeSKent Overstreet if (!ret && have_deleted) { 34714b393eeSKent Overstreet bch_info(c, "restarting deletion of dead snapshots"); 34814b393eeSKent Overstreet if (c->opts.fsck) { 34914b393eeSKent Overstreet bch2_delete_dead_snapshots_work(&c->snapshot_delete_work); 35014b393eeSKent Overstreet } else { 35114b393eeSKent Overstreet bch2_delete_dead_snapshots(c); 35214b393eeSKent Overstreet } 35314b393eeSKent Overstreet } 35414b393eeSKent Overstreet 35514b393eeSKent Overstreet return ret; 35614b393eeSKent Overstreet } 35714b393eeSKent Overstreet 35814b393eeSKent Overstreet /* 35914b393eeSKent Overstreet * Mark a snapshot as deleted, for future cleanup: 36014b393eeSKent Overstreet */ 36114b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id) 36214b393eeSKent Overstreet { 36314b393eeSKent Overstreet struct btree_iter iter; 36414b393eeSKent Overstreet struct bkey_s_c k; 36514b393eeSKent Overstreet struct bkey_i_snapshot *s; 36614b393eeSKent Overstreet int ret = 0; 36714b393eeSKent Overstreet 36814b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 36914b393eeSKent Overstreet BTREE_ITER_INTENT); 37014b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 37114b393eeSKent Overstreet ret = bkey_err(k); 37214b393eeSKent Overstreet if (ret) 37314b393eeSKent Overstreet goto err; 37414b393eeSKent Overstreet 37514b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 37614b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 37714b393eeSKent Overstreet ret = -ENOENT; 37814b393eeSKent Overstreet goto err; 37914b393eeSKent Overstreet } 38014b393eeSKent Overstreet 38114b393eeSKent Overstreet /* already deleted? */ 38214b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 38314b393eeSKent Overstreet goto err; 38414b393eeSKent Overstreet 38514b393eeSKent Overstreet s = bch2_trans_kmalloc(trans, sizeof(*s)); 38614b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(s); 38714b393eeSKent Overstreet if (ret) 38814b393eeSKent Overstreet goto err; 38914b393eeSKent Overstreet 39014b393eeSKent Overstreet bkey_reassemble(&s->k_i, k); 39114b393eeSKent Overstreet SET_BCH_SNAPSHOT_DELETED(&s->v, true); 392*416cc426SKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&s->v, false); 393*416cc426SKent Overstreet s->v.subvol = 0; 394*416cc426SKent Overstreet 39514b393eeSKent Overstreet ret = bch2_trans_update(trans, &iter, &s->k_i, 0); 39614b393eeSKent Overstreet if (ret) 39714b393eeSKent Overstreet goto err; 39814b393eeSKent Overstreet err: 39914b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 40014b393eeSKent Overstreet return ret; 40114b393eeSKent Overstreet } 40214b393eeSKent Overstreet 40314b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) 40414b393eeSKent Overstreet { 40514b393eeSKent Overstreet struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; 40614b393eeSKent Overstreet struct bkey_s_c k; 40714b393eeSKent Overstreet struct bkey_s_c_snapshot s; 40814b393eeSKent Overstreet struct bkey_i_snapshot *parent; 40914b393eeSKent Overstreet u32 parent_id; 41014b393eeSKent Overstreet unsigned i; 41114b393eeSKent Overstreet int ret = 0; 41214b393eeSKent Overstreet 41314b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 41414b393eeSKent Overstreet BTREE_ITER_INTENT); 41514b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 41614b393eeSKent Overstreet ret = bkey_err(k); 41714b393eeSKent Overstreet if (ret) 41814b393eeSKent Overstreet goto err; 41914b393eeSKent Overstreet 42014b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 42114b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 42214b393eeSKent Overstreet ret = -ENOENT; 42314b393eeSKent Overstreet goto err; 42414b393eeSKent Overstreet } 42514b393eeSKent Overstreet 42614b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 42714b393eeSKent Overstreet 42814b393eeSKent Overstreet BUG_ON(!BCH_SNAPSHOT_DELETED(s.v)); 42914b393eeSKent Overstreet parent_id = le32_to_cpu(s.v->parent); 43014b393eeSKent Overstreet 43114b393eeSKent Overstreet if (parent_id) { 43214b393eeSKent Overstreet bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots, 43314b393eeSKent Overstreet POS(0, parent_id), 43414b393eeSKent Overstreet BTREE_ITER_INTENT); 43514b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&p_iter); 43614b393eeSKent Overstreet ret = bkey_err(k); 43714b393eeSKent Overstreet if (ret) 43814b393eeSKent Overstreet goto err; 43914b393eeSKent Overstreet 44014b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 44114b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id); 44214b393eeSKent Overstreet ret = -ENOENT; 44314b393eeSKent Overstreet goto err; 44414b393eeSKent Overstreet } 44514b393eeSKent Overstreet 44614b393eeSKent Overstreet parent = bch2_trans_kmalloc(trans, sizeof(*parent)); 44714b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(parent); 44814b393eeSKent Overstreet if (ret) 44914b393eeSKent Overstreet goto err; 45014b393eeSKent Overstreet 45114b393eeSKent Overstreet bkey_reassemble(&parent->k_i, k); 45214b393eeSKent Overstreet 45314b393eeSKent Overstreet for (i = 0; i < 2; i++) 45414b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[i]) == id) 45514b393eeSKent Overstreet break; 45614b393eeSKent Overstreet 45714b393eeSKent Overstreet if (i == 2) 45814b393eeSKent Overstreet bch_err(trans->c, "snapshot %u missing child pointer to %u", 45914b393eeSKent Overstreet parent_id, id); 46014b393eeSKent Overstreet else 46114b393eeSKent Overstreet parent->v.children[i] = 0; 46214b393eeSKent Overstreet 46314b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[0]) < 46414b393eeSKent Overstreet le32_to_cpu(parent->v.children[1])) 46514b393eeSKent Overstreet swap(parent->v.children[0], 46614b393eeSKent Overstreet parent->v.children[1]); 46714b393eeSKent Overstreet 46814b393eeSKent Overstreet ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0); 46914b393eeSKent Overstreet if (ret) 47014b393eeSKent Overstreet goto err; 47114b393eeSKent Overstreet } 47214b393eeSKent Overstreet 47314b393eeSKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 47414b393eeSKent Overstreet err: 47514b393eeSKent Overstreet bch2_trans_iter_exit(trans, &p_iter); 47614b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 47714b393eeSKent Overstreet return ret; 47814b393eeSKent Overstreet } 47914b393eeSKent Overstreet 4807f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, 48114b393eeSKent Overstreet u32 *new_snapids, 48214b393eeSKent Overstreet u32 *snapshot_subvols, 48314b393eeSKent Overstreet unsigned nr_snapids) 48414b393eeSKent Overstreet { 48514b393eeSKent Overstreet struct btree_iter iter; 48614b393eeSKent Overstreet struct bkey_i_snapshot *n; 48714b393eeSKent Overstreet struct bkey_s_c k; 48814b393eeSKent Overstreet unsigned i; 48914b393eeSKent Overstreet int ret = 0; 49014b393eeSKent Overstreet 49114b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, 49214b393eeSKent Overstreet POS_MIN, BTREE_ITER_INTENT); 49314b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 49414b393eeSKent Overstreet ret = bkey_err(k); 49514b393eeSKent Overstreet if (ret) 49614b393eeSKent Overstreet goto err; 49714b393eeSKent Overstreet 49814b393eeSKent Overstreet for (i = 0; i < nr_snapids; i++) { 49914b393eeSKent Overstreet k = bch2_btree_iter_prev_slot(&iter); 50014b393eeSKent Overstreet ret = bkey_err(k); 50114b393eeSKent Overstreet if (ret) 50214b393eeSKent Overstreet goto err; 50314b393eeSKent Overstreet 50414b393eeSKent Overstreet if (!k.k || !k.k->p.offset) { 50514b393eeSKent Overstreet ret = -ENOSPC; 50614b393eeSKent Overstreet goto err; 50714b393eeSKent Overstreet } 50814b393eeSKent Overstreet 50914b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 51014b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 51114b393eeSKent Overstreet if (ret) 51294a3e1a6SKent Overstreet goto err; 51314b393eeSKent Overstreet 51414b393eeSKent Overstreet bkey_snapshot_init(&n->k_i); 51514b393eeSKent Overstreet n->k.p = iter.pos; 51614b393eeSKent Overstreet n->v.flags = 0; 51714b393eeSKent Overstreet n->v.parent = cpu_to_le32(parent); 51814b393eeSKent Overstreet n->v.subvol = cpu_to_le32(snapshot_subvols[i]); 51914b393eeSKent Overstreet n->v.pad = 0; 52014b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, true); 52114b393eeSKent Overstreet 52294a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0) ?: 52394a3e1a6SKent Overstreet bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); 52414b393eeSKent Overstreet if (ret) 52594a3e1a6SKent Overstreet goto err; 52614b393eeSKent Overstreet 52714b393eeSKent Overstreet new_snapids[i] = iter.pos.offset; 52814b393eeSKent Overstreet } 52914b393eeSKent Overstreet 53014b393eeSKent Overstreet if (parent) { 53114b393eeSKent Overstreet bch2_btree_iter_set_pos(&iter, POS(0, parent)); 53214b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 53314b393eeSKent Overstreet ret = bkey_err(k); 53414b393eeSKent Overstreet if (ret) 53514b393eeSKent Overstreet goto err; 53614b393eeSKent Overstreet 53714b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 53814b393eeSKent Overstreet bch_err(trans->c, "snapshot %u not found", parent); 53914b393eeSKent Overstreet ret = -ENOENT; 54014b393eeSKent Overstreet goto err; 54114b393eeSKent Overstreet } 54214b393eeSKent Overstreet 54314b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 54414b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 54514b393eeSKent Overstreet if (ret) 546c4ecf802SKent Overstreet goto err; 54714b393eeSKent Overstreet 54814b393eeSKent Overstreet bkey_reassemble(&n->k_i, k); 54914b393eeSKent Overstreet 55014b393eeSKent Overstreet if (n->v.children[0] || n->v.children[1]) { 55114b393eeSKent Overstreet bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children"); 55214b393eeSKent Overstreet ret = -EINVAL; 55314b393eeSKent Overstreet goto err; 55414b393eeSKent Overstreet } 55514b393eeSKent Overstreet 55614b393eeSKent Overstreet n->v.children[0] = cpu_to_le32(new_snapids[0]); 55714b393eeSKent Overstreet n->v.children[1] = cpu_to_le32(new_snapids[1]); 55814b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, false); 55994a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 56094a3e1a6SKent Overstreet if (ret) 56194a3e1a6SKent Overstreet goto err; 56214b393eeSKent Overstreet } 56314b393eeSKent Overstreet err: 56414b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 56514b393eeSKent Overstreet return ret; 56614b393eeSKent Overstreet } 56714b393eeSKent Overstreet 56891d961baSKent Overstreet static int snapshot_id_add(snapshot_id_list *s, u32 id) 56914b393eeSKent Overstreet { 57014b393eeSKent Overstreet BUG_ON(snapshot_list_has_id(s, id)); 57114b393eeSKent Overstreet 57291d961baSKent Overstreet return darray_push(s, id); 57314b393eeSKent Overstreet } 57414b393eeSKent Overstreet 57514b393eeSKent Overstreet static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans, 57691d961baSKent Overstreet snapshot_id_list *deleted, 57714b393eeSKent Overstreet enum btree_id btree_id) 57814b393eeSKent Overstreet { 57914b393eeSKent Overstreet struct bch_fs *c = trans->c; 58014b393eeSKent Overstreet struct btree_iter iter; 58114b393eeSKent Overstreet struct bkey_s_c k; 58291d961baSKent Overstreet snapshot_id_list equiv_seen = { 0 }; 58314b393eeSKent Overstreet struct bpos last_pos = POS_MIN; 58414b393eeSKent Overstreet int ret = 0; 58514b393eeSKent Overstreet 58614b393eeSKent Overstreet /* 58714b393eeSKent Overstreet * XXX: We should also delete whiteouts that no longer overwrite 58814b393eeSKent Overstreet * anything 58914b393eeSKent Overstreet */ 59014b393eeSKent Overstreet 59114b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, btree_id, POS_MIN, 59214b393eeSKent Overstreet BTREE_ITER_INTENT| 59314b393eeSKent Overstreet BTREE_ITER_PREFETCH| 59414b393eeSKent Overstreet BTREE_ITER_NOT_EXTENTS| 59514b393eeSKent Overstreet BTREE_ITER_ALL_SNAPSHOTS); 59614b393eeSKent Overstreet 59714b393eeSKent Overstreet while ((bch2_trans_begin(trans), 59814b393eeSKent Overstreet (k = bch2_btree_iter_peek(&iter)).k) && 59914b393eeSKent Overstreet !(ret = bkey_err(k))) { 60014b393eeSKent Overstreet u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv; 60114b393eeSKent Overstreet 60214b393eeSKent Overstreet if (bkey_cmp(k.k->p, last_pos)) 60314b393eeSKent Overstreet equiv_seen.nr = 0; 60414b393eeSKent Overstreet last_pos = k.k->p; 60514b393eeSKent Overstreet 60614b393eeSKent Overstreet if (snapshot_list_has_id(deleted, k.k->p.snapshot) || 60714b393eeSKent Overstreet snapshot_list_has_id(&equiv_seen, equiv)) { 60814b393eeSKent Overstreet if (btree_id == BTREE_ID_inodes && 60914b393eeSKent Overstreet bch2_btree_key_cache_flush(trans, btree_id, iter.pos)) 61014b393eeSKent Overstreet continue; 61114b393eeSKent Overstreet 612e68914caSKent Overstreet ret = commit_do(trans, NULL, NULL, 61314b393eeSKent Overstreet BTREE_INSERT_NOFAIL, 61414b393eeSKent Overstreet bch2_btree_iter_traverse(&iter) ?: 61514b393eeSKent Overstreet bch2_btree_delete_at(trans, &iter, 61614b393eeSKent Overstreet BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE)); 61714b393eeSKent Overstreet if (ret) 61814b393eeSKent Overstreet break; 61914b393eeSKent Overstreet } else { 62014b393eeSKent Overstreet ret = snapshot_id_add(&equiv_seen, equiv); 62114b393eeSKent Overstreet if (ret) 62214b393eeSKent Overstreet break; 62314b393eeSKent Overstreet } 62414b393eeSKent Overstreet 62514b393eeSKent Overstreet bch2_btree_iter_advance(&iter); 62614b393eeSKent Overstreet } 62714b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 62814b393eeSKent Overstreet 62991d961baSKent Overstreet darray_exit(&equiv_seen); 63014b393eeSKent Overstreet 63114b393eeSKent Overstreet return ret; 63214b393eeSKent Overstreet } 63314b393eeSKent Overstreet 63414b393eeSKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work) 63514b393eeSKent Overstreet { 63614b393eeSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work); 63714b393eeSKent Overstreet struct btree_trans trans; 63814b393eeSKent Overstreet struct btree_iter iter; 63914b393eeSKent Overstreet struct bkey_s_c k; 64014b393eeSKent Overstreet struct bkey_s_c_snapshot snap; 64191d961baSKent Overstreet snapshot_id_list deleted = { 0 }; 64214b393eeSKent Overstreet u32 i, id, children[2]; 64314b393eeSKent Overstreet int ret = 0; 64414b393eeSKent Overstreet 64514b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 64614b393eeSKent Overstreet 64714b393eeSKent Overstreet /* 64814b393eeSKent Overstreet * For every snapshot node: If we have no live children and it's not 64914b393eeSKent Overstreet * pointed to by a subvolume, delete it: 65014b393eeSKent Overstreet */ 65114b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 65214b393eeSKent Overstreet POS_MIN, 0, k, ret) { 65314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 65414b393eeSKent Overstreet continue; 65514b393eeSKent Overstreet 65614b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 65714b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v) || 65814b393eeSKent Overstreet BCH_SNAPSHOT_SUBVOL(snap.v)) 65914b393eeSKent Overstreet continue; 66014b393eeSKent Overstreet 66114b393eeSKent Overstreet children[0] = le32_to_cpu(snap.v->children[0]); 66214b393eeSKent Overstreet children[1] = le32_to_cpu(snap.v->children[1]); 66314b393eeSKent Overstreet 66414b393eeSKent Overstreet ret = snapshot_live(&trans, children[0]) ?: 66514b393eeSKent Overstreet snapshot_live(&trans, children[1]); 66614b393eeSKent Overstreet if (ret < 0) 66714b393eeSKent Overstreet break; 66814b393eeSKent Overstreet if (ret) 66914b393eeSKent Overstreet continue; 67014b393eeSKent Overstreet 671e68914caSKent Overstreet ret = commit_do(&trans, NULL, NULL, 0, 67214b393eeSKent Overstreet bch2_snapshot_node_set_deleted(&trans, iter.pos.offset)); 67314b393eeSKent Overstreet if (ret) { 67414b393eeSKent Overstreet bch_err(c, "error deleting snapshot %llu: %i", iter.pos.offset, ret); 67514b393eeSKent Overstreet break; 67614b393eeSKent Overstreet } 67714b393eeSKent Overstreet } 67814b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 67914b393eeSKent Overstreet 68014b393eeSKent Overstreet if (ret) { 68114b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 68214b393eeSKent Overstreet goto err; 68314b393eeSKent Overstreet } 68414b393eeSKent Overstreet 68514b393eeSKent Overstreet ret = bch2_snapshots_set_equiv(&trans); 68614b393eeSKent Overstreet if (ret) 68714b393eeSKent Overstreet goto err; 68814b393eeSKent Overstreet 68914b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 69014b393eeSKent Overstreet POS_MIN, 0, k, ret) { 69114b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 69214b393eeSKent Overstreet continue; 69314b393eeSKent Overstreet 69414b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 69514b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v)) { 69614b393eeSKent Overstreet ret = snapshot_id_add(&deleted, k.k->p.offset); 69714b393eeSKent Overstreet if (ret) 69814b393eeSKent Overstreet break; 69914b393eeSKent Overstreet } 70014b393eeSKent Overstreet } 70114b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 70214b393eeSKent Overstreet 70314b393eeSKent Overstreet if (ret) { 70414b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 70514b393eeSKent Overstreet goto err; 70614b393eeSKent Overstreet } 70714b393eeSKent Overstreet 70814b393eeSKent Overstreet for (id = 0; id < BTREE_ID_NR; id++) { 70914b393eeSKent Overstreet if (!btree_type_has_snapshots(id)) 71014b393eeSKent Overstreet continue; 71114b393eeSKent Overstreet 71214b393eeSKent Overstreet ret = bch2_snapshot_delete_keys_btree(&trans, &deleted, id); 71314b393eeSKent Overstreet if (ret) { 71414b393eeSKent Overstreet bch_err(c, "error deleting snapshot keys: %i", ret); 71514b393eeSKent Overstreet goto err; 71614b393eeSKent Overstreet } 71714b393eeSKent Overstreet } 71814b393eeSKent Overstreet 71914b393eeSKent Overstreet for (i = 0; i < deleted.nr; i++) { 720e68914caSKent Overstreet ret = commit_do(&trans, NULL, NULL, 0, 72191d961baSKent Overstreet bch2_snapshot_node_delete(&trans, deleted.data[i])); 72214b393eeSKent Overstreet if (ret) { 72314b393eeSKent Overstreet bch_err(c, "error deleting snapshot %u: %i", 72491d961baSKent Overstreet deleted.data[i], ret); 72514b393eeSKent Overstreet goto err; 72614b393eeSKent Overstreet } 72714b393eeSKent Overstreet } 72814b393eeSKent Overstreet err: 72991d961baSKent Overstreet darray_exit(&deleted); 73014b393eeSKent Overstreet bch2_trans_exit(&trans); 73114b393eeSKent Overstreet percpu_ref_put(&c->writes); 73214b393eeSKent Overstreet } 73314b393eeSKent Overstreet 73414b393eeSKent Overstreet static void bch2_delete_dead_snapshots(struct bch_fs *c) 73514b393eeSKent Overstreet { 736a3d7afa5SKent Overstreet if (unlikely(!percpu_ref_tryget_live(&c->writes))) 73714b393eeSKent Overstreet return; 73814b393eeSKent Overstreet 73914b393eeSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_delete_work)) 74014b393eeSKent Overstreet percpu_ref_put(&c->writes); 74114b393eeSKent Overstreet } 74214b393eeSKent Overstreet 74314b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, 74414b393eeSKent Overstreet struct btree_trans_commit_hook *h) 74514b393eeSKent Overstreet { 74614b393eeSKent Overstreet bch2_delete_dead_snapshots(trans->c); 74714b393eeSKent Overstreet return 0; 74814b393eeSKent Overstreet } 74914b393eeSKent Overstreet 75014b393eeSKent Overstreet /* Subvolumes: */ 75114b393eeSKent Overstreet 752f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, 753275c8426SKent Overstreet int rw, struct printbuf *err) 75414b393eeSKent Overstreet { 755f0ac7df2SKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 || 756f0ac7df2SKent Overstreet bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) { 757401ec4dbSKent Overstreet prt_printf(err, "invalid pos"); 758f0ac7df2SKent Overstreet return -EINVAL; 759f0ac7df2SKent Overstreet } 76014b393eeSKent Overstreet 761f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) { 762401ec4dbSKent Overstreet prt_printf(err, "incorrect value size (%zu != %zu)", 763f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_subvolume)); 764f0ac7df2SKent Overstreet return -EINVAL; 765f0ac7df2SKent Overstreet } 76614b393eeSKent Overstreet 767f0ac7df2SKent Overstreet return 0; 76814b393eeSKent Overstreet } 76914b393eeSKent Overstreet 77014b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, 77114b393eeSKent Overstreet struct bkey_s_c k) 77214b393eeSKent Overstreet { 77314b393eeSKent Overstreet struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k); 77414b393eeSKent Overstreet 775401ec4dbSKent Overstreet prt_printf(out, "root %llu snapshot id %u", 77614b393eeSKent Overstreet le64_to_cpu(s.v->inode), 77714b393eeSKent Overstreet le32_to_cpu(s.v->snapshot)); 77814b393eeSKent Overstreet } 77914b393eeSKent Overstreet 78097996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, 78197996ddfSKent Overstreet bool inconsistent_if_not_found, 78297996ddfSKent Overstreet int iter_flags, 78397996ddfSKent Overstreet struct bch_subvolume *s) 78414b393eeSKent Overstreet { 78514b393eeSKent Overstreet struct btree_iter iter; 78614b393eeSKent Overstreet struct bkey_s_c k; 78714b393eeSKent Overstreet int ret; 78814b393eeSKent Overstreet 78997996ddfSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol), 79097996ddfSKent Overstreet iter_flags); 79114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 79297996ddfSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT; 79314b393eeSKent Overstreet 79497996ddfSKent Overstreet if (ret == -ENOENT && inconsistent_if_not_found) 79514b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol); 79697996ddfSKent Overstreet if (!ret) 79797996ddfSKent Overstreet *s = *bkey_s_c_to_subvolume(k).v; 79897996ddfSKent Overstreet 79997996ddfSKent Overstreet bch2_trans_iter_exit(trans, &iter); 80097996ddfSKent Overstreet return ret; 80114b393eeSKent Overstreet } 80214b393eeSKent Overstreet 8039ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot, 8049ca4853bSKent Overstreet struct bch_subvolume *subvol) 8059ca4853bSKent Overstreet { 8069ca4853bSKent Overstreet struct bch_snapshot snap; 8079ca4853bSKent Overstreet 8089ca4853bSKent Overstreet return snapshot_lookup(trans, snapshot, &snap) ?: 8099ca4853bSKent Overstreet bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol); 8109ca4853bSKent Overstreet } 8119ca4853bSKent Overstreet 81297996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol, 81397996ddfSKent Overstreet u32 *snapid) 81497996ddfSKent Overstreet { 81597996ddfSKent Overstreet struct bch_subvolume s; 81697996ddfSKent Overstreet int ret; 81797996ddfSKent Overstreet 81897996ddfSKent Overstreet ret = bch2_subvolume_get(trans, subvol, true, 81997996ddfSKent Overstreet BTREE_ITER_CACHED| 82097996ddfSKent Overstreet BTREE_ITER_WITH_UPDATES, 82197996ddfSKent Overstreet &s); 82297996ddfSKent Overstreet 82397996ddfSKent Overstreet *snapid = le32_to_cpu(s.snapshot); 82414b393eeSKent Overstreet return ret; 82514b393eeSKent Overstreet } 82614b393eeSKent Overstreet 8272027875bSKent Overstreet /* 8282027875bSKent Overstreet * Delete subvolume, mark snapshot ID as deleted, queue up snapshot 8292027875bSKent Overstreet * deletion/cleanup: 8302027875bSKent Overstreet */ 8312027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid) 83214b393eeSKent Overstreet { 83314b393eeSKent Overstreet struct btree_iter iter; 83414b393eeSKent Overstreet struct bkey_s_c k; 83514b393eeSKent Overstreet struct bkey_s_c_subvolume subvol; 83614b393eeSKent Overstreet struct btree_trans_commit_hook *h; 83714b393eeSKent Overstreet u32 snapid; 83814b393eeSKent Overstreet int ret = 0; 83914b393eeSKent Overstreet 84014b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 84114b393eeSKent Overstreet POS(0, subvolid), 84214b393eeSKent Overstreet BTREE_ITER_CACHED| 84314b393eeSKent Overstreet BTREE_ITER_INTENT); 84414b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 84514b393eeSKent Overstreet ret = bkey_err(k); 84614b393eeSKent Overstreet if (ret) 84714b393eeSKent Overstreet goto err; 84814b393eeSKent Overstreet 84914b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 85014b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 85114b393eeSKent Overstreet ret = -EIO; 85214b393eeSKent Overstreet goto err; 85314b393eeSKent Overstreet } 85414b393eeSKent Overstreet 85514b393eeSKent Overstreet subvol = bkey_s_c_to_subvolume(k); 85614b393eeSKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 85714b393eeSKent Overstreet 858*416cc426SKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 85914b393eeSKent Overstreet if (ret) 86014b393eeSKent Overstreet goto err; 86114b393eeSKent Overstreet 86214b393eeSKent Overstreet ret = bch2_snapshot_node_set_deleted(trans, snapid); 86314b393eeSKent Overstreet 86414b393eeSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 86514b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 86614b393eeSKent Overstreet if (ret) 86714b393eeSKent Overstreet goto err; 86814b393eeSKent Overstreet 86914b393eeSKent Overstreet h->fn = bch2_delete_dead_snapshots_hook; 87014b393eeSKent Overstreet bch2_trans_commit_hook(trans, h); 87114b393eeSKent Overstreet err: 87214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 87314b393eeSKent Overstreet return ret; 87414b393eeSKent Overstreet } 87514b393eeSKent Overstreet 8762027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) 8772027875bSKent Overstreet { 8782027875bSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, 8792027875bSKent Overstreet snapshot_wait_for_pagecache_and_delete_work); 88091d961baSKent Overstreet snapshot_id_list s; 8812027875bSKent Overstreet u32 *id; 8822027875bSKent Overstreet int ret = 0; 8832027875bSKent Overstreet 8842027875bSKent Overstreet while (!ret) { 8852027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 8862027875bSKent Overstreet s = c->snapshots_unlinked; 88791d961baSKent Overstreet darray_init(&c->snapshots_unlinked); 8882027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 8892027875bSKent Overstreet 8902027875bSKent Overstreet if (!s.nr) 8912027875bSKent Overstreet break; 8922027875bSKent Overstreet 8932027875bSKent Overstreet bch2_evict_subvolume_inodes(c, &s); 8942027875bSKent Overstreet 89591d961baSKent Overstreet for (id = s.data; id < s.data + s.nr; id++) { 8962027875bSKent Overstreet ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL, 8972027875bSKent Overstreet bch2_subvolume_delete(&trans, *id)); 8982027875bSKent Overstreet if (ret) { 8992027875bSKent Overstreet bch_err(c, "error %i deleting subvolume %u", ret, *id); 9002027875bSKent Overstreet break; 9012027875bSKent Overstreet } 9022027875bSKent Overstreet } 9032027875bSKent Overstreet 90491d961baSKent Overstreet darray_exit(&s); 9052027875bSKent Overstreet } 9062027875bSKent Overstreet 9072027875bSKent Overstreet percpu_ref_put(&c->writes); 9082027875bSKent Overstreet } 9092027875bSKent Overstreet 9102027875bSKent Overstreet struct subvolume_unlink_hook { 9112027875bSKent Overstreet struct btree_trans_commit_hook h; 9122027875bSKent Overstreet u32 subvol; 9132027875bSKent Overstreet }; 9142027875bSKent Overstreet 9152027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, 9162027875bSKent Overstreet struct btree_trans_commit_hook *_h) 9172027875bSKent Overstreet { 9182027875bSKent Overstreet struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h); 9192027875bSKent Overstreet struct bch_fs *c = trans->c; 9202027875bSKent Overstreet int ret = 0; 9212027875bSKent Overstreet 9222027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9232027875bSKent Overstreet if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol)) 9242027875bSKent Overstreet ret = snapshot_id_add(&c->snapshots_unlinked, h->subvol); 9252027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9262027875bSKent Overstreet 9272027875bSKent Overstreet if (ret) 9282027875bSKent Overstreet return ret; 9292027875bSKent Overstreet 930a3d7afa5SKent Overstreet if (unlikely(!percpu_ref_tryget_live(&c->writes))) 9312027875bSKent Overstreet return -EROFS; 9322027875bSKent Overstreet 9332027875bSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work)) 9342027875bSKent Overstreet percpu_ref_put(&c->writes); 9352027875bSKent Overstreet return 0; 9362027875bSKent Overstreet } 9372027875bSKent Overstreet 9382027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) 9392027875bSKent Overstreet { 9402027875bSKent Overstreet struct btree_iter iter; 9412027875bSKent Overstreet struct bkey_s_c k; 9422027875bSKent Overstreet struct bkey_i_subvolume *n; 9432027875bSKent Overstreet struct subvolume_unlink_hook *h; 9442027875bSKent Overstreet int ret = 0; 9452027875bSKent Overstreet 9462027875bSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 9472027875bSKent Overstreet POS(0, subvolid), 9482027875bSKent Overstreet BTREE_ITER_CACHED| 9492027875bSKent Overstreet BTREE_ITER_INTENT); 9502027875bSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 9512027875bSKent Overstreet ret = bkey_err(k); 9522027875bSKent Overstreet if (ret) 9532027875bSKent Overstreet goto err; 9542027875bSKent Overstreet 9552027875bSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 9562027875bSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 9572027875bSKent Overstreet ret = -EIO; 9582027875bSKent Overstreet goto err; 9592027875bSKent Overstreet } 9602027875bSKent Overstreet 9612027875bSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 9622027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 9632027875bSKent Overstreet if (ret) 9642027875bSKent Overstreet goto err; 9652027875bSKent Overstreet 9662027875bSKent Overstreet bkey_reassemble(&n->k_i, k); 9672027875bSKent Overstreet SET_BCH_SUBVOLUME_UNLINKED(&n->v, true); 9682027875bSKent Overstreet 9692027875bSKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 9702027875bSKent Overstreet if (ret) 9712027875bSKent Overstreet goto err; 9722027875bSKent Overstreet 9732027875bSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 9742027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 9752027875bSKent Overstreet if (ret) 9762027875bSKent Overstreet goto err; 9772027875bSKent Overstreet 9782027875bSKent Overstreet h->h.fn = bch2_subvolume_wait_for_pagecache_and_delete_hook; 9792027875bSKent Overstreet h->subvol = subvolid; 9802027875bSKent Overstreet bch2_trans_commit_hook(trans, &h->h); 9812027875bSKent Overstreet err: 9822027875bSKent Overstreet bch2_trans_iter_exit(trans, &iter); 9832027875bSKent Overstreet return ret; 9842027875bSKent Overstreet } 9852027875bSKent Overstreet 98614b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode, 98714b393eeSKent Overstreet u32 src_subvolid, 98814b393eeSKent Overstreet u32 *new_subvolid, 98914b393eeSKent Overstreet u32 *new_snapshotid, 99014b393eeSKent Overstreet bool ro) 99114b393eeSKent Overstreet { 992ca130b9cSKent Overstreet struct bch_fs *c = trans->c; 99314b393eeSKent Overstreet struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL }; 99414b393eeSKent Overstreet struct bkey_i_subvolume *new_subvol = NULL; 99514b393eeSKent Overstreet struct bkey_i_subvolume *src_subvol = NULL; 99614b393eeSKent Overstreet struct bkey_s_c k; 99714b393eeSKent Overstreet u32 parent = 0, new_nodes[2], snapshot_subvols[2]; 99814b393eeSKent Overstreet int ret = 0; 99914b393eeSKent Overstreet 100014b393eeSKent Overstreet for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN, 100114b393eeSKent Overstreet BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { 100214b393eeSKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) 100314b393eeSKent Overstreet break; 1004ca130b9cSKent Overstreet 1005ca130b9cSKent Overstreet /* 1006ca130b9cSKent Overstreet * bch2_subvolume_delete() doesn't flush the btree key cache - 1007ca130b9cSKent Overstreet * ideally it would but that's tricky 1008ca130b9cSKent Overstreet */ 1009ca130b9cSKent Overstreet if (bkey_deleted(k.k) && 1010ca130b9cSKent Overstreet !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos)) 101114b393eeSKent Overstreet goto found_slot; 101214b393eeSKent Overstreet } 101314b393eeSKent Overstreet 101414b393eeSKent Overstreet if (!ret) 101514b393eeSKent Overstreet ret = -ENOSPC; 101614b393eeSKent Overstreet goto err; 101714b393eeSKent Overstreet found_slot: 101814b393eeSKent Overstreet snapshot_subvols[0] = dst_iter.pos.offset; 101914b393eeSKent Overstreet snapshot_subvols[1] = src_subvolid; 102014b393eeSKent Overstreet 102114b393eeSKent Overstreet if (src_subvolid) { 102214b393eeSKent Overstreet /* Creating a snapshot: */ 102314b393eeSKent Overstreet src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol)); 102414b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(src_subvol); 102514b393eeSKent Overstreet if (ret) 102614b393eeSKent Overstreet goto err; 102714b393eeSKent Overstreet 102814b393eeSKent Overstreet bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes, 102914b393eeSKent Overstreet POS(0, src_subvolid), 103014b393eeSKent Overstreet BTREE_ITER_CACHED| 103114b393eeSKent Overstreet BTREE_ITER_INTENT); 103214b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&src_iter); 103314b393eeSKent Overstreet ret = bkey_err(k); 103414b393eeSKent Overstreet if (ret) 103514b393eeSKent Overstreet goto err; 103614b393eeSKent Overstreet 103714b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 1038ca130b9cSKent Overstreet bch_err(c, "subvolume %u not found", src_subvolid); 103914b393eeSKent Overstreet ret = -ENOENT; 104014b393eeSKent Overstreet goto err; 104114b393eeSKent Overstreet } 104214b393eeSKent Overstreet 104314b393eeSKent Overstreet bkey_reassemble(&src_subvol->k_i, k); 104414b393eeSKent Overstreet parent = le32_to_cpu(src_subvol->v.snapshot); 104514b393eeSKent Overstreet } 104614b393eeSKent Overstreet 104714b393eeSKent Overstreet ret = bch2_snapshot_node_create(trans, parent, new_nodes, 104814b393eeSKent Overstreet snapshot_subvols, 104914b393eeSKent Overstreet src_subvolid ? 2 : 1); 105014b393eeSKent Overstreet if (ret) 105114b393eeSKent Overstreet goto err; 105214b393eeSKent Overstreet 105314b393eeSKent Overstreet if (src_subvolid) { 105414b393eeSKent Overstreet src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]); 105594a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0); 105694a3e1a6SKent Overstreet if (ret) 105794a3e1a6SKent Overstreet goto err; 105814b393eeSKent Overstreet } 105914b393eeSKent Overstreet 106014b393eeSKent Overstreet new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol)); 106114b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(new_subvol); 106214b393eeSKent Overstreet if (ret) 106314b393eeSKent Overstreet goto err; 106414b393eeSKent Overstreet 106514b393eeSKent Overstreet bkey_subvolume_init(&new_subvol->k_i); 106614b393eeSKent Overstreet new_subvol->v.flags = 0; 106714b393eeSKent Overstreet new_subvol->v.snapshot = cpu_to_le32(new_nodes[0]); 106814b393eeSKent Overstreet new_subvol->v.inode = cpu_to_le64(inode); 106914b393eeSKent Overstreet SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro); 107014b393eeSKent Overstreet SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0); 107114b393eeSKent Overstreet new_subvol->k.p = dst_iter.pos; 107294a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0); 107394a3e1a6SKent Overstreet if (ret) 107494a3e1a6SKent Overstreet goto err; 107514b393eeSKent Overstreet 107614b393eeSKent Overstreet *new_subvolid = new_subvol->k.p.offset; 107714b393eeSKent Overstreet *new_snapshotid = new_nodes[0]; 107814b393eeSKent Overstreet err: 107914b393eeSKent Overstreet bch2_trans_iter_exit(trans, &src_iter); 108014b393eeSKent Overstreet bch2_trans_iter_exit(trans, &dst_iter); 108114b393eeSKent Overstreet return ret; 108214b393eeSKent Overstreet } 108314b393eeSKent Overstreet 108414b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c) 108514b393eeSKent Overstreet { 108614b393eeSKent Overstreet INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work); 10872027875bSKent Overstreet INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work, 10882027875bSKent Overstreet bch2_subvolume_wait_for_pagecache_and_delete); 10892027875bSKent Overstreet mutex_init(&c->snapshots_unlinked_lock); 109014b393eeSKent Overstreet return 0; 109114b393eeSKent Overstreet } 1092