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 void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, 1314b393eeSKent Overstreet struct bkey_s_c k) 1414b393eeSKent Overstreet { 1514b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k); 1614b393eeSKent Overstreet 17416cc426SKent Overstreet prt_printf(out, "is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u", 1814b393eeSKent Overstreet BCH_SNAPSHOT_SUBVOL(s.v), 1914b393eeSKent Overstreet BCH_SNAPSHOT_DELETED(s.v), 2014b393eeSKent Overstreet le32_to_cpu(s.v->parent), 2114b393eeSKent Overstreet le32_to_cpu(s.v->children[0]), 2214b393eeSKent Overstreet le32_to_cpu(s.v->children[1]), 2314b393eeSKent Overstreet le32_to_cpu(s.v->subvol)); 2414b393eeSKent Overstreet } 2514b393eeSKent Overstreet 26f0ac7df2SKent Overstreet int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, 27275c8426SKent Overstreet int rw, struct printbuf *err) 2814b393eeSKent Overstreet { 2914b393eeSKent Overstreet struct bkey_s_c_snapshot s; 3014b393eeSKent Overstreet u32 i, id; 3114b393eeSKent Overstreet 3214b393eeSKent Overstreet if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 || 33f0ac7df2SKent Overstreet bkey_cmp(k.k->p, POS(0, 1)) < 0) { 34401ec4dbSKent Overstreet prt_printf(err, "bad pos"); 35f0ac7df2SKent Overstreet return -EINVAL; 36f0ac7df2SKent Overstreet } 3714b393eeSKent Overstreet 38f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) { 39401ec4dbSKent Overstreet prt_printf(err, "bad val size (%zu != %zu)", 40f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_snapshot)); 41f0ac7df2SKent Overstreet return -EINVAL; 42f0ac7df2SKent Overstreet } 4314b393eeSKent Overstreet 4414b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 4514b393eeSKent Overstreet 4614b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 47f0ac7df2SKent Overstreet if (id && id <= k.k->p.offset) { 48401ec4dbSKent Overstreet prt_printf(err, "bad parent node (%u <= %llu)", 49f0ac7df2SKent Overstreet id, k.k->p.offset); 50f0ac7df2SKent Overstreet return -EINVAL; 51f0ac7df2SKent Overstreet } 5214b393eeSKent Overstreet 53f0ac7df2SKent Overstreet if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) { 54401ec4dbSKent Overstreet prt_printf(err, "children not normalized"); 55f0ac7df2SKent Overstreet return -EINVAL; 56f0ac7df2SKent Overstreet } 5714b393eeSKent Overstreet 5814b393eeSKent Overstreet if (s.v->children[0] && 59f0ac7df2SKent Overstreet s.v->children[0] == s.v->children[1]) { 60401ec4dbSKent Overstreet prt_printf(err, "duplicate child nodes"); 61f0ac7df2SKent Overstreet return -EINVAL; 62f0ac7df2SKent Overstreet } 6314b393eeSKent Overstreet 6414b393eeSKent Overstreet for (i = 0; i < 2; i++) { 6514b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 6614b393eeSKent Overstreet 67f0ac7df2SKent Overstreet if (id >= k.k->p.offset) { 68401ec4dbSKent Overstreet prt_printf(err, "bad child node (%u >= %llu)", 69f0ac7df2SKent Overstreet id, k.k->p.offset); 70f0ac7df2SKent Overstreet return -EINVAL; 71f0ac7df2SKent Overstreet } 7214b393eeSKent Overstreet } 7314b393eeSKent Overstreet 74f0ac7df2SKent Overstreet return 0; 7514b393eeSKent Overstreet } 7614b393eeSKent Overstreet 77904823deSKent Overstreet int bch2_mark_snapshot(struct btree_trans *trans, 7814b393eeSKent Overstreet struct bkey_s_c old, struct bkey_s_c new, 79904823deSKent Overstreet unsigned flags) 8014b393eeSKent Overstreet { 81904823deSKent Overstreet struct bch_fs *c = trans->c; 8214b393eeSKent Overstreet struct snapshot_t *t; 8314b393eeSKent Overstreet 8414b393eeSKent Overstreet t = genradix_ptr_alloc(&c->snapshots, 8514b393eeSKent Overstreet U32_MAX - new.k->p.offset, 8614b393eeSKent Overstreet GFP_KERNEL); 8714b393eeSKent Overstreet if (!t) 8814b393eeSKent Overstreet return -ENOMEM; 8914b393eeSKent Overstreet 9014b393eeSKent Overstreet if (new.k->type == KEY_TYPE_snapshot) { 9114b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new); 9214b393eeSKent Overstreet 9314b393eeSKent Overstreet t->parent = le32_to_cpu(s.v->parent); 9414b393eeSKent Overstreet t->children[0] = le32_to_cpu(s.v->children[0]); 9514b393eeSKent Overstreet t->children[1] = le32_to_cpu(s.v->children[1]); 9614b393eeSKent Overstreet t->subvol = BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0; 9714b393eeSKent Overstreet } else { 9814b393eeSKent Overstreet t->parent = 0; 9914b393eeSKent Overstreet t->children[0] = 0; 10014b393eeSKent Overstreet t->children[1] = 0; 10114b393eeSKent Overstreet t->subvol = 0; 10214b393eeSKent Overstreet } 10314b393eeSKent Overstreet 10414b393eeSKent Overstreet return 0; 10514b393eeSKent Overstreet } 10614b393eeSKent Overstreet 10714b393eeSKent Overstreet static int snapshot_lookup(struct btree_trans *trans, u32 id, 10814b393eeSKent Overstreet struct bch_snapshot *s) 10914b393eeSKent Overstreet { 11014b393eeSKent Overstreet struct btree_iter iter; 11114b393eeSKent Overstreet struct bkey_s_c k; 11214b393eeSKent Overstreet int ret; 11314b393eeSKent Overstreet 11414b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 11514b393eeSKent Overstreet BTREE_ITER_WITH_UPDATES); 11614b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 11714b393eeSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT; 11814b393eeSKent Overstreet 11914b393eeSKent Overstreet if (!ret) 12014b393eeSKent Overstreet *s = *bkey_s_c_to_snapshot(k).v; 12114b393eeSKent Overstreet 12214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 12314b393eeSKent Overstreet return ret; 12414b393eeSKent Overstreet } 12514b393eeSKent Overstreet 12614b393eeSKent Overstreet static int snapshot_live(struct btree_trans *trans, u32 id) 12714b393eeSKent Overstreet { 12814b393eeSKent Overstreet struct bch_snapshot v; 12914b393eeSKent Overstreet int ret; 13014b393eeSKent Overstreet 13114b393eeSKent Overstreet if (!id) 13214b393eeSKent Overstreet return 0; 13314b393eeSKent Overstreet 134a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 13514b393eeSKent Overstreet if (ret == -ENOENT) 13614b393eeSKent Overstreet bch_err(trans->c, "snapshot node %u not found", id); 13714b393eeSKent Overstreet if (ret) 13814b393eeSKent Overstreet return ret; 13914b393eeSKent Overstreet 14014b393eeSKent Overstreet return !BCH_SNAPSHOT_DELETED(&v); 14114b393eeSKent Overstreet } 14214b393eeSKent Overstreet 143a1783320SKent Overstreet static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k) 14414b393eeSKent Overstreet { 14514b393eeSKent Overstreet struct bch_fs *c = trans->c; 14635f1a503SKent Overstreet unsigned i, nr_live = 0, live_idx = 0; 147a1783320SKent Overstreet struct bkey_s_c_snapshot snap; 148a1783320SKent Overstreet u32 id = k.k->p.offset, child[2]; 149a1783320SKent Overstreet 150a1783320SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 151a1783320SKent Overstreet return 0; 152a1783320SKent Overstreet 153a1783320SKent Overstreet snap = bkey_s_c_to_snapshot(k); 154a1783320SKent Overstreet 155a1783320SKent Overstreet child[0] = le32_to_cpu(snap.v->children[0]); 156a1783320SKent Overstreet child[1] = le32_to_cpu(snap.v->children[1]); 15714b393eeSKent Overstreet 15814b393eeSKent Overstreet for (i = 0; i < 2; i++) { 15935f1a503SKent Overstreet int ret = snapshot_live(trans, child[i]); 16014b393eeSKent Overstreet if (ret < 0) 16135f1a503SKent Overstreet return ret; 16214b393eeSKent Overstreet 16314b393eeSKent Overstreet if (ret) 16414b393eeSKent Overstreet live_idx = i; 16514b393eeSKent Overstreet nr_live += ret; 16614b393eeSKent Overstreet } 16714b393eeSKent Overstreet 16814b393eeSKent Overstreet snapshot_t(c, id)->equiv = nr_live == 1 16914b393eeSKent Overstreet ? snapshot_t(c, child[live_idx])->equiv 17014b393eeSKent Overstreet : id; 17135f1a503SKent Overstreet return 0; 17214b393eeSKent Overstreet } 17335f1a503SKent Overstreet 17414b393eeSKent Overstreet /* fsck: */ 17535f1a503SKent Overstreet static int check_snapshot(struct btree_trans *trans, 176a1783320SKent Overstreet struct btree_iter *iter, 177a1783320SKent Overstreet struct bkey_s_c k) 17814b393eeSKent Overstreet { 17935f1a503SKent Overstreet struct bch_fs *c = trans->c; 18035f1a503SKent Overstreet struct bkey_s_c_snapshot s; 18114b393eeSKent Overstreet struct bch_subvolume subvol; 18214b393eeSKent Overstreet struct bch_snapshot v; 18335f1a503SKent Overstreet struct printbuf buf = PRINTBUF; 18435f1a503SKent Overstreet bool should_have_subvol; 18514b393eeSKent Overstreet u32 i, id; 18635f1a503SKent Overstreet int ret = 0; 18714b393eeSKent Overstreet 18835f1a503SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 18935f1a503SKent Overstreet return 0; 19014b393eeSKent Overstreet 19135f1a503SKent Overstreet s = bkey_s_c_to_snapshot(k); 19214b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 19314b393eeSKent Overstreet if (id) { 194a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 19514b393eeSKent Overstreet if (ret == -ENOENT) 19635f1a503SKent Overstreet bch_err(c, "snapshot with nonexistent parent:\n %s", 19735f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf)); 19814b393eeSKent Overstreet if (ret) 19935f1a503SKent Overstreet goto err; 20014b393eeSKent Overstreet 20114b393eeSKent Overstreet if (le32_to_cpu(v.children[0]) != s.k->p.offset && 20214b393eeSKent Overstreet le32_to_cpu(v.children[1]) != s.k->p.offset) { 20335f1a503SKent Overstreet bch_err(c, "snapshot parent %u missing pointer to child %llu", 20414b393eeSKent Overstreet id, s.k->p.offset); 20535f1a503SKent Overstreet ret = -EINVAL; 20635f1a503SKent Overstreet goto err; 20714b393eeSKent Overstreet } 20814b393eeSKent Overstreet } 20914b393eeSKent Overstreet 21014b393eeSKent Overstreet for (i = 0; i < 2 && s.v->children[i]; i++) { 21114b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 21214b393eeSKent Overstreet 213a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 21414b393eeSKent Overstreet if (ret == -ENOENT) 21535f1a503SKent Overstreet bch_err(c, "snapshot node %llu has nonexistent child %u", 21614b393eeSKent Overstreet s.k->p.offset, id); 21714b393eeSKent Overstreet if (ret) 21835f1a503SKent Overstreet goto err; 21914b393eeSKent Overstreet 22014b393eeSKent Overstreet if (le32_to_cpu(v.parent) != s.k->p.offset) { 22135f1a503SKent Overstreet bch_err(c, "snapshot child %u has wrong parent (got %u should be %llu)", 22214b393eeSKent Overstreet id, le32_to_cpu(v.parent), s.k->p.offset); 22335f1a503SKent Overstreet ret = -EINVAL; 22435f1a503SKent Overstreet goto err; 22514b393eeSKent Overstreet } 22614b393eeSKent Overstreet } 22714b393eeSKent Overstreet 22835f1a503SKent Overstreet should_have_subvol = BCH_SNAPSHOT_SUBVOL(s.v) && 22935f1a503SKent Overstreet !BCH_SNAPSHOT_DELETED(s.v); 23035f1a503SKent Overstreet 23135f1a503SKent Overstreet if (should_have_subvol) { 23235f1a503SKent Overstreet id = le32_to_cpu(s.v->subvol); 233a1783320SKent Overstreet ret = bch2_subvolume_get(trans, id, 0, false, &subvol); 23435f1a503SKent Overstreet if (ret == -ENOENT) 23535f1a503SKent Overstreet bch_err(c, "snapshot points to nonexistent subvolume:\n %s", 23635f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf)); 23735f1a503SKent Overstreet if (ret) 23835f1a503SKent Overstreet goto err; 23935f1a503SKent Overstreet 24035f1a503SKent Overstreet if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) { 24135f1a503SKent Overstreet bch_err(c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL", 24235f1a503SKent Overstreet s.k->p.offset); 24335f1a503SKent Overstreet ret = -EINVAL; 24435f1a503SKent Overstreet goto err; 24535f1a503SKent Overstreet } 24635f1a503SKent Overstreet } else { 24735f1a503SKent Overstreet if (fsck_err_on(s.v->subvol, c, "snapshot should not point to subvol:\n %s", 24835f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) { 24935f1a503SKent Overstreet struct bkey_i_snapshot *u = bch2_trans_kmalloc(trans, sizeof(*u)); 25035f1a503SKent Overstreet 25135f1a503SKent Overstreet ret = PTR_ERR_OR_ZERO(u); 25235f1a503SKent Overstreet if (ret) 25335f1a503SKent Overstreet goto err; 25435f1a503SKent Overstreet 25535f1a503SKent Overstreet bkey_reassemble(&u->k_i, s.s_c); 25635f1a503SKent Overstreet u->v.subvol = 0; 25735f1a503SKent Overstreet ret = bch2_trans_update(trans, iter, &u->k_i, 0); 25835f1a503SKent Overstreet if (ret) 25935f1a503SKent Overstreet goto err; 26035f1a503SKent Overstreet } 26135f1a503SKent Overstreet } 26235f1a503SKent Overstreet 26335f1a503SKent Overstreet if (BCH_SNAPSHOT_DELETED(s.v)) 26435f1a503SKent Overstreet set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 26535f1a503SKent Overstreet err: 26635f1a503SKent Overstreet fsck_err: 26735f1a503SKent Overstreet printbuf_exit(&buf); 26835f1a503SKent Overstreet return ret; 26914b393eeSKent Overstreet } 27014b393eeSKent Overstreet 2714ab35c34SKent Overstreet int bch2_fs_check_snapshots(struct bch_fs *c) 27214b393eeSKent Overstreet { 27314b393eeSKent Overstreet struct btree_trans trans; 27414b393eeSKent Overstreet struct btree_iter iter; 275a1783320SKent Overstreet struct bkey_s_c k; 27614b393eeSKent Overstreet int ret; 27714b393eeSKent Overstreet 27814b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 27914b393eeSKent Overstreet 280a1783320SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, 281a1783320SKent Overstreet POS(BCACHEFS_ROOT_INO, 0), 282a1783320SKent Overstreet BTREE_ITER_PREFETCH, k, 283a1783320SKent Overstreet NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, 284a1783320SKent Overstreet check_snapshot(&trans, &iter, k)); 28514b393eeSKent Overstreet 28635f1a503SKent Overstreet if (ret) 28714b393eeSKent Overstreet bch_err(c, "error %i checking snapshots", ret); 28814b393eeSKent Overstreet 28914b393eeSKent Overstreet bch2_trans_exit(&trans); 29014b393eeSKent Overstreet return ret; 29114b393eeSKent Overstreet } 29214b393eeSKent Overstreet 2934ab35c34SKent Overstreet static int check_subvol(struct btree_trans *trans, 294*6738dd19SKent Overstreet struct btree_iter *iter, 295*6738dd19SKent Overstreet struct bkey_s_c k) 2964ab35c34SKent Overstreet { 2974ab35c34SKent Overstreet struct bkey_s_c_subvolume subvol; 29835f1a503SKent Overstreet struct bch_snapshot snapshot; 29935f1a503SKent Overstreet unsigned snapid; 3004ab35c34SKent Overstreet int ret; 3014ab35c34SKent Overstreet 3024ab35c34SKent Overstreet if (k.k->type != KEY_TYPE_subvolume) 3034ab35c34SKent Overstreet return 0; 3044ab35c34SKent Overstreet 3054ab35c34SKent Overstreet subvol = bkey_s_c_to_subvolume(k); 30635f1a503SKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 30735f1a503SKent Overstreet ret = snapshot_lookup(trans, snapid, &snapshot); 30835f1a503SKent Overstreet 30935f1a503SKent Overstreet if (ret == -ENOENT) 31035f1a503SKent Overstreet bch_err(trans->c, "subvolume %llu points to nonexistent snapshot %u", 31135f1a503SKent Overstreet k.k->p.offset, snapid); 31235f1a503SKent Overstreet if (ret) 31335f1a503SKent Overstreet return ret; 3144ab35c34SKent Overstreet 3154ab35c34SKent Overstreet if (BCH_SUBVOLUME_UNLINKED(subvol.v)) { 3164ab35c34SKent Overstreet ret = bch2_subvolume_delete(trans, iter->pos.offset); 3174ab35c34SKent Overstreet if (ret && ret != -EINTR) 3184ab35c34SKent Overstreet bch_err(trans->c, "error deleting subvolume %llu: %i", 3194ab35c34SKent Overstreet iter->pos.offset, ret); 3204ab35c34SKent Overstreet if (ret) 3214ab35c34SKent Overstreet return ret; 3224ab35c34SKent Overstreet } 3234ab35c34SKent Overstreet 3244ab35c34SKent Overstreet return 0; 3254ab35c34SKent Overstreet } 3264ab35c34SKent Overstreet 3274ab35c34SKent Overstreet int bch2_fs_check_subvols(struct bch_fs *c) 3284ab35c34SKent Overstreet { 3294ab35c34SKent Overstreet struct btree_trans trans; 3304ab35c34SKent Overstreet struct btree_iter iter; 331*6738dd19SKent Overstreet struct bkey_s_c k; 3324ab35c34SKent Overstreet int ret; 3334ab35c34SKent Overstreet 33435f1a503SKent Overstreet bch2_trans_init(&trans, c, 0, 0); 3354ab35c34SKent Overstreet 336*6738dd19SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, 337*6738dd19SKent Overstreet BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k, 338*6738dd19SKent Overstreet NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, 339*6738dd19SKent Overstreet check_subvol(&trans, &iter, k)); 3404ab35c34SKent Overstreet 3414ab35c34SKent Overstreet bch2_trans_exit(&trans); 3424ab35c34SKent Overstreet 3434ab35c34SKent Overstreet return ret; 3444ab35c34SKent Overstreet } 3454ab35c34SKent Overstreet 34614b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c) 34714b393eeSKent Overstreet { 34814b393eeSKent Overstreet genradix_free(&c->snapshots); 34914b393eeSKent Overstreet } 35014b393eeSKent Overstreet 35114b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c) 35214b393eeSKent Overstreet { 35314b393eeSKent Overstreet struct btree_trans trans; 35414b393eeSKent Overstreet struct btree_iter iter; 35514b393eeSKent Overstreet struct bkey_s_c k; 35614b393eeSKent Overstreet int ret = 0; 35714b393eeSKent Overstreet 35814b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 35914b393eeSKent Overstreet 360a1783320SKent Overstreet for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, 361a1783320SKent Overstreet POS_MIN, 0, k, 362a1783320SKent Overstreet bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0) ?: 363a1783320SKent Overstreet bch2_snapshot_set_equiv(&trans, k)); 36414b393eeSKent Overstreet 36514b393eeSKent Overstreet bch2_trans_exit(&trans); 36635f1a503SKent Overstreet 36735f1a503SKent Overstreet if (ret) 36835f1a503SKent Overstreet bch_err(c, "error starting snapshots: %i", ret); 36914b393eeSKent Overstreet return ret; 37014b393eeSKent Overstreet } 37114b393eeSKent Overstreet 37214b393eeSKent Overstreet /* 37314b393eeSKent Overstreet * Mark a snapshot as deleted, for future cleanup: 37414b393eeSKent Overstreet */ 37514b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id) 37614b393eeSKent Overstreet { 37714b393eeSKent Overstreet struct btree_iter iter; 37814b393eeSKent Overstreet struct bkey_s_c k; 37914b393eeSKent Overstreet struct bkey_i_snapshot *s; 38014b393eeSKent Overstreet int ret = 0; 38114b393eeSKent Overstreet 38214b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 38314b393eeSKent Overstreet BTREE_ITER_INTENT); 38414b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 38514b393eeSKent Overstreet ret = bkey_err(k); 38614b393eeSKent Overstreet if (ret) 38714b393eeSKent Overstreet goto err; 38814b393eeSKent Overstreet 38914b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 39014b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 39114b393eeSKent Overstreet ret = -ENOENT; 39214b393eeSKent Overstreet goto err; 39314b393eeSKent Overstreet } 39414b393eeSKent Overstreet 39514b393eeSKent Overstreet /* already deleted? */ 39614b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 39714b393eeSKent Overstreet goto err; 39814b393eeSKent Overstreet 39914b393eeSKent Overstreet s = bch2_trans_kmalloc(trans, sizeof(*s)); 40014b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(s); 40114b393eeSKent Overstreet if (ret) 40214b393eeSKent Overstreet goto err; 40314b393eeSKent Overstreet 40414b393eeSKent Overstreet bkey_reassemble(&s->k_i, k); 40514b393eeSKent Overstreet SET_BCH_SNAPSHOT_DELETED(&s->v, true); 406416cc426SKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&s->v, false); 407416cc426SKent Overstreet s->v.subvol = 0; 408416cc426SKent Overstreet 40914b393eeSKent Overstreet ret = bch2_trans_update(trans, &iter, &s->k_i, 0); 41014b393eeSKent Overstreet if (ret) 41114b393eeSKent Overstreet goto err; 41214b393eeSKent Overstreet err: 41314b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 41414b393eeSKent Overstreet return ret; 41514b393eeSKent Overstreet } 41614b393eeSKent Overstreet 41714b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) 41814b393eeSKent Overstreet { 41914b393eeSKent Overstreet struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; 42014b393eeSKent Overstreet struct bkey_s_c k; 42114b393eeSKent Overstreet struct bkey_s_c_snapshot s; 42214b393eeSKent Overstreet struct bkey_i_snapshot *parent; 42314b393eeSKent Overstreet u32 parent_id; 42414b393eeSKent Overstreet unsigned i; 42514b393eeSKent Overstreet int ret = 0; 42614b393eeSKent Overstreet 42714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 42814b393eeSKent Overstreet BTREE_ITER_INTENT); 42914b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 43014b393eeSKent Overstreet ret = bkey_err(k); 43114b393eeSKent Overstreet if (ret) 43214b393eeSKent Overstreet goto err; 43314b393eeSKent Overstreet 43414b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 43514b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 43614b393eeSKent Overstreet ret = -ENOENT; 43714b393eeSKent Overstreet goto err; 43814b393eeSKent Overstreet } 43914b393eeSKent Overstreet 44014b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 44114b393eeSKent Overstreet 44214b393eeSKent Overstreet BUG_ON(!BCH_SNAPSHOT_DELETED(s.v)); 44314b393eeSKent Overstreet parent_id = le32_to_cpu(s.v->parent); 44414b393eeSKent Overstreet 44514b393eeSKent Overstreet if (parent_id) { 44614b393eeSKent Overstreet bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots, 44714b393eeSKent Overstreet POS(0, parent_id), 44814b393eeSKent Overstreet BTREE_ITER_INTENT); 44914b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&p_iter); 45014b393eeSKent Overstreet ret = bkey_err(k); 45114b393eeSKent Overstreet if (ret) 45214b393eeSKent Overstreet goto err; 45314b393eeSKent Overstreet 45414b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 45514b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id); 45614b393eeSKent Overstreet ret = -ENOENT; 45714b393eeSKent Overstreet goto err; 45814b393eeSKent Overstreet } 45914b393eeSKent Overstreet 46014b393eeSKent Overstreet parent = bch2_trans_kmalloc(trans, sizeof(*parent)); 46114b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(parent); 46214b393eeSKent Overstreet if (ret) 46314b393eeSKent Overstreet goto err; 46414b393eeSKent Overstreet 46514b393eeSKent Overstreet bkey_reassemble(&parent->k_i, k); 46614b393eeSKent Overstreet 46714b393eeSKent Overstreet for (i = 0; i < 2; i++) 46814b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[i]) == id) 46914b393eeSKent Overstreet break; 47014b393eeSKent Overstreet 47114b393eeSKent Overstreet if (i == 2) 47214b393eeSKent Overstreet bch_err(trans->c, "snapshot %u missing child pointer to %u", 47314b393eeSKent Overstreet parent_id, id); 47414b393eeSKent Overstreet else 47514b393eeSKent Overstreet parent->v.children[i] = 0; 47614b393eeSKent Overstreet 47714b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[0]) < 47814b393eeSKent Overstreet le32_to_cpu(parent->v.children[1])) 47914b393eeSKent Overstreet swap(parent->v.children[0], 48014b393eeSKent Overstreet parent->v.children[1]); 48114b393eeSKent Overstreet 48214b393eeSKent Overstreet ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0); 48314b393eeSKent Overstreet if (ret) 48414b393eeSKent Overstreet goto err; 48514b393eeSKent Overstreet } 48614b393eeSKent Overstreet 48714b393eeSKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 48814b393eeSKent Overstreet err: 48914b393eeSKent Overstreet bch2_trans_iter_exit(trans, &p_iter); 49014b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 49114b393eeSKent Overstreet return ret; 49214b393eeSKent Overstreet } 49314b393eeSKent Overstreet 4947f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, 49514b393eeSKent Overstreet u32 *new_snapids, 49614b393eeSKent Overstreet u32 *snapshot_subvols, 49714b393eeSKent Overstreet unsigned nr_snapids) 49814b393eeSKent Overstreet { 49914b393eeSKent Overstreet struct btree_iter iter; 50014b393eeSKent Overstreet struct bkey_i_snapshot *n; 50114b393eeSKent Overstreet struct bkey_s_c k; 50214b393eeSKent Overstreet unsigned i; 50314b393eeSKent Overstreet int ret = 0; 50414b393eeSKent Overstreet 50514b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, 50614b393eeSKent Overstreet POS_MIN, BTREE_ITER_INTENT); 50714b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 50814b393eeSKent Overstreet ret = bkey_err(k); 50914b393eeSKent Overstreet if (ret) 51014b393eeSKent Overstreet goto err; 51114b393eeSKent Overstreet 51214b393eeSKent Overstreet for (i = 0; i < nr_snapids; i++) { 51314b393eeSKent Overstreet k = bch2_btree_iter_prev_slot(&iter); 51414b393eeSKent Overstreet ret = bkey_err(k); 51514b393eeSKent Overstreet if (ret) 51614b393eeSKent Overstreet goto err; 51714b393eeSKent Overstreet 51814b393eeSKent Overstreet if (!k.k || !k.k->p.offset) { 51914b393eeSKent Overstreet ret = -ENOSPC; 52014b393eeSKent Overstreet goto err; 52114b393eeSKent Overstreet } 52214b393eeSKent Overstreet 52314b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 52414b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 52514b393eeSKent Overstreet if (ret) 52694a3e1a6SKent Overstreet goto err; 52714b393eeSKent Overstreet 52814b393eeSKent Overstreet bkey_snapshot_init(&n->k_i); 52914b393eeSKent Overstreet n->k.p = iter.pos; 53014b393eeSKent Overstreet n->v.flags = 0; 53114b393eeSKent Overstreet n->v.parent = cpu_to_le32(parent); 53214b393eeSKent Overstreet n->v.subvol = cpu_to_le32(snapshot_subvols[i]); 53314b393eeSKent Overstreet n->v.pad = 0; 53414b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, true); 53514b393eeSKent Overstreet 53694a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0) ?: 53794a3e1a6SKent Overstreet bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); 53814b393eeSKent Overstreet if (ret) 53994a3e1a6SKent Overstreet goto err; 54014b393eeSKent Overstreet 54114b393eeSKent Overstreet new_snapids[i] = iter.pos.offset; 54214b393eeSKent Overstreet } 54314b393eeSKent Overstreet 54414b393eeSKent Overstreet if (parent) { 54514b393eeSKent Overstreet bch2_btree_iter_set_pos(&iter, POS(0, parent)); 54614b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 54714b393eeSKent Overstreet ret = bkey_err(k); 54814b393eeSKent Overstreet if (ret) 54914b393eeSKent Overstreet goto err; 55014b393eeSKent Overstreet 55114b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 55214b393eeSKent Overstreet bch_err(trans->c, "snapshot %u not found", parent); 55314b393eeSKent Overstreet ret = -ENOENT; 55414b393eeSKent Overstreet goto err; 55514b393eeSKent Overstreet } 55614b393eeSKent Overstreet 55714b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 55814b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 55914b393eeSKent Overstreet if (ret) 560c4ecf802SKent Overstreet goto err; 56114b393eeSKent Overstreet 56214b393eeSKent Overstreet bkey_reassemble(&n->k_i, k); 56314b393eeSKent Overstreet 56414b393eeSKent Overstreet if (n->v.children[0] || n->v.children[1]) { 56514b393eeSKent Overstreet bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children"); 56614b393eeSKent Overstreet ret = -EINVAL; 56714b393eeSKent Overstreet goto err; 56814b393eeSKent Overstreet } 56914b393eeSKent Overstreet 57014b393eeSKent Overstreet n->v.children[0] = cpu_to_le32(new_snapids[0]); 57114b393eeSKent Overstreet n->v.children[1] = cpu_to_le32(new_snapids[1]); 57235f1a503SKent Overstreet n->v.subvol = 0; 57314b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, false); 57494a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 57594a3e1a6SKent Overstreet if (ret) 57694a3e1a6SKent Overstreet goto err; 57714b393eeSKent Overstreet } 57814b393eeSKent Overstreet err: 57914b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 58014b393eeSKent Overstreet return ret; 58114b393eeSKent Overstreet } 58214b393eeSKent Overstreet 583*6738dd19SKent Overstreet static int snapshot_delete_key(struct btree_trans *trans, 584*6738dd19SKent Overstreet struct btree_iter *iter, 585*6738dd19SKent Overstreet struct bkey_s_c k, 58691d961baSKent Overstreet snapshot_id_list *deleted, 587*6738dd19SKent Overstreet snapshot_id_list *equiv_seen, 588*6738dd19SKent Overstreet struct bpos *last_pos) 58914b393eeSKent Overstreet { 59014b393eeSKent Overstreet struct bch_fs *c = trans->c; 59114b393eeSKent Overstreet u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv; 59214b393eeSKent Overstreet 593*6738dd19SKent Overstreet if (bkey_cmp(k.k->p, *last_pos)) 594*6738dd19SKent Overstreet equiv_seen->nr = 0; 595*6738dd19SKent Overstreet *last_pos = k.k->p; 59614b393eeSKent Overstreet 59714b393eeSKent Overstreet if (snapshot_list_has_id(deleted, k.k->p.snapshot) || 598*6738dd19SKent Overstreet snapshot_list_has_id(equiv_seen, equiv)) { 599*6738dd19SKent Overstreet return bch2_btree_delete_at(trans, iter, 600*6738dd19SKent Overstreet BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE); 60114b393eeSKent Overstreet } else { 602*6738dd19SKent Overstreet return snapshot_list_add(c, equiv_seen, equiv); 60314b393eeSKent Overstreet } 60414b393eeSKent Overstreet } 60514b393eeSKent Overstreet 606a1783320SKent Overstreet static int bch2_delete_redundant_snapshot(struct btree_trans *trans, struct btree_iter *iter, 607a1783320SKent Overstreet struct bkey_s_c k) 608a1783320SKent Overstreet { 609a1783320SKent Overstreet struct bkey_s_c_snapshot snap; 610a1783320SKent Overstreet u32 children[2]; 611a1783320SKent Overstreet int ret; 612a1783320SKent Overstreet 613a1783320SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 614a1783320SKent Overstreet return 0; 615a1783320SKent Overstreet 616a1783320SKent Overstreet snap = bkey_s_c_to_snapshot(k); 617a1783320SKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v) || 618a1783320SKent Overstreet BCH_SNAPSHOT_SUBVOL(snap.v)) 619a1783320SKent Overstreet return 0; 620a1783320SKent Overstreet 621a1783320SKent Overstreet children[0] = le32_to_cpu(snap.v->children[0]); 622a1783320SKent Overstreet children[1] = le32_to_cpu(snap.v->children[1]); 623a1783320SKent Overstreet 624a1783320SKent Overstreet ret = snapshot_live(trans, children[0]) ?: 625a1783320SKent Overstreet snapshot_live(trans, children[1]); 626a1783320SKent Overstreet if (ret < 0) 627a1783320SKent Overstreet return ret; 628a1783320SKent Overstreet 629a1783320SKent Overstreet if (!ret) 630a1783320SKent Overstreet return bch2_snapshot_node_set_deleted(trans, k.k->p.offset); 631a1783320SKent Overstreet return 0; 632a1783320SKent Overstreet } 633a1783320SKent Overstreet 6344ab35c34SKent Overstreet int bch2_delete_dead_snapshots(struct bch_fs *c) 63514b393eeSKent Overstreet { 63614b393eeSKent Overstreet struct btree_trans trans; 63714b393eeSKent Overstreet struct btree_iter iter; 63814b393eeSKent Overstreet struct bkey_s_c k; 63914b393eeSKent Overstreet struct bkey_s_c_snapshot snap; 64091d961baSKent Overstreet snapshot_id_list deleted = { 0 }; 641a1783320SKent Overstreet u32 i, id; 64214b393eeSKent Overstreet int ret = 0; 64314b393eeSKent Overstreet 6444ab35c34SKent Overstreet if (!test_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags)) 6454ab35c34SKent Overstreet return 0; 6464ab35c34SKent Overstreet 6474ab35c34SKent Overstreet if (!test_bit(BCH_FS_STARTED, &c->flags)) { 6484ab35c34SKent Overstreet ret = bch2_fs_read_write_early(c); 6494ab35c34SKent Overstreet if (ret) { 6504ab35c34SKent Overstreet bch_err(c, "error deleleting dead snapshots: error going rw: %i", ret); 6514ab35c34SKent Overstreet return ret; 6524ab35c34SKent Overstreet } 6534ab35c34SKent Overstreet } 6544ab35c34SKent Overstreet 65514b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 65614b393eeSKent Overstreet 65714b393eeSKent Overstreet /* 65814b393eeSKent Overstreet * For every snapshot node: If we have no live children and it's not 65914b393eeSKent Overstreet * pointed to by a subvolume, delete it: 66014b393eeSKent Overstreet */ 661a1783320SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, 662a1783320SKent Overstreet POS_MIN, 0, k, 663a1783320SKent Overstreet NULL, NULL, 0, 664a1783320SKent Overstreet bch2_delete_redundant_snapshot(&trans, &iter, k)); 66514b393eeSKent Overstreet if (ret) { 666a1783320SKent Overstreet bch_err(c, "error deleting redundant snapshots: %i", ret); 66714b393eeSKent Overstreet goto err; 66814b393eeSKent Overstreet } 66914b393eeSKent Overstreet 670a1783320SKent Overstreet for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, 671a1783320SKent Overstreet POS_MIN, 0, k, 672a1783320SKent Overstreet bch2_snapshot_set_equiv(&trans, k)); 673a1783320SKent Overstreet if (ret) { 674a1783320SKent Overstreet bch_err(c, "error in bch2_snapshots_set_equiv: %i", ret); 67514b393eeSKent Overstreet goto err; 676a1783320SKent Overstreet } 67714b393eeSKent Overstreet 67814b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 67914b393eeSKent Overstreet POS_MIN, 0, k, ret) { 68014b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 68114b393eeSKent Overstreet continue; 68214b393eeSKent Overstreet 68314b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 68414b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v)) { 685597dee1cSKent Overstreet ret = snapshot_list_add(c, &deleted, k.k->p.offset); 68614b393eeSKent Overstreet if (ret) 68714b393eeSKent Overstreet break; 68814b393eeSKent Overstreet } 68914b393eeSKent Overstreet } 69014b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 69114b393eeSKent Overstreet 69214b393eeSKent Overstreet if (ret) { 69314b393eeSKent Overstreet bch_err(c, "error walking snapshots: %i", ret); 69414b393eeSKent Overstreet goto err; 69514b393eeSKent Overstreet } 69614b393eeSKent Overstreet 69714b393eeSKent Overstreet for (id = 0; id < BTREE_ID_NR; id++) { 698*6738dd19SKent Overstreet struct bpos last_pos = POS_MIN; 699*6738dd19SKent Overstreet snapshot_id_list equiv_seen = { 0 }; 700*6738dd19SKent Overstreet 70114b393eeSKent Overstreet if (!btree_type_has_snapshots(id)) 70214b393eeSKent Overstreet continue; 70314b393eeSKent Overstreet 704*6738dd19SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, 705*6738dd19SKent Overstreet id, POS_MIN, 706*6738dd19SKent Overstreet BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, 707*6738dd19SKent Overstreet NULL, NULL, BTREE_INSERT_NOFAIL, 708*6738dd19SKent Overstreet snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos)); 709*6738dd19SKent Overstreet 710*6738dd19SKent Overstreet darray_exit(&equiv_seen); 711*6738dd19SKent Overstreet 71214b393eeSKent Overstreet if (ret) { 71314b393eeSKent Overstreet bch_err(c, "error deleting snapshot keys: %i", ret); 71414b393eeSKent Overstreet goto err; 71514b393eeSKent Overstreet } 71614b393eeSKent Overstreet } 71714b393eeSKent Overstreet 71814b393eeSKent Overstreet for (i = 0; i < deleted.nr; i++) { 719e68914caSKent Overstreet ret = commit_do(&trans, NULL, NULL, 0, 72091d961baSKent Overstreet bch2_snapshot_node_delete(&trans, deleted.data[i])); 72114b393eeSKent Overstreet if (ret) { 72214b393eeSKent Overstreet bch_err(c, "error deleting snapshot %u: %i", 72391d961baSKent Overstreet deleted.data[i], ret); 72414b393eeSKent Overstreet goto err; 72514b393eeSKent Overstreet } 72614b393eeSKent Overstreet } 7274ab35c34SKent Overstreet 7284ab35c34SKent Overstreet clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 72914b393eeSKent Overstreet err: 73091d961baSKent Overstreet darray_exit(&deleted); 73114b393eeSKent Overstreet bch2_trans_exit(&trans); 7324ab35c34SKent Overstreet return ret; 7334ab35c34SKent Overstreet } 7344ab35c34SKent Overstreet 7354ab35c34SKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work) 7364ab35c34SKent Overstreet { 7374ab35c34SKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work); 7384ab35c34SKent Overstreet 7394ab35c34SKent Overstreet bch2_delete_dead_snapshots(c); 74014b393eeSKent Overstreet percpu_ref_put(&c->writes); 74114b393eeSKent Overstreet } 74214b393eeSKent Overstreet 7434ab35c34SKent Overstreet void bch2_delete_dead_snapshots_async(struct bch_fs *c) 74414b393eeSKent Overstreet { 7454ab35c34SKent Overstreet if (!percpu_ref_tryget_live(&c->writes)) 74614b393eeSKent Overstreet return; 74714b393eeSKent Overstreet 74814b393eeSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_delete_work)) 74914b393eeSKent Overstreet percpu_ref_put(&c->writes); 75014b393eeSKent Overstreet } 75114b393eeSKent Overstreet 75214b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, 75314b393eeSKent Overstreet struct btree_trans_commit_hook *h) 75414b393eeSKent Overstreet { 7554ab35c34SKent Overstreet struct bch_fs *c = trans->c; 7564ab35c34SKent Overstreet 7574ab35c34SKent Overstreet set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 7584ab35c34SKent Overstreet 7594ab35c34SKent Overstreet if (!test_bit(BCH_FS_FSCK_DONE, &c->flags)) 7604ab35c34SKent Overstreet return 0; 7614ab35c34SKent Overstreet 7624ab35c34SKent Overstreet bch2_delete_dead_snapshots_async(c); 76314b393eeSKent Overstreet return 0; 76414b393eeSKent Overstreet } 76514b393eeSKent Overstreet 76614b393eeSKent Overstreet /* Subvolumes: */ 76714b393eeSKent Overstreet 768f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, 769275c8426SKent Overstreet int rw, struct printbuf *err) 77014b393eeSKent Overstreet { 771f0ac7df2SKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 || 772f0ac7df2SKent Overstreet bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) { 773401ec4dbSKent Overstreet prt_printf(err, "invalid pos"); 774f0ac7df2SKent Overstreet return -EINVAL; 775f0ac7df2SKent Overstreet } 77614b393eeSKent Overstreet 777f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) { 778401ec4dbSKent Overstreet prt_printf(err, "incorrect value size (%zu != %zu)", 779f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_subvolume)); 780f0ac7df2SKent Overstreet return -EINVAL; 781f0ac7df2SKent Overstreet } 78214b393eeSKent Overstreet 783f0ac7df2SKent Overstreet return 0; 78414b393eeSKent Overstreet } 78514b393eeSKent Overstreet 78614b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, 78714b393eeSKent Overstreet struct bkey_s_c k) 78814b393eeSKent Overstreet { 78914b393eeSKent Overstreet struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k); 79014b393eeSKent Overstreet 791401ec4dbSKent Overstreet prt_printf(out, "root %llu snapshot id %u", 79214b393eeSKent Overstreet le64_to_cpu(s.v->inode), 79314b393eeSKent Overstreet le32_to_cpu(s.v->snapshot)); 79414b393eeSKent Overstreet } 79514b393eeSKent Overstreet 79697996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, 79797996ddfSKent Overstreet bool inconsistent_if_not_found, 79897996ddfSKent Overstreet int iter_flags, 79997996ddfSKent Overstreet struct bch_subvolume *s) 80014b393eeSKent Overstreet { 80114b393eeSKent Overstreet struct btree_iter iter; 80214b393eeSKent Overstreet struct bkey_s_c k; 80314b393eeSKent Overstreet int ret; 80414b393eeSKent Overstreet 80597996ddfSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol), 80697996ddfSKent Overstreet iter_flags); 80714b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 80897996ddfSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT; 80914b393eeSKent Overstreet 81097996ddfSKent Overstreet if (ret == -ENOENT && inconsistent_if_not_found) 81114b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol); 81297996ddfSKent Overstreet if (!ret) 81397996ddfSKent Overstreet *s = *bkey_s_c_to_subvolume(k).v; 81497996ddfSKent Overstreet 81597996ddfSKent Overstreet bch2_trans_iter_exit(trans, &iter); 81697996ddfSKent Overstreet return ret; 81714b393eeSKent Overstreet } 81814b393eeSKent Overstreet 8199ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot, 8209ca4853bSKent Overstreet struct bch_subvolume *subvol) 8219ca4853bSKent Overstreet { 8229ca4853bSKent Overstreet struct bch_snapshot snap; 8239ca4853bSKent Overstreet 8249ca4853bSKent Overstreet return snapshot_lookup(trans, snapshot, &snap) ?: 8259ca4853bSKent Overstreet bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol); 8269ca4853bSKent Overstreet } 8279ca4853bSKent Overstreet 82897996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol, 82997996ddfSKent Overstreet u32 *snapid) 83097996ddfSKent Overstreet { 83197996ddfSKent Overstreet struct bch_subvolume s; 83297996ddfSKent Overstreet int ret; 83397996ddfSKent Overstreet 83497996ddfSKent Overstreet ret = bch2_subvolume_get(trans, subvol, true, 83597996ddfSKent Overstreet BTREE_ITER_CACHED| 83697996ddfSKent Overstreet BTREE_ITER_WITH_UPDATES, 83797996ddfSKent Overstreet &s); 83897996ddfSKent Overstreet 83997996ddfSKent Overstreet *snapid = le32_to_cpu(s.snapshot); 84014b393eeSKent Overstreet return ret; 84114b393eeSKent Overstreet } 84214b393eeSKent Overstreet 8432027875bSKent Overstreet /* 8442027875bSKent Overstreet * Delete subvolume, mark snapshot ID as deleted, queue up snapshot 8452027875bSKent Overstreet * deletion/cleanup: 8462027875bSKent Overstreet */ 8472027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid) 84814b393eeSKent Overstreet { 84914b393eeSKent Overstreet struct btree_iter iter; 85014b393eeSKent Overstreet struct bkey_s_c k; 85114b393eeSKent Overstreet struct bkey_s_c_subvolume subvol; 85214b393eeSKent Overstreet struct btree_trans_commit_hook *h; 85314b393eeSKent Overstreet u32 snapid; 85414b393eeSKent Overstreet int ret = 0; 85514b393eeSKent Overstreet 85614b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 85714b393eeSKent Overstreet POS(0, subvolid), 85814b393eeSKent Overstreet BTREE_ITER_CACHED| 85914b393eeSKent Overstreet BTREE_ITER_INTENT); 86014b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 86114b393eeSKent Overstreet ret = bkey_err(k); 86214b393eeSKent Overstreet if (ret) 86314b393eeSKent Overstreet goto err; 86414b393eeSKent Overstreet 86514b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 86614b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 86714b393eeSKent Overstreet ret = -EIO; 86814b393eeSKent Overstreet goto err; 86914b393eeSKent Overstreet } 87014b393eeSKent Overstreet 87114b393eeSKent Overstreet subvol = bkey_s_c_to_subvolume(k); 87214b393eeSKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 87314b393eeSKent Overstreet 874416cc426SKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 87514b393eeSKent Overstreet if (ret) 87614b393eeSKent Overstreet goto err; 87714b393eeSKent Overstreet 87814b393eeSKent Overstreet ret = bch2_snapshot_node_set_deleted(trans, snapid); 87914b393eeSKent Overstreet 88014b393eeSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 88114b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 88214b393eeSKent Overstreet if (ret) 88314b393eeSKent Overstreet goto err; 88414b393eeSKent Overstreet 88514b393eeSKent Overstreet h->fn = bch2_delete_dead_snapshots_hook; 88614b393eeSKent Overstreet bch2_trans_commit_hook(trans, h); 88714b393eeSKent Overstreet err: 88814b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 88914b393eeSKent Overstreet return ret; 89014b393eeSKent Overstreet } 89114b393eeSKent Overstreet 8922027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) 8932027875bSKent Overstreet { 8942027875bSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, 8952027875bSKent Overstreet snapshot_wait_for_pagecache_and_delete_work); 89691d961baSKent Overstreet snapshot_id_list s; 8972027875bSKent Overstreet u32 *id; 8982027875bSKent Overstreet int ret = 0; 8992027875bSKent Overstreet 9002027875bSKent Overstreet while (!ret) { 9012027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9022027875bSKent Overstreet s = c->snapshots_unlinked; 90391d961baSKent Overstreet darray_init(&c->snapshots_unlinked); 9042027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9052027875bSKent Overstreet 9062027875bSKent Overstreet if (!s.nr) 9072027875bSKent Overstreet break; 9082027875bSKent Overstreet 9092027875bSKent Overstreet bch2_evict_subvolume_inodes(c, &s); 9102027875bSKent Overstreet 91191d961baSKent Overstreet for (id = s.data; id < s.data + s.nr; id++) { 9122027875bSKent Overstreet ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL, 9132027875bSKent Overstreet bch2_subvolume_delete(&trans, *id)); 9142027875bSKent Overstreet if (ret) { 9152027875bSKent Overstreet bch_err(c, "error %i deleting subvolume %u", ret, *id); 9162027875bSKent Overstreet break; 9172027875bSKent Overstreet } 9182027875bSKent Overstreet } 9192027875bSKent Overstreet 92091d961baSKent Overstreet darray_exit(&s); 9212027875bSKent Overstreet } 9222027875bSKent Overstreet 9232027875bSKent Overstreet percpu_ref_put(&c->writes); 9242027875bSKent Overstreet } 9252027875bSKent Overstreet 9262027875bSKent Overstreet struct subvolume_unlink_hook { 9272027875bSKent Overstreet struct btree_trans_commit_hook h; 9282027875bSKent Overstreet u32 subvol; 9292027875bSKent Overstreet }; 9302027875bSKent Overstreet 9312027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, 9322027875bSKent Overstreet struct btree_trans_commit_hook *_h) 9332027875bSKent Overstreet { 9342027875bSKent Overstreet struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h); 9352027875bSKent Overstreet struct bch_fs *c = trans->c; 9362027875bSKent Overstreet int ret = 0; 9372027875bSKent Overstreet 9382027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9392027875bSKent Overstreet if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol)) 940597dee1cSKent Overstreet ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol); 9412027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9422027875bSKent Overstreet 9432027875bSKent Overstreet if (ret) 9442027875bSKent Overstreet return ret; 9452027875bSKent Overstreet 946a3d7afa5SKent Overstreet if (unlikely(!percpu_ref_tryget_live(&c->writes))) 9472027875bSKent Overstreet return -EROFS; 9482027875bSKent Overstreet 9492027875bSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work)) 9502027875bSKent Overstreet percpu_ref_put(&c->writes); 9512027875bSKent Overstreet return 0; 9522027875bSKent Overstreet } 9532027875bSKent Overstreet 9542027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) 9552027875bSKent Overstreet { 9562027875bSKent Overstreet struct btree_iter iter; 9572027875bSKent Overstreet struct bkey_s_c k; 9582027875bSKent Overstreet struct bkey_i_subvolume *n; 9592027875bSKent Overstreet struct subvolume_unlink_hook *h; 9602027875bSKent Overstreet int ret = 0; 9612027875bSKent Overstreet 9622027875bSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 9632027875bSKent Overstreet POS(0, subvolid), 9642027875bSKent Overstreet BTREE_ITER_CACHED| 9652027875bSKent Overstreet BTREE_ITER_INTENT); 9662027875bSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 9672027875bSKent Overstreet ret = bkey_err(k); 9682027875bSKent Overstreet if (ret) 9692027875bSKent Overstreet goto err; 9702027875bSKent Overstreet 9712027875bSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 9722027875bSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 9732027875bSKent Overstreet ret = -EIO; 9742027875bSKent Overstreet goto err; 9752027875bSKent Overstreet } 9762027875bSKent Overstreet 9772027875bSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 9782027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 9792027875bSKent Overstreet if (ret) 9802027875bSKent Overstreet goto err; 9812027875bSKent Overstreet 9822027875bSKent Overstreet bkey_reassemble(&n->k_i, k); 9832027875bSKent Overstreet SET_BCH_SUBVOLUME_UNLINKED(&n->v, true); 9842027875bSKent Overstreet 9852027875bSKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 9862027875bSKent Overstreet if (ret) 9872027875bSKent Overstreet goto err; 9882027875bSKent Overstreet 9892027875bSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 9902027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 9912027875bSKent Overstreet if (ret) 9922027875bSKent Overstreet goto err; 9932027875bSKent Overstreet 9942027875bSKent Overstreet h->h.fn = bch2_subvolume_wait_for_pagecache_and_delete_hook; 9952027875bSKent Overstreet h->subvol = subvolid; 9962027875bSKent Overstreet bch2_trans_commit_hook(trans, &h->h); 9972027875bSKent Overstreet err: 9982027875bSKent Overstreet bch2_trans_iter_exit(trans, &iter); 9992027875bSKent Overstreet return ret; 10002027875bSKent Overstreet } 10012027875bSKent Overstreet 100214b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode, 100314b393eeSKent Overstreet u32 src_subvolid, 100414b393eeSKent Overstreet u32 *new_subvolid, 100514b393eeSKent Overstreet u32 *new_snapshotid, 100614b393eeSKent Overstreet bool ro) 100714b393eeSKent Overstreet { 1008ca130b9cSKent Overstreet struct bch_fs *c = trans->c; 100914b393eeSKent Overstreet struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL }; 101014b393eeSKent Overstreet struct bkey_i_subvolume *new_subvol = NULL; 101114b393eeSKent Overstreet struct bkey_i_subvolume *src_subvol = NULL; 101214b393eeSKent Overstreet struct bkey_s_c k; 101314b393eeSKent Overstreet u32 parent = 0, new_nodes[2], snapshot_subvols[2]; 101414b393eeSKent Overstreet int ret = 0; 101514b393eeSKent Overstreet 101614b393eeSKent Overstreet for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN, 101714b393eeSKent Overstreet BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { 101814b393eeSKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) 101914b393eeSKent Overstreet break; 1020ca130b9cSKent Overstreet 1021ca130b9cSKent Overstreet /* 1022ca130b9cSKent Overstreet * bch2_subvolume_delete() doesn't flush the btree key cache - 1023ca130b9cSKent Overstreet * ideally it would but that's tricky 1024ca130b9cSKent Overstreet */ 1025ca130b9cSKent Overstreet if (bkey_deleted(k.k) && 1026ca130b9cSKent Overstreet !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos)) 102714b393eeSKent Overstreet goto found_slot; 102814b393eeSKent Overstreet } 102914b393eeSKent Overstreet 103014b393eeSKent Overstreet if (!ret) 103114b393eeSKent Overstreet ret = -ENOSPC; 103214b393eeSKent Overstreet goto err; 103314b393eeSKent Overstreet found_slot: 103414b393eeSKent Overstreet snapshot_subvols[0] = dst_iter.pos.offset; 103514b393eeSKent Overstreet snapshot_subvols[1] = src_subvolid; 103614b393eeSKent Overstreet 103714b393eeSKent Overstreet if (src_subvolid) { 103814b393eeSKent Overstreet /* Creating a snapshot: */ 103914b393eeSKent Overstreet src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol)); 104014b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(src_subvol); 104114b393eeSKent Overstreet if (ret) 104214b393eeSKent Overstreet goto err; 104314b393eeSKent Overstreet 104414b393eeSKent Overstreet bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes, 104514b393eeSKent Overstreet POS(0, src_subvolid), 104614b393eeSKent Overstreet BTREE_ITER_CACHED| 104714b393eeSKent Overstreet BTREE_ITER_INTENT); 104814b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&src_iter); 104914b393eeSKent Overstreet ret = bkey_err(k); 105014b393eeSKent Overstreet if (ret) 105114b393eeSKent Overstreet goto err; 105214b393eeSKent Overstreet 105314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 1054ca130b9cSKent Overstreet bch_err(c, "subvolume %u not found", src_subvolid); 105514b393eeSKent Overstreet ret = -ENOENT; 105614b393eeSKent Overstreet goto err; 105714b393eeSKent Overstreet } 105814b393eeSKent Overstreet 105914b393eeSKent Overstreet bkey_reassemble(&src_subvol->k_i, k); 106014b393eeSKent Overstreet parent = le32_to_cpu(src_subvol->v.snapshot); 106114b393eeSKent Overstreet } 106214b393eeSKent Overstreet 106314b393eeSKent Overstreet ret = bch2_snapshot_node_create(trans, parent, new_nodes, 106414b393eeSKent Overstreet snapshot_subvols, 106514b393eeSKent Overstreet src_subvolid ? 2 : 1); 106614b393eeSKent Overstreet if (ret) 106714b393eeSKent Overstreet goto err; 106814b393eeSKent Overstreet 106914b393eeSKent Overstreet if (src_subvolid) { 107014b393eeSKent Overstreet src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]); 107194a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0); 107294a3e1a6SKent Overstreet if (ret) 107394a3e1a6SKent Overstreet goto err; 107414b393eeSKent Overstreet } 107514b393eeSKent Overstreet 107614b393eeSKent Overstreet new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol)); 107714b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(new_subvol); 107814b393eeSKent Overstreet if (ret) 107914b393eeSKent Overstreet goto err; 108014b393eeSKent Overstreet 108114b393eeSKent Overstreet bkey_subvolume_init(&new_subvol->k_i); 108214b393eeSKent Overstreet new_subvol->v.flags = 0; 108314b393eeSKent Overstreet new_subvol->v.snapshot = cpu_to_le32(new_nodes[0]); 108414b393eeSKent Overstreet new_subvol->v.inode = cpu_to_le64(inode); 108514b393eeSKent Overstreet SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro); 108614b393eeSKent Overstreet SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0); 108714b393eeSKent Overstreet new_subvol->k.p = dst_iter.pos; 108894a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0); 108994a3e1a6SKent Overstreet if (ret) 109094a3e1a6SKent Overstreet goto err; 109114b393eeSKent Overstreet 109214b393eeSKent Overstreet *new_subvolid = new_subvol->k.p.offset; 109314b393eeSKent Overstreet *new_snapshotid = new_nodes[0]; 109414b393eeSKent Overstreet err: 109514b393eeSKent Overstreet bch2_trans_iter_exit(trans, &src_iter); 109614b393eeSKent Overstreet bch2_trans_iter_exit(trans, &dst_iter); 109714b393eeSKent Overstreet return ret; 109814b393eeSKent Overstreet } 109914b393eeSKent Overstreet 110014b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c) 110114b393eeSKent Overstreet { 110214b393eeSKent Overstreet INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work); 11032027875bSKent Overstreet INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work, 11042027875bSKent Overstreet bch2_subvolume_wait_for_pagecache_and_delete); 11052027875bSKent Overstreet mutex_init(&c->snapshots_unlinked_lock); 110614b393eeSKent Overstreet return 0; 110714b393eeSKent Overstreet } 1108