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" 6d4bf5eecSKent Overstreet #include "errcode.h" 714b393eeSKent Overstreet #include "error.h" 82027875bSKent Overstreet #include "fs.h" 914b393eeSKent Overstreet #include "subvolume.h" 1014b393eeSKent Overstreet 1114b393eeSKent Overstreet /* Snapshot tree: */ 1214b393eeSKent Overstreet 1314b393eeSKent Overstreet void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, 1414b393eeSKent Overstreet struct bkey_s_c k) 1514b393eeSKent Overstreet { 1614b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(k); 1714b393eeSKent Overstreet 18416cc426SKent Overstreet prt_printf(out, "is_subvol %llu deleted %llu parent %10u children %10u %10u subvol %u", 1914b393eeSKent Overstreet BCH_SNAPSHOT_SUBVOL(s.v), 2014b393eeSKent Overstreet BCH_SNAPSHOT_DELETED(s.v), 2114b393eeSKent Overstreet le32_to_cpu(s.v->parent), 2214b393eeSKent Overstreet le32_to_cpu(s.v->children[0]), 2314b393eeSKent Overstreet le32_to_cpu(s.v->children[1]), 2414b393eeSKent Overstreet le32_to_cpu(s.v->subvol)); 2514b393eeSKent Overstreet } 2614b393eeSKent Overstreet 27f0ac7df2SKent Overstreet int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, 28275c8426SKent Overstreet int rw, struct printbuf *err) 2914b393eeSKent Overstreet { 3014b393eeSKent Overstreet struct bkey_s_c_snapshot s; 3114b393eeSKent Overstreet u32 i, id; 3214b393eeSKent Overstreet 3314b393eeSKent Overstreet if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 || 34f0ac7df2SKent Overstreet bkey_cmp(k.k->p, POS(0, 1)) < 0) { 35401ec4dbSKent Overstreet prt_printf(err, "bad pos"); 36f0ac7df2SKent Overstreet return -EINVAL; 37f0ac7df2SKent Overstreet } 3814b393eeSKent Overstreet 39f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) { 40401ec4dbSKent Overstreet prt_printf(err, "bad val size (%zu != %zu)", 41f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_snapshot)); 42f0ac7df2SKent Overstreet return -EINVAL; 43f0ac7df2SKent Overstreet } 4414b393eeSKent Overstreet 4514b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 4614b393eeSKent Overstreet 4714b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 48f0ac7df2SKent Overstreet if (id && id <= k.k->p.offset) { 49401ec4dbSKent Overstreet prt_printf(err, "bad parent node (%u <= %llu)", 50f0ac7df2SKent Overstreet id, k.k->p.offset); 51f0ac7df2SKent Overstreet return -EINVAL; 52f0ac7df2SKent Overstreet } 5314b393eeSKent Overstreet 54f0ac7df2SKent Overstreet if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) { 55401ec4dbSKent Overstreet prt_printf(err, "children not normalized"); 56f0ac7df2SKent Overstreet return -EINVAL; 57f0ac7df2SKent Overstreet } 5814b393eeSKent Overstreet 5914b393eeSKent Overstreet if (s.v->children[0] && 60f0ac7df2SKent Overstreet s.v->children[0] == s.v->children[1]) { 61401ec4dbSKent Overstreet prt_printf(err, "duplicate child nodes"); 62f0ac7df2SKent Overstreet return -EINVAL; 63f0ac7df2SKent Overstreet } 6414b393eeSKent Overstreet 6514b393eeSKent Overstreet for (i = 0; i < 2; i++) { 6614b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 6714b393eeSKent Overstreet 68f0ac7df2SKent Overstreet if (id >= k.k->p.offset) { 69401ec4dbSKent Overstreet prt_printf(err, "bad child node (%u >= %llu)", 70f0ac7df2SKent Overstreet id, k.k->p.offset); 71f0ac7df2SKent Overstreet return -EINVAL; 72f0ac7df2SKent Overstreet } 7314b393eeSKent Overstreet } 7414b393eeSKent Overstreet 75f0ac7df2SKent Overstreet return 0; 7614b393eeSKent Overstreet } 7714b393eeSKent Overstreet 78904823deSKent Overstreet int bch2_mark_snapshot(struct btree_trans *trans, 7914b393eeSKent Overstreet struct bkey_s_c old, struct bkey_s_c new, 80904823deSKent Overstreet unsigned flags) 8114b393eeSKent Overstreet { 82904823deSKent Overstreet struct bch_fs *c = trans->c; 8314b393eeSKent Overstreet struct snapshot_t *t; 8414b393eeSKent Overstreet 8514b393eeSKent Overstreet t = genradix_ptr_alloc(&c->snapshots, 8614b393eeSKent Overstreet U32_MAX - new.k->p.offset, 8714b393eeSKent Overstreet GFP_KERNEL); 8814b393eeSKent Overstreet if (!t) 8914b393eeSKent Overstreet return -ENOMEM; 9014b393eeSKent Overstreet 9114b393eeSKent Overstreet if (new.k->type == KEY_TYPE_snapshot) { 9214b393eeSKent Overstreet struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new); 9314b393eeSKent Overstreet 9414b393eeSKent Overstreet t->parent = le32_to_cpu(s.v->parent); 9514b393eeSKent Overstreet t->children[0] = le32_to_cpu(s.v->children[0]); 9614b393eeSKent Overstreet t->children[1] = le32_to_cpu(s.v->children[1]); 9714b393eeSKent Overstreet t->subvol = BCH_SNAPSHOT_SUBVOL(s.v) ? le32_to_cpu(s.v->subvol) : 0; 9814b393eeSKent Overstreet } else { 9914b393eeSKent Overstreet t->parent = 0; 10014b393eeSKent Overstreet t->children[0] = 0; 10114b393eeSKent Overstreet t->children[1] = 0; 10214b393eeSKent Overstreet t->subvol = 0; 10314b393eeSKent Overstreet } 10414b393eeSKent Overstreet 10514b393eeSKent Overstreet return 0; 10614b393eeSKent Overstreet } 10714b393eeSKent Overstreet 10814b393eeSKent Overstreet static int snapshot_lookup(struct btree_trans *trans, u32 id, 10914b393eeSKent Overstreet struct bch_snapshot *s) 11014b393eeSKent Overstreet { 11114b393eeSKent Overstreet struct btree_iter iter; 11214b393eeSKent Overstreet struct bkey_s_c k; 11314b393eeSKent Overstreet int ret; 11414b393eeSKent Overstreet 11514b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 11614b393eeSKent Overstreet BTREE_ITER_WITH_UPDATES); 11714b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 11814b393eeSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_snapshot ? 0 : -ENOENT; 11914b393eeSKent Overstreet 12014b393eeSKent Overstreet if (!ret) 12114b393eeSKent Overstreet *s = *bkey_s_c_to_snapshot(k).v; 12214b393eeSKent Overstreet 12314b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 12414b393eeSKent Overstreet return ret; 12514b393eeSKent Overstreet } 12614b393eeSKent Overstreet 12714b393eeSKent Overstreet static int snapshot_live(struct btree_trans *trans, u32 id) 12814b393eeSKent Overstreet { 12914b393eeSKent Overstreet struct bch_snapshot v; 13014b393eeSKent Overstreet int ret; 13114b393eeSKent Overstreet 13214b393eeSKent Overstreet if (!id) 13314b393eeSKent Overstreet return 0; 13414b393eeSKent Overstreet 135a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 13614b393eeSKent Overstreet if (ret == -ENOENT) 13714b393eeSKent Overstreet bch_err(trans->c, "snapshot node %u not found", id); 13814b393eeSKent Overstreet if (ret) 13914b393eeSKent Overstreet return ret; 14014b393eeSKent Overstreet 14114b393eeSKent Overstreet return !BCH_SNAPSHOT_DELETED(&v); 14214b393eeSKent Overstreet } 14314b393eeSKent Overstreet 144a1783320SKent Overstreet static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k) 14514b393eeSKent Overstreet { 14614b393eeSKent Overstreet struct bch_fs *c = trans->c; 14735f1a503SKent Overstreet unsigned i, nr_live = 0, live_idx = 0; 148a1783320SKent Overstreet struct bkey_s_c_snapshot snap; 149a1783320SKent Overstreet u32 id = k.k->p.offset, child[2]; 150a1783320SKent Overstreet 151a1783320SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 152a1783320SKent Overstreet return 0; 153a1783320SKent Overstreet 154a1783320SKent Overstreet snap = bkey_s_c_to_snapshot(k); 155a1783320SKent Overstreet 156a1783320SKent Overstreet child[0] = le32_to_cpu(snap.v->children[0]); 157a1783320SKent Overstreet child[1] = le32_to_cpu(snap.v->children[1]); 15814b393eeSKent Overstreet 15914b393eeSKent Overstreet for (i = 0; i < 2; i++) { 16035f1a503SKent Overstreet int ret = snapshot_live(trans, child[i]); 161*a1019576SKent Overstreet 16214b393eeSKent Overstreet if (ret < 0) 16335f1a503SKent Overstreet return ret; 16414b393eeSKent Overstreet 16514b393eeSKent Overstreet if (ret) 16614b393eeSKent Overstreet live_idx = i; 16714b393eeSKent Overstreet nr_live += ret; 16814b393eeSKent Overstreet } 16914b393eeSKent Overstreet 17014b393eeSKent Overstreet snapshot_t(c, id)->equiv = nr_live == 1 17114b393eeSKent Overstreet ? snapshot_t(c, child[live_idx])->equiv 17214b393eeSKent Overstreet : id; 17335f1a503SKent Overstreet return 0; 17414b393eeSKent Overstreet } 17535f1a503SKent Overstreet 17614b393eeSKent Overstreet /* fsck: */ 17735f1a503SKent Overstreet static int check_snapshot(struct btree_trans *trans, 178a1783320SKent Overstreet struct btree_iter *iter, 179a1783320SKent Overstreet struct bkey_s_c k) 18014b393eeSKent Overstreet { 18135f1a503SKent Overstreet struct bch_fs *c = trans->c; 18235f1a503SKent Overstreet struct bkey_s_c_snapshot s; 18314b393eeSKent Overstreet struct bch_subvolume subvol; 18414b393eeSKent Overstreet struct bch_snapshot v; 18535f1a503SKent Overstreet struct printbuf buf = PRINTBUF; 18635f1a503SKent Overstreet bool should_have_subvol; 18714b393eeSKent Overstreet u32 i, id; 18835f1a503SKent Overstreet int ret = 0; 18914b393eeSKent Overstreet 19035f1a503SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 19135f1a503SKent Overstreet return 0; 19214b393eeSKent Overstreet 19335f1a503SKent Overstreet s = bkey_s_c_to_snapshot(k); 19414b393eeSKent Overstreet id = le32_to_cpu(s.v->parent); 19514b393eeSKent Overstreet if (id) { 196a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 19714b393eeSKent Overstreet if (ret == -ENOENT) 19835f1a503SKent Overstreet bch_err(c, "snapshot with nonexistent parent:\n %s", 19935f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf)); 20014b393eeSKent Overstreet if (ret) 20135f1a503SKent Overstreet goto err; 20214b393eeSKent Overstreet 20314b393eeSKent Overstreet if (le32_to_cpu(v.children[0]) != s.k->p.offset && 20414b393eeSKent Overstreet le32_to_cpu(v.children[1]) != s.k->p.offset) { 20535f1a503SKent Overstreet bch_err(c, "snapshot parent %u missing pointer to child %llu", 20614b393eeSKent Overstreet id, s.k->p.offset); 20735f1a503SKent Overstreet ret = -EINVAL; 20835f1a503SKent Overstreet goto err; 20914b393eeSKent Overstreet } 21014b393eeSKent Overstreet } 21114b393eeSKent Overstreet 21214b393eeSKent Overstreet for (i = 0; i < 2 && s.v->children[i]; i++) { 21314b393eeSKent Overstreet id = le32_to_cpu(s.v->children[i]); 21414b393eeSKent Overstreet 215a1783320SKent Overstreet ret = snapshot_lookup(trans, id, &v); 21614b393eeSKent Overstreet if (ret == -ENOENT) 21735f1a503SKent Overstreet bch_err(c, "snapshot node %llu has nonexistent child %u", 21814b393eeSKent Overstreet s.k->p.offset, id); 21914b393eeSKent Overstreet if (ret) 22035f1a503SKent Overstreet goto err; 22114b393eeSKent Overstreet 22214b393eeSKent Overstreet if (le32_to_cpu(v.parent) != s.k->p.offset) { 22335f1a503SKent Overstreet bch_err(c, "snapshot child %u has wrong parent (got %u should be %llu)", 22414b393eeSKent Overstreet id, le32_to_cpu(v.parent), s.k->p.offset); 22535f1a503SKent Overstreet ret = -EINVAL; 22635f1a503SKent Overstreet goto err; 22714b393eeSKent Overstreet } 22814b393eeSKent Overstreet } 22914b393eeSKent Overstreet 23035f1a503SKent Overstreet should_have_subvol = BCH_SNAPSHOT_SUBVOL(s.v) && 23135f1a503SKent Overstreet !BCH_SNAPSHOT_DELETED(s.v); 23235f1a503SKent Overstreet 23335f1a503SKent Overstreet if (should_have_subvol) { 23435f1a503SKent Overstreet id = le32_to_cpu(s.v->subvol); 235a1783320SKent Overstreet ret = bch2_subvolume_get(trans, id, 0, false, &subvol); 23635f1a503SKent Overstreet if (ret == -ENOENT) 23735f1a503SKent Overstreet bch_err(c, "snapshot points to nonexistent subvolume:\n %s", 23835f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf)); 23935f1a503SKent Overstreet if (ret) 24035f1a503SKent Overstreet goto err; 24135f1a503SKent Overstreet 24235f1a503SKent Overstreet if (BCH_SNAPSHOT_SUBVOL(s.v) != (le32_to_cpu(subvol.snapshot) == s.k->p.offset)) { 24335f1a503SKent Overstreet bch_err(c, "snapshot node %llu has wrong BCH_SNAPSHOT_SUBVOL", 24435f1a503SKent Overstreet s.k->p.offset); 24535f1a503SKent Overstreet ret = -EINVAL; 24635f1a503SKent Overstreet goto err; 24735f1a503SKent Overstreet } 24835f1a503SKent Overstreet } else { 24935f1a503SKent Overstreet if (fsck_err_on(s.v->subvol, c, "snapshot should not point to subvol:\n %s", 25035f1a503SKent Overstreet (bch2_bkey_val_to_text(&buf, c, s.s_c), buf.buf))) { 25135f1a503SKent Overstreet struct bkey_i_snapshot *u = bch2_trans_kmalloc(trans, sizeof(*u)); 25235f1a503SKent Overstreet 25335f1a503SKent Overstreet ret = PTR_ERR_OR_ZERO(u); 25435f1a503SKent Overstreet if (ret) 25535f1a503SKent Overstreet goto err; 25635f1a503SKent Overstreet 25735f1a503SKent Overstreet bkey_reassemble(&u->k_i, s.s_c); 25835f1a503SKent Overstreet u->v.subvol = 0; 25935f1a503SKent Overstreet ret = bch2_trans_update(trans, iter, &u->k_i, 0); 26035f1a503SKent Overstreet if (ret) 26135f1a503SKent Overstreet goto err; 26235f1a503SKent Overstreet } 26335f1a503SKent Overstreet } 26435f1a503SKent Overstreet 26535f1a503SKent Overstreet if (BCH_SNAPSHOT_DELETED(s.v)) 26635f1a503SKent Overstreet set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 26735f1a503SKent Overstreet err: 26835f1a503SKent Overstreet fsck_err: 26935f1a503SKent Overstreet printbuf_exit(&buf); 27035f1a503SKent Overstreet return ret; 27114b393eeSKent Overstreet } 27214b393eeSKent Overstreet 2734ab35c34SKent Overstreet int bch2_fs_check_snapshots(struct bch_fs *c) 27414b393eeSKent Overstreet { 27514b393eeSKent Overstreet struct btree_trans trans; 27614b393eeSKent Overstreet struct btree_iter iter; 277a1783320SKent Overstreet struct bkey_s_c k; 27814b393eeSKent Overstreet int ret; 27914b393eeSKent Overstreet 28014b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 28114b393eeSKent Overstreet 282c59d66b5SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, 283c59d66b5SKent Overstreet BTREE_ID_snapshots, POS_MIN, 284a1783320SKent Overstreet BTREE_ITER_PREFETCH, k, 285a1783320SKent Overstreet NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, 286a1783320SKent Overstreet check_snapshot(&trans, &iter, k)); 28714b393eeSKent Overstreet 28835f1a503SKent Overstreet if (ret) 28914b393eeSKent Overstreet bch_err(c, "error %i checking snapshots", ret); 29014b393eeSKent Overstreet 29114b393eeSKent Overstreet bch2_trans_exit(&trans); 29214b393eeSKent Overstreet return ret; 29314b393eeSKent Overstreet } 29414b393eeSKent Overstreet 2954ab35c34SKent Overstreet static int check_subvol(struct btree_trans *trans, 2966738dd19SKent Overstreet struct btree_iter *iter, 2976738dd19SKent Overstreet struct bkey_s_c k) 2984ab35c34SKent Overstreet { 2994ab35c34SKent Overstreet struct bkey_s_c_subvolume subvol; 30035f1a503SKent Overstreet struct bch_snapshot snapshot; 30135f1a503SKent Overstreet unsigned snapid; 3024ab35c34SKent Overstreet int ret; 3034ab35c34SKent Overstreet 3044ab35c34SKent Overstreet if (k.k->type != KEY_TYPE_subvolume) 3054ab35c34SKent Overstreet return 0; 3064ab35c34SKent Overstreet 3074ab35c34SKent Overstreet subvol = bkey_s_c_to_subvolume(k); 30835f1a503SKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 30935f1a503SKent Overstreet ret = snapshot_lookup(trans, snapid, &snapshot); 31035f1a503SKent Overstreet 31135f1a503SKent Overstreet if (ret == -ENOENT) 31235f1a503SKent Overstreet bch_err(trans->c, "subvolume %llu points to nonexistent snapshot %u", 31335f1a503SKent Overstreet k.k->p.offset, snapid); 31435f1a503SKent Overstreet if (ret) 31535f1a503SKent Overstreet return ret; 3164ab35c34SKent Overstreet 3174ab35c34SKent Overstreet if (BCH_SUBVOLUME_UNLINKED(subvol.v)) { 3184ab35c34SKent Overstreet ret = bch2_subvolume_delete(trans, iter->pos.offset); 319549d173cSKent Overstreet if (ret && !bch2_err_matches(ret, BCH_ERR_transaction_restart)) 320d4bf5eecSKent Overstreet bch_err(trans->c, "error deleting subvolume %llu: %s", 321d4bf5eecSKent Overstreet iter->pos.offset, bch2_err_str(ret)); 3224ab35c34SKent Overstreet if (ret) 3234ab35c34SKent Overstreet return ret; 3244ab35c34SKent Overstreet } 3254ab35c34SKent Overstreet 3264ab35c34SKent Overstreet return 0; 3274ab35c34SKent Overstreet } 3284ab35c34SKent Overstreet 3294ab35c34SKent Overstreet int bch2_fs_check_subvols(struct bch_fs *c) 3304ab35c34SKent Overstreet { 3314ab35c34SKent Overstreet struct btree_trans trans; 3324ab35c34SKent Overstreet struct btree_iter iter; 3336738dd19SKent Overstreet struct bkey_s_c k; 3344ab35c34SKent Overstreet int ret; 3354ab35c34SKent Overstreet 33635f1a503SKent Overstreet bch2_trans_init(&trans, c, 0, 0); 3374ab35c34SKent Overstreet 3386738dd19SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, 3396738dd19SKent Overstreet BTREE_ID_subvolumes, POS_MIN, BTREE_ITER_PREFETCH, k, 3406738dd19SKent Overstreet NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, 3416738dd19SKent Overstreet check_subvol(&trans, &iter, k)); 3424ab35c34SKent Overstreet 3434ab35c34SKent Overstreet bch2_trans_exit(&trans); 3444ab35c34SKent Overstreet 3454ab35c34SKent Overstreet return ret; 3464ab35c34SKent Overstreet } 3474ab35c34SKent Overstreet 34814b393eeSKent Overstreet void bch2_fs_snapshots_exit(struct bch_fs *c) 34914b393eeSKent Overstreet { 35014b393eeSKent Overstreet genradix_free(&c->snapshots); 35114b393eeSKent Overstreet } 35214b393eeSKent Overstreet 35314b393eeSKent Overstreet int bch2_fs_snapshots_start(struct bch_fs *c) 35414b393eeSKent Overstreet { 35514b393eeSKent Overstreet struct btree_trans trans; 35614b393eeSKent Overstreet struct btree_iter iter; 35714b393eeSKent Overstreet struct bkey_s_c k; 35814b393eeSKent Overstreet int ret = 0; 35914b393eeSKent Overstreet 36014b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 36114b393eeSKent Overstreet 362a1783320SKent Overstreet for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, 363a1783320SKent Overstreet POS_MIN, 0, k, 364a1783320SKent Overstreet bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0) ?: 365a1783320SKent Overstreet bch2_snapshot_set_equiv(&trans, k)); 36614b393eeSKent Overstreet 36714b393eeSKent Overstreet bch2_trans_exit(&trans); 36835f1a503SKent Overstreet 36935f1a503SKent Overstreet if (ret) 370d4bf5eecSKent Overstreet bch_err(c, "error starting snapshots: %s", bch2_err_str(ret)); 37114b393eeSKent Overstreet return ret; 37214b393eeSKent Overstreet } 37314b393eeSKent Overstreet 37414b393eeSKent Overstreet /* 37514b393eeSKent Overstreet * Mark a snapshot as deleted, for future cleanup: 37614b393eeSKent Overstreet */ 37714b393eeSKent Overstreet static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id) 37814b393eeSKent Overstreet { 37914b393eeSKent Overstreet struct btree_iter iter; 38014b393eeSKent Overstreet struct bkey_s_c k; 38114b393eeSKent Overstreet struct bkey_i_snapshot *s; 38214b393eeSKent Overstreet int ret = 0; 38314b393eeSKent Overstreet 38414b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 38514b393eeSKent Overstreet BTREE_ITER_INTENT); 38614b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 38714b393eeSKent Overstreet ret = bkey_err(k); 38814b393eeSKent Overstreet if (ret) 38914b393eeSKent Overstreet goto err; 39014b393eeSKent Overstreet 39114b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 39214b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); 39314b393eeSKent Overstreet ret = -ENOENT; 39414b393eeSKent Overstreet goto err; 39514b393eeSKent Overstreet } 39614b393eeSKent Overstreet 39714b393eeSKent Overstreet /* already deleted? */ 39814b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) 39914b393eeSKent Overstreet goto err; 40014b393eeSKent Overstreet 40114b393eeSKent Overstreet s = bch2_trans_kmalloc(trans, sizeof(*s)); 40214b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(s); 40314b393eeSKent Overstreet if (ret) 40414b393eeSKent Overstreet goto err; 40514b393eeSKent Overstreet 40614b393eeSKent Overstreet bkey_reassemble(&s->k_i, k); 40714b393eeSKent Overstreet SET_BCH_SNAPSHOT_DELETED(&s->v, true); 408416cc426SKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&s->v, false); 409416cc426SKent Overstreet s->v.subvol = 0; 410416cc426SKent Overstreet 41114b393eeSKent Overstreet ret = bch2_trans_update(trans, &iter, &s->k_i, 0); 41214b393eeSKent Overstreet if (ret) 41314b393eeSKent Overstreet goto err; 41414b393eeSKent Overstreet err: 41514b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 41614b393eeSKent Overstreet return ret; 41714b393eeSKent Overstreet } 41814b393eeSKent Overstreet 41914b393eeSKent Overstreet static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) 42014b393eeSKent Overstreet { 42114b393eeSKent Overstreet struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; 42214b393eeSKent Overstreet struct bkey_s_c k; 42314b393eeSKent Overstreet struct bkey_s_c_snapshot s; 42414b393eeSKent Overstreet struct bkey_i_snapshot *parent; 42514b393eeSKent Overstreet u32 parent_id; 42614b393eeSKent Overstreet unsigned i; 42714b393eeSKent Overstreet int ret = 0; 42814b393eeSKent Overstreet 42914b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), 43014b393eeSKent Overstreet BTREE_ITER_INTENT); 43114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&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", id); 43814b393eeSKent Overstreet ret = -ENOENT; 43914b393eeSKent Overstreet goto err; 44014b393eeSKent Overstreet } 44114b393eeSKent Overstreet 44214b393eeSKent Overstreet s = bkey_s_c_to_snapshot(k); 44314b393eeSKent Overstreet 44414b393eeSKent Overstreet BUG_ON(!BCH_SNAPSHOT_DELETED(s.v)); 44514b393eeSKent Overstreet parent_id = le32_to_cpu(s.v->parent); 44614b393eeSKent Overstreet 44714b393eeSKent Overstreet if (parent_id) { 44814b393eeSKent Overstreet bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots, 44914b393eeSKent Overstreet POS(0, parent_id), 45014b393eeSKent Overstreet BTREE_ITER_INTENT); 45114b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&p_iter); 45214b393eeSKent Overstreet ret = bkey_err(k); 45314b393eeSKent Overstreet if (ret) 45414b393eeSKent Overstreet goto err; 45514b393eeSKent Overstreet 45614b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 45714b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id); 45814b393eeSKent Overstreet ret = -ENOENT; 45914b393eeSKent Overstreet goto err; 46014b393eeSKent Overstreet } 46114b393eeSKent Overstreet 46214b393eeSKent Overstreet parent = bch2_trans_kmalloc(trans, sizeof(*parent)); 46314b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(parent); 46414b393eeSKent Overstreet if (ret) 46514b393eeSKent Overstreet goto err; 46614b393eeSKent Overstreet 46714b393eeSKent Overstreet bkey_reassemble(&parent->k_i, k); 46814b393eeSKent Overstreet 46914b393eeSKent Overstreet for (i = 0; i < 2; i++) 47014b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[i]) == id) 47114b393eeSKent Overstreet break; 47214b393eeSKent Overstreet 47314b393eeSKent Overstreet if (i == 2) 47414b393eeSKent Overstreet bch_err(trans->c, "snapshot %u missing child pointer to %u", 47514b393eeSKent Overstreet parent_id, id); 47614b393eeSKent Overstreet else 47714b393eeSKent Overstreet parent->v.children[i] = 0; 47814b393eeSKent Overstreet 47914b393eeSKent Overstreet if (le32_to_cpu(parent->v.children[0]) < 48014b393eeSKent Overstreet le32_to_cpu(parent->v.children[1])) 48114b393eeSKent Overstreet swap(parent->v.children[0], 48214b393eeSKent Overstreet parent->v.children[1]); 48314b393eeSKent Overstreet 48414b393eeSKent Overstreet ret = bch2_trans_update(trans, &p_iter, &parent->k_i, 0); 48514b393eeSKent Overstreet if (ret) 48614b393eeSKent Overstreet goto err; 48714b393eeSKent Overstreet } 48814b393eeSKent Overstreet 48914b393eeSKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 49014b393eeSKent Overstreet err: 49114b393eeSKent Overstreet bch2_trans_iter_exit(trans, &p_iter); 49214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 49314b393eeSKent Overstreet return ret; 49414b393eeSKent Overstreet } 49514b393eeSKent Overstreet 4967f6ff935SKent Overstreet int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, 49714b393eeSKent Overstreet u32 *new_snapids, 49814b393eeSKent Overstreet u32 *snapshot_subvols, 49914b393eeSKent Overstreet unsigned nr_snapids) 50014b393eeSKent Overstreet { 50114b393eeSKent Overstreet struct btree_iter iter; 50214b393eeSKent Overstreet struct bkey_i_snapshot *n; 50314b393eeSKent Overstreet struct bkey_s_c k; 50414b393eeSKent Overstreet unsigned i; 50514b393eeSKent Overstreet int ret = 0; 50614b393eeSKent Overstreet 50714b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, 50814b393eeSKent Overstreet POS_MIN, BTREE_ITER_INTENT); 50914b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 51014b393eeSKent Overstreet ret = bkey_err(k); 51114b393eeSKent Overstreet if (ret) 51214b393eeSKent Overstreet goto err; 51314b393eeSKent Overstreet 51414b393eeSKent Overstreet for (i = 0; i < nr_snapids; i++) { 51514b393eeSKent Overstreet k = bch2_btree_iter_prev_slot(&iter); 51614b393eeSKent Overstreet ret = bkey_err(k); 51714b393eeSKent Overstreet if (ret) 51814b393eeSKent Overstreet goto err; 51914b393eeSKent Overstreet 52014b393eeSKent Overstreet if (!k.k || !k.k->p.offset) { 521098ef98dSKent Overstreet ret = -BCH_ERR_ENOSPC_snapshot_create; 52214b393eeSKent Overstreet goto err; 52314b393eeSKent Overstreet } 52414b393eeSKent Overstreet 52514b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 52614b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 52714b393eeSKent Overstreet if (ret) 52894a3e1a6SKent Overstreet goto err; 52914b393eeSKent Overstreet 53014b393eeSKent Overstreet bkey_snapshot_init(&n->k_i); 53114b393eeSKent Overstreet n->k.p = iter.pos; 53214b393eeSKent Overstreet n->v.flags = 0; 53314b393eeSKent Overstreet n->v.parent = cpu_to_le32(parent); 53414b393eeSKent Overstreet n->v.subvol = cpu_to_le32(snapshot_subvols[i]); 53514b393eeSKent Overstreet n->v.pad = 0; 53614b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, true); 53714b393eeSKent Overstreet 53894a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0) ?: 53994a3e1a6SKent Overstreet bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); 54014b393eeSKent Overstreet if (ret) 54194a3e1a6SKent Overstreet goto err; 54214b393eeSKent Overstreet 54314b393eeSKent Overstreet new_snapids[i] = iter.pos.offset; 54414b393eeSKent Overstreet } 54514b393eeSKent Overstreet 54614b393eeSKent Overstreet if (parent) { 54714b393eeSKent Overstreet bch2_btree_iter_set_pos(&iter, POS(0, parent)); 54814b393eeSKent Overstreet k = bch2_btree_iter_peek(&iter); 54914b393eeSKent Overstreet ret = bkey_err(k); 55014b393eeSKent Overstreet if (ret) 55114b393eeSKent Overstreet goto err; 55214b393eeSKent Overstreet 55314b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) { 55414b393eeSKent Overstreet bch_err(trans->c, "snapshot %u not found", parent); 55514b393eeSKent Overstreet ret = -ENOENT; 55614b393eeSKent Overstreet goto err; 55714b393eeSKent Overstreet } 55814b393eeSKent Overstreet 55914b393eeSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 56014b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 56114b393eeSKent Overstreet if (ret) 562c4ecf802SKent Overstreet goto err; 56314b393eeSKent Overstreet 56414b393eeSKent Overstreet bkey_reassemble(&n->k_i, k); 56514b393eeSKent Overstreet 56614b393eeSKent Overstreet if (n->v.children[0] || n->v.children[1]) { 56714b393eeSKent Overstreet bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children"); 56814b393eeSKent Overstreet ret = -EINVAL; 56914b393eeSKent Overstreet goto err; 57014b393eeSKent Overstreet } 57114b393eeSKent Overstreet 57214b393eeSKent Overstreet n->v.children[0] = cpu_to_le32(new_snapids[0]); 57314b393eeSKent Overstreet n->v.children[1] = cpu_to_le32(new_snapids[1]); 57435f1a503SKent Overstreet n->v.subvol = 0; 57514b393eeSKent Overstreet SET_BCH_SNAPSHOT_SUBVOL(&n->v, false); 57694a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 57794a3e1a6SKent Overstreet if (ret) 57894a3e1a6SKent Overstreet goto err; 57914b393eeSKent Overstreet } 58014b393eeSKent Overstreet err: 58114b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 58214b393eeSKent Overstreet return ret; 58314b393eeSKent Overstreet } 58414b393eeSKent Overstreet 5856738dd19SKent Overstreet static int snapshot_delete_key(struct btree_trans *trans, 5866738dd19SKent Overstreet struct btree_iter *iter, 5876738dd19SKent Overstreet struct bkey_s_c k, 58891d961baSKent Overstreet snapshot_id_list *deleted, 5896738dd19SKent Overstreet snapshot_id_list *equiv_seen, 5906738dd19SKent Overstreet struct bpos *last_pos) 59114b393eeSKent Overstreet { 59214b393eeSKent Overstreet struct bch_fs *c = trans->c; 59314b393eeSKent Overstreet u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv; 59414b393eeSKent Overstreet 5956738dd19SKent Overstreet if (bkey_cmp(k.k->p, *last_pos)) 5966738dd19SKent Overstreet equiv_seen->nr = 0; 5976738dd19SKent Overstreet *last_pos = k.k->p; 59814b393eeSKent Overstreet 59914b393eeSKent Overstreet if (snapshot_list_has_id(deleted, k.k->p.snapshot) || 6006738dd19SKent Overstreet snapshot_list_has_id(equiv_seen, equiv)) { 6016738dd19SKent Overstreet return bch2_btree_delete_at(trans, iter, 6026738dd19SKent Overstreet BTREE_UPDATE_INTERNAL_SNAPSHOT_NODE); 60314b393eeSKent Overstreet } else { 6046738dd19SKent Overstreet return snapshot_list_add(c, equiv_seen, equiv); 60514b393eeSKent Overstreet } 60614b393eeSKent Overstreet } 60714b393eeSKent Overstreet 608a1783320SKent Overstreet static int bch2_delete_redundant_snapshot(struct btree_trans *trans, struct btree_iter *iter, 609a1783320SKent Overstreet struct bkey_s_c k) 610a1783320SKent Overstreet { 611a1783320SKent Overstreet struct bkey_s_c_snapshot snap; 612a1783320SKent Overstreet u32 children[2]; 613a1783320SKent Overstreet int ret; 614a1783320SKent Overstreet 615a1783320SKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 616a1783320SKent Overstreet return 0; 617a1783320SKent Overstreet 618a1783320SKent Overstreet snap = bkey_s_c_to_snapshot(k); 619a1783320SKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v) || 620a1783320SKent Overstreet BCH_SNAPSHOT_SUBVOL(snap.v)) 621a1783320SKent Overstreet return 0; 622a1783320SKent Overstreet 623a1783320SKent Overstreet children[0] = le32_to_cpu(snap.v->children[0]); 624a1783320SKent Overstreet children[1] = le32_to_cpu(snap.v->children[1]); 625a1783320SKent Overstreet 626a1783320SKent Overstreet ret = snapshot_live(trans, children[0]) ?: 627a1783320SKent Overstreet snapshot_live(trans, children[1]); 628a1783320SKent Overstreet if (ret < 0) 629a1783320SKent Overstreet return ret; 630a1783320SKent Overstreet 631a1783320SKent Overstreet if (!ret) 632a1783320SKent Overstreet return bch2_snapshot_node_set_deleted(trans, k.k->p.offset); 633a1783320SKent Overstreet return 0; 634a1783320SKent Overstreet } 635a1783320SKent Overstreet 6364ab35c34SKent Overstreet int bch2_delete_dead_snapshots(struct bch_fs *c) 63714b393eeSKent Overstreet { 63814b393eeSKent Overstreet struct btree_trans trans; 63914b393eeSKent Overstreet struct btree_iter iter; 64014b393eeSKent Overstreet struct bkey_s_c k; 64114b393eeSKent Overstreet struct bkey_s_c_snapshot snap; 64291d961baSKent Overstreet snapshot_id_list deleted = { 0 }; 643a1783320SKent Overstreet u32 i, id; 64414b393eeSKent Overstreet int ret = 0; 64514b393eeSKent Overstreet 6464ab35c34SKent Overstreet if (!test_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags)) 6474ab35c34SKent Overstreet return 0; 6484ab35c34SKent Overstreet 6494ab35c34SKent Overstreet if (!test_bit(BCH_FS_STARTED, &c->flags)) { 6504ab35c34SKent Overstreet ret = bch2_fs_read_write_early(c); 6514ab35c34SKent Overstreet if (ret) { 652d4bf5eecSKent Overstreet bch_err(c, "error deleleting dead snapshots: error going rw: %s", bch2_err_str(ret)); 6534ab35c34SKent Overstreet return ret; 6544ab35c34SKent Overstreet } 6554ab35c34SKent Overstreet } 6564ab35c34SKent Overstreet 65714b393eeSKent Overstreet bch2_trans_init(&trans, c, 0, 0); 65814b393eeSKent Overstreet 65914b393eeSKent Overstreet /* 66014b393eeSKent Overstreet * For every snapshot node: If we have no live children and it's not 66114b393eeSKent Overstreet * pointed to by a subvolume, delete it: 66214b393eeSKent Overstreet */ 663a1783320SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, 664a1783320SKent Overstreet POS_MIN, 0, k, 665a1783320SKent Overstreet NULL, NULL, 0, 666a1783320SKent Overstreet bch2_delete_redundant_snapshot(&trans, &iter, k)); 66714b393eeSKent Overstreet if (ret) { 668d4bf5eecSKent Overstreet bch_err(c, "error deleting redundant snapshots: %s", bch2_err_str(ret)); 66914b393eeSKent Overstreet goto err; 67014b393eeSKent Overstreet } 67114b393eeSKent Overstreet 672a1783320SKent Overstreet for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, 673a1783320SKent Overstreet POS_MIN, 0, k, 674a1783320SKent Overstreet bch2_snapshot_set_equiv(&trans, k)); 675a1783320SKent Overstreet if (ret) { 676d4bf5eecSKent Overstreet bch_err(c, "error in bch2_snapshots_set_equiv: %s", bch2_err_str(ret)); 67714b393eeSKent Overstreet goto err; 678a1783320SKent Overstreet } 67914b393eeSKent Overstreet 68014b393eeSKent Overstreet for_each_btree_key(&trans, iter, BTREE_ID_snapshots, 68114b393eeSKent Overstreet POS_MIN, 0, k, ret) { 68214b393eeSKent Overstreet if (k.k->type != KEY_TYPE_snapshot) 68314b393eeSKent Overstreet continue; 68414b393eeSKent Overstreet 68514b393eeSKent Overstreet snap = bkey_s_c_to_snapshot(k); 68614b393eeSKent Overstreet if (BCH_SNAPSHOT_DELETED(snap.v)) { 687597dee1cSKent Overstreet ret = snapshot_list_add(c, &deleted, k.k->p.offset); 68814b393eeSKent Overstreet if (ret) 68914b393eeSKent Overstreet break; 69014b393eeSKent Overstreet } 69114b393eeSKent Overstreet } 69214b393eeSKent Overstreet bch2_trans_iter_exit(&trans, &iter); 69314b393eeSKent Overstreet 69414b393eeSKent Overstreet if (ret) { 695d4bf5eecSKent Overstreet bch_err(c, "error walking snapshots: %s", bch2_err_str(ret)); 69614b393eeSKent Overstreet goto err; 69714b393eeSKent Overstreet } 69814b393eeSKent Overstreet 69914b393eeSKent Overstreet for (id = 0; id < BTREE_ID_NR; id++) { 7006738dd19SKent Overstreet struct bpos last_pos = POS_MIN; 7016738dd19SKent Overstreet snapshot_id_list equiv_seen = { 0 }; 7026738dd19SKent Overstreet 70314b393eeSKent Overstreet if (!btree_type_has_snapshots(id)) 70414b393eeSKent Overstreet continue; 70514b393eeSKent Overstreet 7066738dd19SKent Overstreet ret = for_each_btree_key_commit(&trans, iter, 7076738dd19SKent Overstreet id, POS_MIN, 7086738dd19SKent Overstreet BTREE_ITER_PREFETCH|BTREE_ITER_ALL_SNAPSHOTS, k, 7096738dd19SKent Overstreet NULL, NULL, BTREE_INSERT_NOFAIL, 7106738dd19SKent Overstreet snapshot_delete_key(&trans, &iter, k, &deleted, &equiv_seen, &last_pos)); 7116738dd19SKent Overstreet 7126738dd19SKent Overstreet darray_exit(&equiv_seen); 7136738dd19SKent Overstreet 71414b393eeSKent Overstreet if (ret) { 715d4bf5eecSKent Overstreet bch_err(c, "error deleting snapshot keys: %s", bch2_err_str(ret)); 71614b393eeSKent Overstreet goto err; 71714b393eeSKent Overstreet } 71814b393eeSKent Overstreet } 71914b393eeSKent Overstreet 72014b393eeSKent Overstreet for (i = 0; i < deleted.nr; i++) { 721e68914caSKent Overstreet ret = commit_do(&trans, NULL, NULL, 0, 72291d961baSKent Overstreet bch2_snapshot_node_delete(&trans, deleted.data[i])); 72314b393eeSKent Overstreet if (ret) { 724d4bf5eecSKent Overstreet bch_err(c, "error deleting snapshot %u: %s", 725d4bf5eecSKent Overstreet deleted.data[i], bch2_err_str(ret)); 72614b393eeSKent Overstreet goto err; 72714b393eeSKent Overstreet } 72814b393eeSKent Overstreet } 7294ab35c34SKent Overstreet 7304ab35c34SKent Overstreet clear_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 73114b393eeSKent Overstreet err: 73291d961baSKent Overstreet darray_exit(&deleted); 73314b393eeSKent Overstreet bch2_trans_exit(&trans); 7344ab35c34SKent Overstreet return ret; 7354ab35c34SKent Overstreet } 7364ab35c34SKent Overstreet 7374ab35c34SKent Overstreet static void bch2_delete_dead_snapshots_work(struct work_struct *work) 7384ab35c34SKent Overstreet { 7394ab35c34SKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work); 7404ab35c34SKent Overstreet 7414ab35c34SKent Overstreet bch2_delete_dead_snapshots(c); 74214b393eeSKent Overstreet percpu_ref_put(&c->writes); 74314b393eeSKent Overstreet } 74414b393eeSKent Overstreet 7454ab35c34SKent Overstreet void bch2_delete_dead_snapshots_async(struct bch_fs *c) 74614b393eeSKent Overstreet { 7474ab35c34SKent Overstreet if (!percpu_ref_tryget_live(&c->writes)) 74814b393eeSKent Overstreet return; 74914b393eeSKent Overstreet 75014b393eeSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_delete_work)) 75114b393eeSKent Overstreet percpu_ref_put(&c->writes); 75214b393eeSKent Overstreet } 75314b393eeSKent Overstreet 75414b393eeSKent Overstreet static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, 75514b393eeSKent Overstreet struct btree_trans_commit_hook *h) 75614b393eeSKent Overstreet { 7574ab35c34SKent Overstreet struct bch_fs *c = trans->c; 7584ab35c34SKent Overstreet 7594ab35c34SKent Overstreet set_bit(BCH_FS_HAVE_DELETED_SNAPSHOTS, &c->flags); 7604ab35c34SKent Overstreet 7614ab35c34SKent Overstreet if (!test_bit(BCH_FS_FSCK_DONE, &c->flags)) 7624ab35c34SKent Overstreet return 0; 7634ab35c34SKent Overstreet 7644ab35c34SKent Overstreet bch2_delete_dead_snapshots_async(c); 76514b393eeSKent Overstreet return 0; 76614b393eeSKent Overstreet } 76714b393eeSKent Overstreet 76814b393eeSKent Overstreet /* Subvolumes: */ 76914b393eeSKent Overstreet 770f0ac7df2SKent Overstreet int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, 771275c8426SKent Overstreet int rw, struct printbuf *err) 77214b393eeSKent Overstreet { 773f0ac7df2SKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 || 774f0ac7df2SKent Overstreet bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) { 775401ec4dbSKent Overstreet prt_printf(err, "invalid pos"); 776f0ac7df2SKent Overstreet return -EINVAL; 777f0ac7df2SKent Overstreet } 77814b393eeSKent Overstreet 779f0ac7df2SKent Overstreet if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) { 780401ec4dbSKent Overstreet prt_printf(err, "incorrect value size (%zu != %zu)", 781f0ac7df2SKent Overstreet bkey_val_bytes(k.k), sizeof(struct bch_subvolume)); 782f0ac7df2SKent Overstreet return -EINVAL; 783f0ac7df2SKent Overstreet } 78414b393eeSKent Overstreet 785f0ac7df2SKent Overstreet return 0; 78614b393eeSKent Overstreet } 78714b393eeSKent Overstreet 78814b393eeSKent Overstreet void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, 78914b393eeSKent Overstreet struct bkey_s_c k) 79014b393eeSKent Overstreet { 79114b393eeSKent Overstreet struct bkey_s_c_subvolume s = bkey_s_c_to_subvolume(k); 79214b393eeSKent Overstreet 793401ec4dbSKent Overstreet prt_printf(out, "root %llu snapshot id %u", 79414b393eeSKent Overstreet le64_to_cpu(s.v->inode), 79514b393eeSKent Overstreet le32_to_cpu(s.v->snapshot)); 79614b393eeSKent Overstreet } 79714b393eeSKent Overstreet 79897996ddfSKent Overstreet int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, 79997996ddfSKent Overstreet bool inconsistent_if_not_found, 80097996ddfSKent Overstreet int iter_flags, 80197996ddfSKent Overstreet struct bch_subvolume *s) 80214b393eeSKent Overstreet { 80314b393eeSKent Overstreet struct btree_iter iter; 80414b393eeSKent Overstreet struct bkey_s_c k; 80514b393eeSKent Overstreet int ret; 80614b393eeSKent Overstreet 80797996ddfSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, POS(0, subvol), 80897996ddfSKent Overstreet iter_flags); 80914b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 81097996ddfSKent Overstreet ret = bkey_err(k) ?: k.k->type == KEY_TYPE_subvolume ? 0 : -ENOENT; 81114b393eeSKent Overstreet 81297996ddfSKent Overstreet if (ret == -ENOENT && inconsistent_if_not_found) 81314b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvol); 81497996ddfSKent Overstreet if (!ret) 81597996ddfSKent Overstreet *s = *bkey_s_c_to_subvolume(k).v; 81697996ddfSKent Overstreet 81797996ddfSKent Overstreet bch2_trans_iter_exit(trans, &iter); 81897996ddfSKent Overstreet return ret; 81914b393eeSKent Overstreet } 82014b393eeSKent Overstreet 8219ca4853bSKent Overstreet int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot, 8229ca4853bSKent Overstreet struct bch_subvolume *subvol) 8239ca4853bSKent Overstreet { 8249ca4853bSKent Overstreet struct bch_snapshot snap; 8259ca4853bSKent Overstreet 8269ca4853bSKent Overstreet return snapshot_lookup(trans, snapshot, &snap) ?: 8279ca4853bSKent Overstreet bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol); 8289ca4853bSKent Overstreet } 8299ca4853bSKent Overstreet 83097996ddfSKent Overstreet int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol, 83197996ddfSKent Overstreet u32 *snapid) 83297996ddfSKent Overstreet { 83397996ddfSKent Overstreet struct bch_subvolume s; 83497996ddfSKent Overstreet int ret; 83597996ddfSKent Overstreet 83697996ddfSKent Overstreet ret = bch2_subvolume_get(trans, subvol, true, 83797996ddfSKent Overstreet BTREE_ITER_CACHED| 83897996ddfSKent Overstreet BTREE_ITER_WITH_UPDATES, 83997996ddfSKent Overstreet &s); 84097996ddfSKent Overstreet 84197996ddfSKent Overstreet *snapid = le32_to_cpu(s.snapshot); 84214b393eeSKent Overstreet return ret; 84314b393eeSKent Overstreet } 84414b393eeSKent Overstreet 8452027875bSKent Overstreet /* 8462027875bSKent Overstreet * Delete subvolume, mark snapshot ID as deleted, queue up snapshot 8472027875bSKent Overstreet * deletion/cleanup: 8482027875bSKent Overstreet */ 8492027875bSKent Overstreet int bch2_subvolume_delete(struct btree_trans *trans, u32 subvolid) 85014b393eeSKent Overstreet { 85114b393eeSKent Overstreet struct btree_iter iter; 85214b393eeSKent Overstreet struct bkey_s_c k; 85314b393eeSKent Overstreet struct bkey_s_c_subvolume subvol; 85414b393eeSKent Overstreet struct btree_trans_commit_hook *h; 85514b393eeSKent Overstreet u32 snapid; 85614b393eeSKent Overstreet int ret = 0; 85714b393eeSKent Overstreet 85814b393eeSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 85914b393eeSKent Overstreet POS(0, subvolid), 86014b393eeSKent Overstreet BTREE_ITER_CACHED| 86114b393eeSKent Overstreet BTREE_ITER_INTENT); 86214b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 86314b393eeSKent Overstreet ret = bkey_err(k); 86414b393eeSKent Overstreet if (ret) 86514b393eeSKent Overstreet goto err; 86614b393eeSKent Overstreet 86714b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 86814b393eeSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 86914b393eeSKent Overstreet ret = -EIO; 87014b393eeSKent Overstreet goto err; 87114b393eeSKent Overstreet } 87214b393eeSKent Overstreet 87314b393eeSKent Overstreet subvol = bkey_s_c_to_subvolume(k); 87414b393eeSKent Overstreet snapid = le32_to_cpu(subvol.v->snapshot); 87514b393eeSKent Overstreet 876416cc426SKent Overstreet ret = bch2_btree_delete_at(trans, &iter, 0); 87714b393eeSKent Overstreet if (ret) 87814b393eeSKent Overstreet goto err; 87914b393eeSKent Overstreet 88014b393eeSKent Overstreet ret = bch2_snapshot_node_set_deleted(trans, snapid); 88131301dd4SKent Overstreet if (ret) 88231301dd4SKent Overstreet goto err; 88314b393eeSKent Overstreet 88414b393eeSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 88514b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 88614b393eeSKent Overstreet if (ret) 88714b393eeSKent Overstreet goto err; 88814b393eeSKent Overstreet 88914b393eeSKent Overstreet h->fn = bch2_delete_dead_snapshots_hook; 89014b393eeSKent Overstreet bch2_trans_commit_hook(trans, h); 89114b393eeSKent Overstreet err: 89214b393eeSKent Overstreet bch2_trans_iter_exit(trans, &iter); 89314b393eeSKent Overstreet return ret; 89414b393eeSKent Overstreet } 89514b393eeSKent Overstreet 8962027875bSKent Overstreet void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) 8972027875bSKent Overstreet { 8982027875bSKent Overstreet struct bch_fs *c = container_of(work, struct bch_fs, 8992027875bSKent Overstreet snapshot_wait_for_pagecache_and_delete_work); 90091d961baSKent Overstreet snapshot_id_list s; 9012027875bSKent Overstreet u32 *id; 9022027875bSKent Overstreet int ret = 0; 9032027875bSKent Overstreet 9042027875bSKent Overstreet while (!ret) { 9052027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9062027875bSKent Overstreet s = c->snapshots_unlinked; 90791d961baSKent Overstreet darray_init(&c->snapshots_unlinked); 9082027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9092027875bSKent Overstreet 9102027875bSKent Overstreet if (!s.nr) 9112027875bSKent Overstreet break; 9122027875bSKent Overstreet 9132027875bSKent Overstreet bch2_evict_subvolume_inodes(c, &s); 9142027875bSKent Overstreet 91591d961baSKent Overstreet for (id = s.data; id < s.data + s.nr; id++) { 9162027875bSKent Overstreet ret = bch2_trans_do(c, NULL, NULL, BTREE_INSERT_NOFAIL, 9172027875bSKent Overstreet bch2_subvolume_delete(&trans, *id)); 9182027875bSKent Overstreet if (ret) { 919d4bf5eecSKent Overstreet bch_err(c, "error deleting subvolume %u: %s", *id, bch2_err_str(ret)); 9202027875bSKent Overstreet break; 9212027875bSKent Overstreet } 9222027875bSKent Overstreet } 9232027875bSKent Overstreet 92491d961baSKent Overstreet darray_exit(&s); 9252027875bSKent Overstreet } 9262027875bSKent Overstreet 9272027875bSKent Overstreet percpu_ref_put(&c->writes); 9282027875bSKent Overstreet } 9292027875bSKent Overstreet 9302027875bSKent Overstreet struct subvolume_unlink_hook { 9312027875bSKent Overstreet struct btree_trans_commit_hook h; 9322027875bSKent Overstreet u32 subvol; 9332027875bSKent Overstreet }; 9342027875bSKent Overstreet 9352027875bSKent Overstreet int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, 9362027875bSKent Overstreet struct btree_trans_commit_hook *_h) 9372027875bSKent Overstreet { 9382027875bSKent Overstreet struct subvolume_unlink_hook *h = container_of(_h, struct subvolume_unlink_hook, h); 9392027875bSKent Overstreet struct bch_fs *c = trans->c; 9402027875bSKent Overstreet int ret = 0; 9412027875bSKent Overstreet 9422027875bSKent Overstreet mutex_lock(&c->snapshots_unlinked_lock); 9432027875bSKent Overstreet if (!snapshot_list_has_id(&c->snapshots_unlinked, h->subvol)) 944597dee1cSKent Overstreet ret = snapshot_list_add(c, &c->snapshots_unlinked, h->subvol); 9452027875bSKent Overstreet mutex_unlock(&c->snapshots_unlinked_lock); 9462027875bSKent Overstreet 9472027875bSKent Overstreet if (ret) 9482027875bSKent Overstreet return ret; 9492027875bSKent Overstreet 950a3d7afa5SKent Overstreet if (unlikely(!percpu_ref_tryget_live(&c->writes))) 9512027875bSKent Overstreet return -EROFS; 9522027875bSKent Overstreet 9532027875bSKent Overstreet if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work)) 9542027875bSKent Overstreet percpu_ref_put(&c->writes); 9552027875bSKent Overstreet return 0; 9562027875bSKent Overstreet } 9572027875bSKent Overstreet 9582027875bSKent Overstreet int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) 9592027875bSKent Overstreet { 9602027875bSKent Overstreet struct btree_iter iter; 9612027875bSKent Overstreet struct bkey_s_c k; 9622027875bSKent Overstreet struct bkey_i_subvolume *n; 9632027875bSKent Overstreet struct subvolume_unlink_hook *h; 9642027875bSKent Overstreet int ret = 0; 9652027875bSKent Overstreet 9662027875bSKent Overstreet bch2_trans_iter_init(trans, &iter, BTREE_ID_subvolumes, 9672027875bSKent Overstreet POS(0, subvolid), 9682027875bSKent Overstreet BTREE_ITER_CACHED| 9692027875bSKent Overstreet BTREE_ITER_INTENT); 9702027875bSKent Overstreet k = bch2_btree_iter_peek_slot(&iter); 9712027875bSKent Overstreet ret = bkey_err(k); 9722027875bSKent Overstreet if (ret) 9732027875bSKent Overstreet goto err; 9742027875bSKent Overstreet 9752027875bSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 9762027875bSKent Overstreet bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); 9772027875bSKent Overstreet ret = -EIO; 9782027875bSKent Overstreet goto err; 9792027875bSKent Overstreet } 9802027875bSKent Overstreet 9812027875bSKent Overstreet n = bch2_trans_kmalloc(trans, sizeof(*n)); 9822027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(n); 9832027875bSKent Overstreet if (ret) 9842027875bSKent Overstreet goto err; 9852027875bSKent Overstreet 9862027875bSKent Overstreet bkey_reassemble(&n->k_i, k); 9872027875bSKent Overstreet SET_BCH_SUBVOLUME_UNLINKED(&n->v, true); 9882027875bSKent Overstreet 9892027875bSKent Overstreet ret = bch2_trans_update(trans, &iter, &n->k_i, 0); 9902027875bSKent Overstreet if (ret) 9912027875bSKent Overstreet goto err; 9922027875bSKent Overstreet 9932027875bSKent Overstreet h = bch2_trans_kmalloc(trans, sizeof(*h)); 9942027875bSKent Overstreet ret = PTR_ERR_OR_ZERO(h); 9952027875bSKent Overstreet if (ret) 9962027875bSKent Overstreet goto err; 9972027875bSKent Overstreet 9982027875bSKent Overstreet h->h.fn = bch2_subvolume_wait_for_pagecache_and_delete_hook; 9992027875bSKent Overstreet h->subvol = subvolid; 10002027875bSKent Overstreet bch2_trans_commit_hook(trans, &h->h); 10012027875bSKent Overstreet err: 10022027875bSKent Overstreet bch2_trans_iter_exit(trans, &iter); 10032027875bSKent Overstreet return ret; 10042027875bSKent Overstreet } 10052027875bSKent Overstreet 100614b393eeSKent Overstreet int bch2_subvolume_create(struct btree_trans *trans, u64 inode, 100714b393eeSKent Overstreet u32 src_subvolid, 100814b393eeSKent Overstreet u32 *new_subvolid, 100914b393eeSKent Overstreet u32 *new_snapshotid, 101014b393eeSKent Overstreet bool ro) 101114b393eeSKent Overstreet { 1012ca130b9cSKent Overstreet struct bch_fs *c = trans->c; 101314b393eeSKent Overstreet struct btree_iter dst_iter, src_iter = (struct btree_iter) { NULL }; 101414b393eeSKent Overstreet struct bkey_i_subvolume *new_subvol = NULL; 101514b393eeSKent Overstreet struct bkey_i_subvolume *src_subvol = NULL; 101614b393eeSKent Overstreet struct bkey_s_c k; 101714b393eeSKent Overstreet u32 parent = 0, new_nodes[2], snapshot_subvols[2]; 101814b393eeSKent Overstreet int ret = 0; 101914b393eeSKent Overstreet 102014b393eeSKent Overstreet for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN, 102114b393eeSKent Overstreet BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { 102214b393eeSKent Overstreet if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) 102314b393eeSKent Overstreet break; 1024ca130b9cSKent Overstreet 1025ca130b9cSKent Overstreet /* 1026ca130b9cSKent Overstreet * bch2_subvolume_delete() doesn't flush the btree key cache - 1027ca130b9cSKent Overstreet * ideally it would but that's tricky 1028ca130b9cSKent Overstreet */ 1029ca130b9cSKent Overstreet if (bkey_deleted(k.k) && 1030ca130b9cSKent Overstreet !bch2_btree_key_cache_find(c, BTREE_ID_subvolumes, dst_iter.pos)) 103114b393eeSKent Overstreet goto found_slot; 103214b393eeSKent Overstreet } 103314b393eeSKent Overstreet 103414b393eeSKent Overstreet if (!ret) 1035098ef98dSKent Overstreet ret = -BCH_ERR_ENOSPC_subvolume_create; 103614b393eeSKent Overstreet goto err; 103714b393eeSKent Overstreet found_slot: 103814b393eeSKent Overstreet snapshot_subvols[0] = dst_iter.pos.offset; 103914b393eeSKent Overstreet snapshot_subvols[1] = src_subvolid; 104014b393eeSKent Overstreet 104114b393eeSKent Overstreet if (src_subvolid) { 104214b393eeSKent Overstreet /* Creating a snapshot: */ 104314b393eeSKent Overstreet src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol)); 104414b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(src_subvol); 104514b393eeSKent Overstreet if (ret) 104614b393eeSKent Overstreet goto err; 104714b393eeSKent Overstreet 104814b393eeSKent Overstreet bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes, 104914b393eeSKent Overstreet POS(0, src_subvolid), 105014b393eeSKent Overstreet BTREE_ITER_CACHED| 105114b393eeSKent Overstreet BTREE_ITER_INTENT); 105214b393eeSKent Overstreet k = bch2_btree_iter_peek_slot(&src_iter); 105314b393eeSKent Overstreet ret = bkey_err(k); 105414b393eeSKent Overstreet if (ret) 105514b393eeSKent Overstreet goto err; 105614b393eeSKent Overstreet 105714b393eeSKent Overstreet if (k.k->type != KEY_TYPE_subvolume) { 1058ca130b9cSKent Overstreet bch_err(c, "subvolume %u not found", src_subvolid); 105914b393eeSKent Overstreet ret = -ENOENT; 106014b393eeSKent Overstreet goto err; 106114b393eeSKent Overstreet } 106214b393eeSKent Overstreet 106314b393eeSKent Overstreet bkey_reassemble(&src_subvol->k_i, k); 106414b393eeSKent Overstreet parent = le32_to_cpu(src_subvol->v.snapshot); 106514b393eeSKent Overstreet } 106614b393eeSKent Overstreet 106714b393eeSKent Overstreet ret = bch2_snapshot_node_create(trans, parent, new_nodes, 106814b393eeSKent Overstreet snapshot_subvols, 106914b393eeSKent Overstreet src_subvolid ? 2 : 1); 107014b393eeSKent Overstreet if (ret) 107114b393eeSKent Overstreet goto err; 107214b393eeSKent Overstreet 107314b393eeSKent Overstreet if (src_subvolid) { 107414b393eeSKent Overstreet src_subvol->v.snapshot = cpu_to_le32(new_nodes[1]); 107594a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &src_iter, &src_subvol->k_i, 0); 107694a3e1a6SKent Overstreet if (ret) 107794a3e1a6SKent Overstreet goto err; 107814b393eeSKent Overstreet } 107914b393eeSKent Overstreet 108014b393eeSKent Overstreet new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol)); 108114b393eeSKent Overstreet ret = PTR_ERR_OR_ZERO(new_subvol); 108214b393eeSKent Overstreet if (ret) 108314b393eeSKent Overstreet goto err; 108414b393eeSKent Overstreet 108514b393eeSKent Overstreet bkey_subvolume_init(&new_subvol->k_i); 108614b393eeSKent Overstreet new_subvol->v.flags = 0; 108714b393eeSKent Overstreet new_subvol->v.snapshot = cpu_to_le32(new_nodes[0]); 108814b393eeSKent Overstreet new_subvol->v.inode = cpu_to_le64(inode); 108914b393eeSKent Overstreet SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro); 109014b393eeSKent Overstreet SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0); 109114b393eeSKent Overstreet new_subvol->k.p = dst_iter.pos; 109294a3e1a6SKent Overstreet ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0); 109394a3e1a6SKent Overstreet if (ret) 109494a3e1a6SKent Overstreet goto err; 109514b393eeSKent Overstreet 109614b393eeSKent Overstreet *new_subvolid = new_subvol->k.p.offset; 109714b393eeSKent Overstreet *new_snapshotid = new_nodes[0]; 109814b393eeSKent Overstreet err: 109914b393eeSKent Overstreet bch2_trans_iter_exit(trans, &src_iter); 110014b393eeSKent Overstreet bch2_trans_iter_exit(trans, &dst_iter); 110114b393eeSKent Overstreet return ret; 110214b393eeSKent Overstreet } 110314b393eeSKent Overstreet 110414b393eeSKent Overstreet int bch2_fs_subvolumes_init(struct bch_fs *c) 110514b393eeSKent Overstreet { 110614b393eeSKent Overstreet INIT_WORK(&c->snapshot_delete_work, bch2_delete_dead_snapshots_work); 11072027875bSKent Overstreet INIT_WORK(&c->snapshot_wait_for_pagecache_and_delete_work, 11082027875bSKent Overstreet bch2_subvolume_wait_for_pagecache_and_delete); 11092027875bSKent Overstreet mutex_init(&c->snapshots_unlinked_lock); 111014b393eeSKent Overstreet return 0; 111114b393eeSKent Overstreet } 1112