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*401ec4dbSKent Overstreet prt_printf(out, "is_subvol %llu deleted %llu parent %u children %u %u 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) { 37*401ec4dbSKent 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)) { 42*401ec4dbSKent 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) { 51*401ec4dbSKent 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])) { 57*401ec4dbSKent 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]) { 63*401ec4dbSKent 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) { 71*401ec4dbSKent 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 19914b393eeSKent Overstreet id = le32_to_cpu(s.v->subvol); 20097996ddfSKent Overstreet ret = lockrestart_do(trans, bch2_subvolume_get(trans, id, 0, false, &subvol)); 20114b393eeSKent Overstreet if (ret == -ENOENT) 20214b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent subvolume %u", 20314b393eeSKent Overstreet s.k->p.offset, id); 20414b393eeSKent Overstreet if (ret) 20514b393eeSKent Overstreet return ret; 20614b393eeSKent Overstreet 20714b393eeSKent Overstreet if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) { 20814b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL", 20914b393eeSKent Overstreet s.k->p.offset); 21014b393eeSKent Overstreet return -EINVAL; 21114b393eeSKent Overstreet } 21214b393eeSKent Overstreet 21314b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 21414b393eeSKent Overstreet if (id) { 21514b393eeSKent Overstreet ret = lockrestart_do(trans, snapshot_lookup(trans, id, &v)); 21614b393eeSKent Overstreet if (ret == -ENOENT) 21714b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent parent %u", 21814b393eeSKent Overstreet s.k->p.offset, id); 21914b393eeSKent Overstreet if (ret) 22014b393eeSKent Overstreet return ret; 22114b393eeSKent Overstreet 22214b393eeSKent Overstreet if (le32_to_cpu(v.children[0]) != s.k->p.offset && 22314b393eeSKent Overstreet le32_to_cpu(v.children[1]) != s.k->p.offset) { 22414b393eeSKent Overstreet bch_err(trans->c, "snapshot parent %u missing pointer to child %llu", 22514b393eeSKent Overstreet id, s.k->p.offset); 22614b393eeSKent Overstreet return -EINVAL; 22714b393eeSKent Overstreet } 22814b393eeSKent Overstreet } 22914b393eeSKent Overstreet 23014b393eeSKent Overstreet for (i = 0; i < 2 && s.v->children[i]; i++) { 23114b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 23214b393eeSKent Overstreet 23314b393eeSKent Overstreet ret = lockrestart_do(trans, snapshot_lookup(trans, id, &v)); 23414b393eeSKent Overstreet if (ret == -ENOENT) 23514b393eeSKent Overstreet bch_err(trans->c, "snapshot node %llu has nonexistent child %u", 23614b393eeSKent Overstreet s.k->p.offset, id); 23714b393eeSKent Overstreet if (ret) 23814b393eeSKent Overstreet return ret; 23914b393eeSKent Overstreet 24014b393eeSKent Overstreet if (le32_to_cpu(v.parent) != s.k->p.offset) { 24114b393eeSKent Overstreet bch_err(trans->c, "snapshot child %u has wrong parent (got %u should be %llu)", 24214b393eeSKent Overstreet id, le32_to_cpu(v.parent), s.k->p.offset); 24314b393eeSKent Overstreet return -EINVAL; 24414b393eeSKent Overstreet } 24514b393eeSKent Overstreet } 24614b393eeSKent Overstreet 24714b393eeSKent Overstreet return 0; 24814b393eeSKent Overstreet } 24914b393eeSKent Overstreet 25014b393eeSKent Overstreet int bch2_fs_snapshots_check(struct bch_fs *c) 25114b393eeSKent Overstreet { 25214b393eeSKent Overstreet struct btree_trans trans; 25314b393eeSKent Overstreet struct btree_iter iter; 25414b393eeSKent Overstreet struct bkey_s_c k; 25514b393eeSKent Overstreet struct bch_snapshot s; 25614b393eeSKent Overstreet unsigned id; 25714b393eeSKent Overstreet int ret; 25814b393eeSKent Overstreet 25914b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 26014b393eeSKent Overstreet 26114b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 26214b393eeSKent Overstreet POS_MIN, 0, k, ret) { 26314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 26414b393eeSKent Overstreet continue; 26514b393eeSKent Overstreet 26614b393eeSKent Overstreet ret = bch2_snapshot_check(&trans, bkey_s_c_to_snapshot(k)); 26714b393eeSKent Overstreet if (ret) 26814b393eeSKent Overstreet break; 26914b393eeSKent Overstreet } 27014b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 27114b393eeSKent Overstreet 27214b393eeSKent Overstreet if (ret) { 27314b393eeSKent Overstreet bch_err(c, "error %i checking snapshots", ret); 27414b393eeSKent Overstreet goto err; 27514b393eeSKent Overstreet } 27614b393eeSKent Overstreet 27714b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_subvolumes, 27814b393eeSKent Overstreet POS_MIN, 0, k, ret) { 27914b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) 28014b393eeSKent Overstreet continue; 28114b393eeSKent Overstreet again_2: 28214b393eeSKent Overstreet id = le32_to_cpu(bkey_s_c_to_subvolume(k).v->snapshot); 28314b393eeSKent Overstreet ret = snapshot_lookup(&trans, id, &s); 28414b393eeSKent Overstreet 28514b393eeSKent Overstreet if (ret == -EINTR) { 28614b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 28714b393eeSKent Overstreet goto again_2; 28814b393eeSKent Overstreet } else if (ret == -ENOENT) 28914b393eeSKent Overstreet bch_err(c, "subvolume %llu points to nonexistent snapshot %u", 29014b393eeSKent Overstreet k.k->p.offset, id); 29114b393eeSKent Overstreet else if (ret) 29214b393eeSKent Overstreet break; 29314b393eeSKent Overstreet } 29414b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 29514b393eeSKent Overstreet err: 29614b393eeSKent Overstreet bch2_trans_exit(&trans); 29714b393eeSKent Overstreet return ret; 29814b393eeSKent Overstreet } 29914b393eeSKent Overstreet 30014b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c) 30114b393eeSKent Overstreet { 30214b393eeSKent Overstreet genradix_free(&c->snapshots); 30314b393eeSKent Overstreet } 30414b393eeSKent Overstreet 30514b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c) 30614b393eeSKent Overstreet { 30714b393eeSKent Overstreet struct btree_trans trans; 30814b393eeSKent Overstreet struct btree_iter iter; 30914b393eeSKent Overstreet struct bkey_s_c k; 31014b393eeSKent Overstreet bool have_deleted = false; 31114b393eeSKent Overstreet int ret = 0; 31214b393eeSKent Overstreet 31314b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 31414b393eeSKent Overstreet 31514b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 31614b393eeSKent Overstreet POS_MIN, 0, k, ret) { 31714b393eeSKent Overstreet if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0) 31814b393eeSKent Overstreet break; 31914b393eeSKent Overstreet 32014b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 32114b393eeSKent Overstreet bch_err(c, "found wrong key type %u in snapshot node table", 32214b393eeSKent Overstreet k.k->type); 32314b393eeSKent Overstreet continue; 32414b393eeSKent Overstreet } 32514b393eeSKent Overstreet 32614b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 32714b393eeSKent Overstreet have_deleted = true; 32814b393eeSKent Overstreet 329904823deSKent Overstreet ret = bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0); 33014b393eeSKent Overstreet if (ret) 33114b393eeSKent Overstreet break; 33214b393eeSKent Overstreet } 33314b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 33414b393eeSKent Overstreet 33514b393eeSKent Overstreet if (ret) 33614b393eeSKent Overstreet goto err; 33714b393eeSKent Overstreet 33814b393eeSKent Overstreet ret = bch2_snapshots_set_equiv(&trans); 33914b393eeSKent Overstreet if (ret) 34014b393eeSKent Overstreet goto err; 34114b393eeSKent Overstreet err: 34214b393eeSKent Overstreet bch2_trans_exit(&trans); 34314b393eeSKent Overstreet 34414b393eeSKent Overstreet if (!ret && have_deleted) { 34514b393eeSKent Overstreet bch_info(c, "restarting deletion of dead snapshots"); 34614b393eeSKent Overstreet if (c->opts.fsck) { 34714b393eeSKent Overstreet bch2_delete_dead_snapshots_work(&c->snapshot_delete_work); 34814b393eeSKent Overstreet } else { 34914b393eeSKent Overstreet bch2_delete_dead_snapshots(c); 35014b393eeSKent Overstreet } 35114b393eeSKent Overstreet } 35214b393eeSKent Overstreet 35314b393eeSKent Overstreet return ret; 35414b393eeSKent Overstreet } 35514b393eeSKent Overstreet 35614b393eeSKent Overstreet /* 35714b393eeSKent Overstreet * Mark a snapshot as deleted, for future cleanup: 35814b393eeSKent Overstreet */ 35914b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id) 36014b393eeSKent Overstreet { 36114b393eeSKent Overstreet struct btree_iter iter; 36214b393eeSKent Overstreet struct bkey_s_c k; 36314b393eeSKent Overstreet struct bkey_i_snapshot *s; 36414b393eeSKent Overstreet int ret = 0; 36514b393eeSKent Overstreet 36614b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 36714b393eeSKent Overstreet BTREE_ITER_INTENT); 36814b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 36914b393eeSKent Overstreet ret = bkey_err(k); 37014b393eeSKent Overstreet if (ret) 37114b393eeSKent Overstreet goto err; 37214b393eeSKent Overstreet 37314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 37414b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 37514b393eeSKent Overstreet ret = -ENOENT; 37614b393eeSKent Overstreet goto err; 37714b393eeSKent Overstreet } 37814b393eeSKent Overstreet 37914b393eeSKent Overstreet /* already deleted? */ 38014b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 38114b393eeSKent Overstreet goto err; 38214b393eeSKent Overstreet 38314b393eeSKent Overstreet s = bch2_trans_kmalloc(trans, sizeof(*s)); 38414b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(s); 38514b393eeSKent Overstreet if (ret) 38614b393eeSKent Overstreet goto err; 38714b393eeSKent Overstreet 38814b393eeSKent Overstreet bkey_reassemble(&s->k_i, k); 38914b393eeSKent Overstreet 39014b393eeSKent Overstreet SET_BCH_SNAPSHOT_DELETED(&s->v, true); 39114b393eeSKent Overstreet ret = bch2_trans_update(trans, &iter, &s->k_i, 0); 39214b393eeSKent Overstreet if (ret) 39314b393eeSKent Overstreet goto err; 39414b393eeSKent Overstreet err: 39514b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 39614b393eeSKent Overstreet return ret; 39714b393eeSKent Overstreet } 39814b393eeSKent Overstreet 39914b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) 40014b393eeSKent Overstreet { 40114b393eeSKent Overstreet struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; 40214b393eeSKent Overstreet struct bkey_s_c k; 40314b393eeSKent Overstreet struct bkey_s_c_snapshot s; 40414b393eeSKent Overstreet struct bkey_i_snapshot *parent; 40514b393eeSKent Overstreet u32 parent_id; 40614b393eeSKent Overstreet unsigned i; 40714b393eeSKent Overstreet int ret = 0; 40814b393eeSKent Overstreet 40914b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 41014b393eeSKent Overstreet BTREE_ITER_INTENT); 41114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 41214b393eeSKent Overstreet ret = bkey_err(k); 41314b393eeSKent Overstreet if (ret) 41414b393eeSKent Overstreet goto err; 41514b393eeSKent Overstreet 41614b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 41714b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 41814b393eeSKent Overstreet ret = -ENOENT; 41914b393eeSKent Overstreet goto err; 42014b393eeSKent Overstreet } 42114b393eeSKent Overstreet 42214b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 42314b393eeSKent Overstreet 42414b393eeSKent Overstreet BUG_ON(!BCH_SNAPSHOT_DELETED(s.v)); 42514b393eeSKent Overstreet parent_id = le32_to_cpu(s.v->parent); 42614b393eeSKent Overstreet 42714b393eeSKent Overstreet if (parent_id) { 42814b393eeSKent Overstreet bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots, 42914b393eeSKent Overstreet POS(0, parent_id), 43014b393eeSKent Overstreet BTREE_ITER_INTENT); 43114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&p_iter); 43214b393eeSKent Overstreet ret = bkey_err(k); 43314b393eeSKent Overstreet if (ret) 43414b393eeSKent Overstreet goto err; 43514b393eeSKent Overstreet 43614b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 43714b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id); 43814b393eeSKent Overstreet ret = -ENOENT; 43914b393eeSKent Overstreet goto err; 44014b393eeSKent Overstreet } 44114b393eeSKent Overstreet 44214b393eeSKent Overstreet parent = bch2_trans_kmalloc(trans, sizeof(*parent)); 44314b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(parent); 44414b393eeSKent Overstreet if (ret) 44514b393eeSKent Overstreet goto err; 44614b393eeSKent Overstreet 44714b393eeSKent Overstreet bkey_reassemble(&parent->k_i, k); 44814b393eeSKent Overstreet 44914b393eeSKent Overstreet for (i = 0; i < 2; i++) 45014b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[i]) == id) 45114b393eeSKent Overstreet break; 45214b393eeSKent Overstreet 45314b393eeSKent Overstreet if (i == 2) 45414b393eeSKent Overstreet bch_err(trans->c, "snapshot %u missing child pointer to %u", 45514b393eeSKent Overstreet parent_id, id); 45614b393eeSKent Overstreet else 45714b393eeSKent Overstreet parent->v.children[i] = 0; 45814b393eeSKent Overstreet 45914b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[0]) < 46014b393eeSKent Overstreet le32_to_cpu(parent->v.children[1])) 46114b393eeSKent Overstreet swap(parent->v.children[0], 46214b393eeSKent Overstreet parent->v.children[1]); 46314b393eeSKent Overstreet 46414b393eeSKent Overstreet ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0); 46514b393eeSKent Overstreet if (ret) 46614b393eeSKent Overstreet goto err; 46714b393eeSKent Overstreet } 46814b393eeSKent Overstreet 46914b393eeSKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 47014b393eeSKent Overstreet err: 47114b393eeSKent Overstreet bch2_trans_iter_exit(trans, &p_iter); 47214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 47314b393eeSKent Overstreet return ret; 47414b393eeSKent Overstreet } 47514b393eeSKent Overstreet 4767f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, 47714b393eeSKent Overstreet u32 *new_snapids, 47814b393eeSKent Overstreet u32 *snapshot_subvols, 47914b393eeSKent Overstreet unsigned nr_snapids) 48014b393eeSKent Overstreet { 48114b393eeSKent Overstreet struct btree_iter iter; 48214b393eeSKent Overstreet struct bkey_i_snapshot *n; 48314b393eeSKent Overstreet struct bkey_s_c k; 48414b393eeSKent Overstreet unsigned i; 48514b393eeSKent Overstreet int ret = 0; 48614b393eeSKent Overstreet 48714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, 48814b393eeSKent Overstreet POS_MIN, BTREE_ITER_INTENT); 48914b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 49014b393eeSKent Overstreet ret = bkey_err(k); 49114b393eeSKent Overstreet if (ret) 49214b393eeSKent Overstreet goto err; 49314b393eeSKent Overstreet 49414b393eeSKent Overstreet for (i = 0; i < nr_snapids; i++) { 49514b393eeSKent Overstreet k = bch2_btree_iter_prev_slot(&iter); 49614b393eeSKent Overstreet ret = bkey_err(k); 49714b393eeSKent Overstreet if (ret) 49814b393eeSKent Overstreet goto err; 49914b393eeSKent Overstreet 50014b393eeSKent Overstreet if (!k.k || !k.k->p.offset) { 50114b393eeSKent Overstreet ret = -ENOSPC; 50214b393eeSKent Overstreet goto err; 50314b393eeSKent Overstreet } 50414b393eeSKent Overstreet 50514b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 50614b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 50714b393eeSKent Overstreet if (ret) 50894a3e1a6SKent Overstreet goto err; 50914b393eeSKent Overstreet 51014b393eeSKent Overstreet bkey_snapshot_init(&n->k_i); 51114b393eeSKent Overstreet n->k.p = iter.pos; 51214b393eeSKent Overstreet n->v.flags = 0; 51314b393eeSKent Overstreet n->v.parent = cpu_to_le32(parent); 51414b393eeSKent Overstreet n->v.subvol = cpu_to_le32(snapshot_subvols[i]); 51514b393eeSKent Overstreet n->v.pad = 0; 51614b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, true); 51714b393eeSKent Overstreet 51894a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0) ?: 51994a3e1a6SKent Overstreet bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); 52014b393eeSKent Overstreet if (ret) 52194a3e1a6SKent Overstreet goto err; 52214b393eeSKent Overstreet 52314b393eeSKent Overstreet new_snapids[i] = iter.pos.offset; 52414b393eeSKent Overstreet } 52514b393eeSKent Overstreet 52614b393eeSKent Overstreet if (parent) { 52714b393eeSKent Overstreet bch2_btree_iter_set_pos(&iter, POS(0, parent)); 52814b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 52914b393eeSKent Overstreet ret = bkey_err(k); 53014b393eeSKent Overstreet if (ret) 53114b393eeSKent Overstreet goto err; 53214b393eeSKent Overstreet 53314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 53414b393eeSKent Overstreet bch_err(trans->c, "snapshot %u not found", parent); 53514b393eeSKent Overstreet ret = -ENOENT; 53614b393eeSKent Overstreet goto err; 53714b393eeSKent Overstreet } 53814b393eeSKent Overstreet 53914b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 54014b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 54114b393eeSKent Overstreet if (ret) 542c4ecf802SKent Overstreet goto err; 54314b393eeSKent Overstreet 54414b393eeSKent Overstreet bkey_reassemble(&n->k_i, k); 54514b393eeSKent Overstreet 54614b393eeSKent Overstreet if (n->v.children[0] || n->v.children[1]) { 54714b393eeSKent Overstreet bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children"); 54814b393eeSKent Overstreet ret = -EINVAL; 54914b393eeSKent Overstreet goto err; 55014b393eeSKent Overstreet } 55114b393eeSKent Overstreet 55214b393eeSKent Overstreet n->v.children[0] = cpu_to_le32(new_snapids[0]); 55314b393eeSKent Overstreet n->v.children[1] = cpu_to_le32(new_snapids[1]); 55414b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, false); 55594a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 55694a3e1a6SKent Overstreet if (ret) 55794a3e1a6SKent Overstreet goto err; 55814b393eeSKent Overstreet } 55914b393eeSKent Overstreet err: 56014b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 56114b393eeSKent Overstreet return ret; 56214b393eeSKent Overstreet } 56314b393eeSKent Overstreet 56491d961baSKent Overstreet static int snapshot_id_add(snapshot_id_list *s, u32 id) 56514b393eeSKent Overstreet { 56614b393eeSKent Overstreet BUG_ON(snapshot_list_has_id(s, id)); 56714b393eeSKent Overstreet 56891d961baSKent Overstreet return darray_push(s, id); 56914b393eeSKent Overstreet } 57014b393eeSKent Overstreet 57114b393eeSKent Overstreet static int bch2_snapshot_delete_keys_btree(struct btree_trans *trans, 57291d961baSKent Overstreet snapshot_id_list *deleted, 57314b393eeSKent Overstreet enum btree_id btree_id) 57414b393eeSKent Overstreet { 57514b393eeSKent Overstreet struct bch_fs *c = trans->c; 57614b393eeSKent Overstreet struct btree_iter iter; 57714b393eeSKent Overstreet struct bkey_s_c k; 57891d961baSKent Overstreet snapshot_id_list equiv_seen = { 0 }; 57914b393eeSKent Overstreet struct bpos last_pos = POS_MIN; 58014b393eeSKent Overstreet int ret = 0; 58114b393eeSKent Overstreet 58214b393eeSKent Overstreet /* 58314b393eeSKent Overstreet * XXX: We should also delete whiteouts that no longer overwrite 58414b393eeSKent Overstreet * anything 58514b393eeSKent Overstreet */ 58614b393eeSKent Overstreet 58714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, btree_id, POS_MIN, 58814b393eeSKent Overstreet BTREE_ITER_INTENT| 58914b393eeSKent Overstreet BTREE_ITER_PREFETCH| 59014b393eeSKent Overstreet BTREE_ITER_NOT_EXTENTS| 59114b393eeSKent Overstreet BTREE_ITER_ALL_SNAPSHOTS); 59214b393eeSKent Overstreet 59314b393eeSKent Overstreet while ((bch2_trans_begin(trans), 59414b393eeSKent Overstreet (k = bch2_btree_iter_peek(&iter)).k) && 59514b393eeSKent Overstreet !(ret = bkey_err(k))) { 59614b393eeSKent Overstreet u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv; 59714b393eeSKent Overstreet 59814b393eeSKent Overstreet if (bkey_cmp(k.k->p, last_pos)) 59914b393eeSKent Overstreet equiv_seen.nr = 0; 60014b393eeSKent Overstreet last_pos = k.k->p; 60114b393eeSKent Overstreet 60214b393eeSKent Overstreet if (snapshot_list_has_id(deleted, k.k->p.snapshot) || 60314b393eeSKent Overstreet snapshot_list_has_id(&equiv_seen, equiv)) { 60414b393eeSKent Overstreet if (btree_id == BTREE_ID_inodes && 60514b393eeSKent Overstreet bch2_btree_key_cache_flush(trans, btree_id, iter.pos)) 60614b393eeSKent Overstreet continue; 60714b393eeSKent Overstreet 60814b393eeSKent Overstreet ret = __bch2_trans_do(trans, NULL, NULL, 60914b393eeSKent Overstreet BTREE_INSERT_NOFAIL, 61014b393eeSKent Overstreet bch2_btree_iter_traverse(&iter) ?: 61114b393eeSKent Overstreet bch2_btree_delete_at(trans, &iter, 61214b393eeSKent Overstreet BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE)); 61314b393eeSKent Overstreet if (ret) 61414b393eeSKent Overstreet break; 61514b393eeSKent Overstreet } else { 61614b393eeSKent Overstreet ret = snapshot_id_add(&equiv_seen, equiv); 61714b393eeSKent Overstreet if (ret) 61814b393eeSKent Overstreet break; 61914b393eeSKent Overstreet } 62014b393eeSKent Overstreet 62114b393eeSKent Overstreet bch2_btree_iter_advance(&iter); 62214b393eeSKent Overstreet } 62314b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 62414b393eeSKent Overstreet 62591d961baSKent Overstreet darray_exit(&equiv_seen); 62614b393eeSKent Overstreet 62714b393eeSKent Overstreet return ret; 62814b393eeSKent Overstreet } 62914b393eeSKent Overstreet 63014b393eeSKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work) 63114b393eeSKent Overstreet { 63214b393eeSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work); 63314b393eeSKent Overstreet struct btree_trans trans; 63414b393eeSKent Overstreet struct btree_iter iter; 63514b393eeSKent Overstreet struct bkey_s_c k; 63614b393eeSKent Overstreet struct bkey_s_c_snapshot snap; 63791d961baSKent Overstreet snapshot_id_list deleted = { 0 }; 63814b393eeSKent Overstreet u32 i, id, children[2]; 63914b393eeSKent Overstreet int ret = 0; 64014b393eeSKent Overstreet 64114b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 64214b393eeSKent Overstreet 64314b393eeSKent Overstreet /* 64414b393eeSKent Overstreet * For every snapshot node: If we have no live children and it's not 64514b393eeSKent Overstreet * pointed to by a subvolume, delete it: 64614b393eeSKent Overstreet */ 64714b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 64814b393eeSKent Overstreet POS_MIN, 0, k, ret) { 64914b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 65014b393eeSKent Overstreet continue; 65114b393eeSKent Overstreet 65214b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 65314b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v) || 65414b393eeSKent Overstreet BCH_SNAPSHOT_SUBVOL(snap.v)) 65514b393eeSKent Overstreet continue; 65614b393eeSKent Overstreet 65714b393eeSKent Overstreet children[0] = le32_to_cpu(snap.v->children[0]); 65814b393eeSKent Overstreet children[1] = le32_to_cpu(snap.v->children[1]); 65914b393eeSKent Overstreet 66014b393eeSKent Overstreet ret = snapshot_live(&trans, children[0]) ?: 66114b393eeSKent Overstreet snapshot_live(&trans, children[1]); 66214b393eeSKent Overstreet if (ret < 0) 66314b393eeSKent Overstreet break; 66414b393eeSKent Overstreet if (ret) 66514b393eeSKent Overstreet continue; 66614b393eeSKent Overstreet 66714b393eeSKent Overstreet ret = __bch2_trans_do(&trans, NULL, NULL, 0, 66814b393eeSKent Overstreet bch2_snapshot_node_set_deleted(&trans, iter.pos.offset)); 66914b393eeSKent Overstreet if (ret) { 67014b393eeSKent Overstreet bch_err(c, "error deleting snapshot %llu: %i", iter.pos.offset, ret); 67114b393eeSKent Overstreet break; 67214b393eeSKent Overstreet } 67314b393eeSKent Overstreet } 67414b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 67514b393eeSKent Overstreet 67614b393eeSKent Overstreet if (ret) { 67714b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 67814b393eeSKent Overstreet goto err; 67914b393eeSKent Overstreet } 68014b393eeSKent Overstreet 68114b393eeSKent Overstreet ret = bch2_snapshots_set_equiv(&trans); 68214b393eeSKent Overstreet if (ret) 68314b393eeSKent Overstreet goto err; 68414b393eeSKent Overstreet 68514b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 68614b393eeSKent Overstreet POS_MIN, 0, k, ret) { 68714b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 68814b393eeSKent Overstreet continue; 68914b393eeSKent Overstreet 69014b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 69114b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v)) { 69214b393eeSKent Overstreet ret = snapshot_id_add(&deleted, k.k->p.offset); 69314b393eeSKent Overstreet if (ret) 69414b393eeSKent Overstreet break; 69514b393eeSKent Overstreet } 69614b393eeSKent Overstreet } 69714b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 69814b393eeSKent Overstreet 69914b393eeSKent Overstreet if (ret) { 70014b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 70114b393eeSKent Overstreet goto err; 70214b393eeSKent Overstreet } 70314b393eeSKent Overstreet 70414b393eeSKent Overstreet for (id = 0; id < BTREE_ID_NR; id++) { 70514b393eeSKent Overstreet if (!btree_type_has_snapshots(id)) 70614b393eeSKent Overstreet continue; 70714b393eeSKent Overstreet 70814b393eeSKent Overstreet ret = bch2_snapshot_delete_keys_btree(&trans, &deleted, id); 70914b393eeSKent Overstreet if (ret) { 71014b393eeSKent Overstreet bch_err(c, "error deleting snapshot keys: %i", ret); 71114b393eeSKent Overstreet goto err; 71214b393eeSKent Overstreet } 71314b393eeSKent Overstreet } 71414b393eeSKent Overstreet 71514b393eeSKent Overstreet for (i = 0; i < deleted.nr; i++) { 71614b393eeSKent Overstreet ret = __bch2_trans_do(&trans, NULL, NULL, 0, 71791d961baSKent Overstreet bch2_snapshot_node_delete(&trans, deleted.data[i])); 71814b393eeSKent Overstreet if (ret) { 71914b393eeSKent Overstreet bch_err(c, "error deleting snapshot %u: %i", 72091d961baSKent Overstreet deleted.data[i], ret); 72114b393eeSKent Overstreet goto err; 72214b393eeSKent Overstreet } 72314b393eeSKent Overstreet } 72414b393eeSKent Overstreet err: 72591d961baSKent Overstreet darray_exit(&deleted); 72614b393eeSKent Overstreet bch2_trans_exit(&trans); 72714b393eeSKent Overstreet percpu_ref_put(&c->writes); 72814b393eeSKent Overstreet } 72914b393eeSKent Overstreet 73014b393eeSKent Overstreet static void bch2_delete_dead_snapshots(struct bch_fs *c) 73114b393eeSKent Overstreet { 73214b393eeSKent Overstreet if (unlikely(!percpu_ref_tryget(&c->writes))) 73314b393eeSKent Overstreet return; 73414b393eeSKent Overstreet 73514b393eeSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_delete_work)) 73614b393eeSKent Overstreet percpu_ref_put(&c->writes); 73714b393eeSKent Overstreet } 73814b393eeSKent Overstreet 73914b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, 74014b393eeSKent Overstreet struct btree_trans_commit_hook *h) 74114b393eeSKent Overstreet { 74214b393eeSKent Overstreet bch2_delete_dead_snapshots(trans->c); 74314b393eeSKent Overstreet return 0; 74414b393eeSKent Overstreet } 74514b393eeSKent Overstreet 74614b393eeSKent Overstreet /* Subvolumes: */ 74714b393eeSKent Overstreet 748f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, 749275c8426SKent Overstreet int rw, struct printbuf *err) 75014b393eeSKent Overstreet { 751f0ac7df2SKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 || 752f0ac7df2SKent Overstreet bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) { 753*401ec4dbSKent Overstreet prt_printf(err, "invalid pos"); 754f0ac7df2SKent Overstreet return -EINVAL; 755f0ac7df2SKent Overstreet } 75614b393eeSKent Overstreet 757f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) { 758*401ec4dbSKent Overstreet prt_printf(err, "incorrect value size (%zu != %zu)", 759f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_subvolume)); 760f0ac7df2SKent Overstreet return -EINVAL; 761f0ac7df2SKent Overstreet } 76214b393eeSKent Overstreet 763f0ac7df2SKent Overstreet return 0; 76414b393eeSKent Overstreet } 76514b393eeSKent Overstreet 76614b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, 76714b393eeSKent Overstreet struct bkey_s_c k) 76814b393eeSKent Overstreet { 76914b393eeSKent Overstreet struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k); 77014b393eeSKent Overstreet 771*401ec4dbSKent Overstreet prt_printf(out, "root %llu snapshot id %u", 77214b393eeSKent Overstreet le64_to_cpu(s.v->inode), 77314b393eeSKent Overstreet le32_to_cpu(s.v->snapshot)); 77414b393eeSKent Overstreet } 77514b393eeSKent Overstreet 77697996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, 77797996ddfSKent Overstreet bool inconsistent_if_not_found, 77897996ddfSKent Overstreet int iter_flags, 77997996ddfSKent Overstreet struct bch_subvolume *s) 78014b393eeSKent Overstreet { 78114b393eeSKent Overstreet struct btree_iter iter; 78214b393eeSKent Overstreet struct bkey_s_c k; 78314b393eeSKent Overstreet int ret; 78414b393eeSKent Overstreet 78597996ddfSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol), 78697996ddfSKent Overstreet iter_flags); 78714b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 78897996ddfSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT; 78914b393eeSKent Overstreet 79097996ddfSKent Overstreet if (ret == -ENOENT && inconsistent_if_not_found) 79114b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol); 79297996ddfSKent Overstreet if (!ret) 79397996ddfSKent Overstreet *s = *bkey_s_c_to_subvolume(k).v; 79497996ddfSKent Overstreet 79597996ddfSKent Overstreet bch2_trans_iter_exit(trans, &iter); 79697996ddfSKent Overstreet return ret; 79714b393eeSKent Overstreet } 79814b393eeSKent Overstreet 7999ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot, 8009ca4853bSKent Overstreet struct bch_subvolume *subvol) 8019ca4853bSKent Overstreet { 8029ca4853bSKent Overstreet struct bch_snapshot snap; 8039ca4853bSKent Overstreet 8049ca4853bSKent Overstreet return snapshot_lookup(trans, snapshot, &snap) ?: 8059ca4853bSKent Overstreet bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol); 8069ca4853bSKent Overstreet } 8079ca4853bSKent Overstreet 80897996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol, 80997996ddfSKent Overstreet u32 *snapid) 81097996ddfSKent Overstreet { 81197996ddfSKent Overstreet struct bch_subvolume s; 81297996ddfSKent Overstreet int ret; 81397996ddfSKent Overstreet 81497996ddfSKent Overstreet ret = bch2_subvolume_get(trans, subvol, true, 81597996ddfSKent Overstreet BTREE_ITER_CACHED| 81697996ddfSKent Overstreet BTREE_ITER_WITH_UPDATES, 81797996ddfSKent Overstreet &s); 81897996ddfSKent Overstreet 81997996ddfSKent Overstreet *snapid = le32_to_cpu(s.snapshot); 82014b393eeSKent Overstreet return ret; 82114b393eeSKent Overstreet } 82214b393eeSKent Overstreet 8232027875bSKent Overstreet /* 8242027875bSKent Overstreet * Delete subvolume, mark snapshot ID as deleted, queue up snapshot 8252027875bSKent Overstreet * deletion/cleanup: 8262027875bSKent Overstreet */ 8272027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid) 82814b393eeSKent Overstreet { 82914b393eeSKent Overstreet struct btree_iter iter; 83014b393eeSKent Overstreet struct bkey_s_c k; 83114b393eeSKent Overstreet struct bkey_s_c_subvolume subvol; 83214b393eeSKent Overstreet struct btree_trans_commit_hook *h; 83314b393eeSKent Overstreet struct bkey_i *delete; 83414b393eeSKent Overstreet u32 snapid; 83514b393eeSKent Overstreet int ret = 0; 83614b393eeSKent Overstreet 83714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 83814b393eeSKent Overstreet POS(0, subvolid), 83914b393eeSKent Overstreet BTREE_ITER_CACHED| 84014b393eeSKent Overstreet BTREE_ITER_INTENT); 84114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 84214b393eeSKent Overstreet ret = bkey_err(k); 84314b393eeSKent Overstreet if (ret) 84414b393eeSKent Overstreet goto err; 84514b393eeSKent Overstreet 84614b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 84714b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 84814b393eeSKent Overstreet ret = -EIO; 84914b393eeSKent Overstreet goto err; 85014b393eeSKent Overstreet } 85114b393eeSKent Overstreet 85214b393eeSKent Overstreet subvol = bkey_s_c_to_subvolume(k); 85314b393eeSKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 85414b393eeSKent Overstreet 85514b393eeSKent Overstreet delete = bch2_trans_kmalloc(trans, sizeof(*delete)); 85614b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(delete); 85714b393eeSKent Overstreet if (ret) 85814b393eeSKent Overstreet goto err; 85914b393eeSKent Overstreet 86014b393eeSKent Overstreet bkey_init(&delete->k); 86114b393eeSKent Overstreet delete->k.p = iter.pos; 86214b393eeSKent Overstreet ret = bch2_trans_update(trans, &iter, delete, 0); 86314b393eeSKent Overstreet if (ret) 86414b393eeSKent Overstreet goto err; 86514b393eeSKent Overstreet 86614b393eeSKent Overstreet ret = bch2_snapshot_node_set_deleted(trans, snapid); 86714b393eeSKent Overstreet 86814b393eeSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 86914b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 87014b393eeSKent Overstreet if (ret) 87114b393eeSKent Overstreet goto err; 87214b393eeSKent Overstreet 87314b393eeSKent Overstreet h->fn = bch2_delete_dead_snapshots_hook; 87414b393eeSKent Overstreet bch2_trans_commit_hook(trans, h); 87514b393eeSKent Overstreet err: 87614b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 87714b393eeSKent Overstreet return ret; 87814b393eeSKent Overstreet } 87914b393eeSKent Overstreet 8802027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) 8812027875bSKent Overstreet { 8822027875bSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, 8832027875bSKent Overstreet snapshot_wait_for_pagecache_and_delete_work); 88491d961baSKent Overstreet snapshot_id_list s; 8852027875bSKent Overstreet u32 *id; 8862027875bSKent Overstreet int ret = 0; 8872027875bSKent Overstreet 8882027875bSKent Overstreet while (!ret) { 8892027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 8902027875bSKent Overstreet s = c->snapshots_unlinked; 89191d961baSKent Overstreet darray_init(&c->snapshots_unlinked); 8922027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 8932027875bSKent Overstreet 8942027875bSKent Overstreet if (!s.nr) 8952027875bSKent Overstreet break; 8962027875bSKent Overstreet 8972027875bSKent Overstreet bch2_evict_subvolume_inodes(c, &s); 8982027875bSKent Overstreet 89991d961baSKent Overstreet for (id = s.data; id < s.data + s.nr; id++) { 9002027875bSKent Overstreet ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL, 9012027875bSKent Overstreet bch2_subvolume_delete(&trans, *id)); 9022027875bSKent Overstreet if (ret) { 9032027875bSKent Overstreet bch_err(c, "error %i deleting subvolume %u", ret, *id); 9042027875bSKent Overstreet break; 9052027875bSKent Overstreet } 9062027875bSKent Overstreet } 9072027875bSKent Overstreet 90891d961baSKent Overstreet darray_exit(&s); 9092027875bSKent Overstreet } 9102027875bSKent Overstreet 9112027875bSKent Overstreet percpu_ref_put(&c->writes); 9122027875bSKent Overstreet } 9132027875bSKent Overstreet 9142027875bSKent Overstreet struct subvolume_unlink_hook { 9152027875bSKent Overstreet struct btree_trans_commit_hook h; 9162027875bSKent Overstreet u32 subvol; 9172027875bSKent Overstreet }; 9182027875bSKent Overstreet 9192027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, 9202027875bSKent Overstreet struct btree_trans_commit_hook *_h) 9212027875bSKent Overstreet { 9222027875bSKent Overstreet struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h); 9232027875bSKent Overstreet struct bch_fs *c = trans->c; 9242027875bSKent Overstreet int ret = 0; 9252027875bSKent Overstreet 9262027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9272027875bSKent Overstreet if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol)) 9282027875bSKent Overstreet ret = snapshot_id_add(&c->snapshots_unlinked, h->subvol); 9292027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9302027875bSKent Overstreet 9312027875bSKent Overstreet if (ret) 9322027875bSKent Overstreet return ret; 9332027875bSKent Overstreet 9342027875bSKent Overstreet if (unlikely(!percpu_ref_tryget(&c->writes))) 9352027875bSKent Overstreet return -EROFS; 9362027875bSKent Overstreet 9372027875bSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work)) 9382027875bSKent Overstreet percpu_ref_put(&c->writes); 9392027875bSKent Overstreet return 0; 9402027875bSKent Overstreet } 9412027875bSKent Overstreet 9422027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) 9432027875bSKent Overstreet { 9442027875bSKent Overstreet struct btree_iter iter; 9452027875bSKent Overstreet struct bkey_s_c k; 9462027875bSKent Overstreet struct bkey_i_subvolume *n; 9472027875bSKent Overstreet struct subvolume_unlink_hook *h; 9482027875bSKent Overstreet int ret = 0; 9492027875bSKent Overstreet 9502027875bSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 9512027875bSKent Overstreet POS(0, subvolid), 9522027875bSKent Overstreet BTREE_ITER_CACHED| 9532027875bSKent Overstreet BTREE_ITER_INTENT); 9542027875bSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 9552027875bSKent Overstreet ret = bkey_err(k); 9562027875bSKent Overstreet if (ret) 9572027875bSKent Overstreet goto err; 9582027875bSKent Overstreet 9592027875bSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 9602027875bSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 9612027875bSKent Overstreet ret = -EIO; 9622027875bSKent Overstreet goto err; 9632027875bSKent Overstreet } 9642027875bSKent Overstreet 9652027875bSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 9662027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 9672027875bSKent Overstreet if (ret) 9682027875bSKent Overstreet goto err; 9692027875bSKent Overstreet 9702027875bSKent Overstreet bkey_reassemble(&n->k_i, k); 9712027875bSKent Overstreet SET_BCH_SUBVOLUME_UNLINKED(&n->v, true); 9722027875bSKent Overstreet 9732027875bSKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 9742027875bSKent Overstreet if (ret) 9752027875bSKent Overstreet goto err; 9762027875bSKent Overstreet 9772027875bSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 9782027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 9792027875bSKent Overstreet if (ret) 9802027875bSKent Overstreet goto err; 9812027875bSKent Overstreet 9822027875bSKent Overstreet h->h.fn = bch2_subvolume_wait_for_pagecache_and_delete_hook; 9832027875bSKent Overstreet h->subvol = subvolid; 9842027875bSKent Overstreet bch2_trans_commit_hook(trans, &h->h); 9852027875bSKent Overstreet err: 9862027875bSKent Overstreet bch2_trans_iter_exit(trans, &iter); 9872027875bSKent Overstreet return ret; 9882027875bSKent Overstreet } 9892027875bSKent Overstreet 99014b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode, 99114b393eeSKent Overstreet u32 src_subvolid, 99214b393eeSKent Overstreet u32 *new_subvolid, 99314b393eeSKent Overstreet u32 *new_snapshotid, 99414b393eeSKent Overstreet bool ro) 99514b393eeSKent Overstreet { 996ca130b9cSKent Overstreet struct bch_fs *c = trans->c; 99714b393eeSKent Overstreet struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL }; 99814b393eeSKent Overstreet struct bkey_i_subvolume *new_subvol = NULL; 99914b393eeSKent Overstreet struct bkey_i_subvolume *src_subvol = NULL; 100014b393eeSKent Overstreet struct bkey_s_c k; 100114b393eeSKent Overstreet u32 parent = 0, new_nodes[2], snapshot_subvols[2]; 100214b393eeSKent Overstreet int ret = 0; 100314b393eeSKent Overstreet 100414b393eeSKent Overstreet for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN, 100514b393eeSKent Overstreet BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { 100614b393eeSKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) 100714b393eeSKent Overstreet break; 1008ca130b9cSKent Overstreet 1009ca130b9cSKent Overstreet /* 1010ca130b9cSKent Overstreet * bch2_subvolume_delete() doesn't flush the btree key cache - 1011ca130b9cSKent Overstreet * ideally it would but that's tricky 1012ca130b9cSKent Overstreet */ 1013ca130b9cSKent Overstreet if (bkey_deleted(k.k) && 1014ca130b9cSKent Overstreet !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos)) 101514b393eeSKent Overstreet goto found_slot; 101614b393eeSKent Overstreet } 101714b393eeSKent Overstreet 101814b393eeSKent Overstreet if (!ret) 101914b393eeSKent Overstreet ret = -ENOSPC; 102014b393eeSKent Overstreet goto err; 102114b393eeSKent Overstreet found_slot: 102214b393eeSKent Overstreet snapshot_subvols[0] = dst_iter.pos.offset; 102314b393eeSKent Overstreet snapshot_subvols[1] = src_subvolid; 102414b393eeSKent Overstreet 102514b393eeSKent Overstreet if (src_subvolid) { 102614b393eeSKent Overstreet /* Creating a snapshot: */ 102714b393eeSKent Overstreet src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol)); 102814b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(src_subvol); 102914b393eeSKent Overstreet if (ret) 103014b393eeSKent Overstreet goto err; 103114b393eeSKent Overstreet 103214b393eeSKent Overstreet bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes, 103314b393eeSKent Overstreet POS(0, src_subvolid), 103414b393eeSKent Overstreet BTREE_ITER_CACHED| 103514b393eeSKent Overstreet BTREE_ITER_INTENT); 103614b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&src_iter); 103714b393eeSKent Overstreet ret = bkey_err(k); 103814b393eeSKent Overstreet if (ret) 103914b393eeSKent Overstreet goto err; 104014b393eeSKent Overstreet 104114b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 1042ca130b9cSKent Overstreet bch_err(c, "subvolume %u not found", src_subvolid); 104314b393eeSKent Overstreet ret = -ENOENT; 104414b393eeSKent Overstreet goto err; 104514b393eeSKent Overstreet } 104614b393eeSKent Overstreet 104714b393eeSKent Overstreet bkey_reassemble(&src_subvol->k_i, k); 104814b393eeSKent Overstreet parent = le32_to_cpu(src_subvol->v.snapshot); 104914b393eeSKent Overstreet } 105014b393eeSKent Overstreet 105114b393eeSKent Overstreet ret = bch2_snapshot_node_create(trans, parent, new_nodes, 105214b393eeSKent Overstreet snapshot_subvols, 105314b393eeSKent Overstreet src_subvolid ? 2 : 1); 105414b393eeSKent Overstreet if (ret) 105514b393eeSKent Overstreet goto err; 105614b393eeSKent Overstreet 105714b393eeSKent Overstreet if (src_subvolid) { 105814b393eeSKent Overstreet src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]); 105994a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0); 106094a3e1a6SKent Overstreet if (ret) 106194a3e1a6SKent Overstreet goto err; 106214b393eeSKent Overstreet } 106314b393eeSKent Overstreet 106414b393eeSKent Overstreet new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol)); 106514b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(new_subvol); 106614b393eeSKent Overstreet if (ret) 106714b393eeSKent Overstreet goto err; 106814b393eeSKent Overstreet 106914b393eeSKent Overstreet bkey_subvolume_init(&new_subvol->k_i); 107014b393eeSKent Overstreet new_subvol->v.flags = 0; 107114b393eeSKent Overstreet new_subvol->v.snapshot = cpu_to_le32(new_nodes[0]); 107214b393eeSKent Overstreet new_subvol->v.inode = cpu_to_le64(inode); 107314b393eeSKent Overstreet SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro); 107414b393eeSKent Overstreet SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0); 107514b393eeSKent Overstreet new_subvol->k.p = dst_iter.pos; 107694a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0); 107794a3e1a6SKent Overstreet if (ret) 107894a3e1a6SKent Overstreet goto err; 107914b393eeSKent Overstreet 108014b393eeSKent Overstreet *new_subvolid = new_subvol->k.p.offset; 108114b393eeSKent Overstreet *new_snapshotid = new_nodes[0]; 108214b393eeSKent Overstreet err: 108314b393eeSKent Overstreet bch2_trans_iter_exit(trans, &src_iter); 108414b393eeSKent Overstreet bch2_trans_iter_exit(trans, &dst_iter); 108514b393eeSKent Overstreet return ret; 108614b393eeSKent Overstreet } 108714b393eeSKent Overstreet 108814b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c) 108914b393eeSKent Overstreet { 109014b393eeSKent Overstreet INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work); 10912027875bSKent Overstreet INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work, 10922027875bSKent Overstreet bch2_subvolume_wait_for_pagecache_and_delete); 10932027875bSKent Overstreet mutex_init(&c->snapshots_unlinked_lock); 109414b393eeSKent Overstreet return 0; 109514b393eeSKent Overstreet } 1096