X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libbcachefs%2Fsubvolume.c;h=43d83705a7aee6ce209ca3c3023b058ac3eda1f0;hb=ec28e6bfa269daf953af95610c0d1af3e7df1c0a;hp=24244bc3d2fbff6703dcf5b4e27d513ebb7082dc;hpb=ddac1641ee1e2686c2211a8d671ea723634dfc89;p=bcachefs-tools-debian diff --git a/libbcachefs/subvolume.c b/libbcachefs/subvolume.c index 24244bc..43d8370 100644 --- a/libbcachefs/subvolume.c +++ b/libbcachefs/subvolume.c @@ -25,21 +25,21 @@ void bch2_snapshot_to_text(struct printbuf *out, struct bch_fs *c, } int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, - int rw, struct printbuf *err) + unsigned flags, struct printbuf *err) { struct bkey_s_c_snapshot s; u32 i, id; - if (bkey_cmp(k.k->p, POS(0, U32_MAX)) > 0 || - bkey_cmp(k.k->p, POS(0, 1)) < 0) { + if (bkey_gt(k.k->p, POS(0, U32_MAX)) || + bkey_lt(k.k->p, POS(0, 1))) { prt_printf(err, "bad pos"); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } if (bkey_val_bytes(k.k) != sizeof(struct bch_snapshot)) { prt_printf(err, "bad val size (%zu != %zu)", bkey_val_bytes(k.k), sizeof(struct bch_snapshot)); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } s = bkey_s_c_to_snapshot(k); @@ -48,18 +48,18 @@ int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, if (id && id <= k.k->p.offset) { prt_printf(err, "bad parent node (%u <= %llu)", id, k.k->p.offset); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } if (le32_to_cpu(s.v->children[0]) < le32_to_cpu(s.v->children[1])) { prt_printf(err, "children not normalized"); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } if (s.v->children[0] && s.v->children[0] == s.v->children[1]) { prt_printf(err, "duplicate child nodes"); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } for (i = 0; i < 2; i++) { @@ -68,7 +68,7 @@ int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, if (id >= k.k->p.offset) { prt_printf(err, "bad child node (%u >= %llu)", id, k.k->p.offset); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } } @@ -76,6 +76,7 @@ int bch2_snapshot_invalid(const struct bch_fs *c, struct bkey_s_c k, } int bch2_mark_snapshot(struct btree_trans *trans, + enum btree_id btree, unsigned level, struct bkey_s_c old, struct bkey_s_c new, unsigned flags) { @@ -86,7 +87,7 @@ int bch2_mark_snapshot(struct btree_trans *trans, U32_MAX - new.k->p.offset, GFP_KERNEL); if (!t) - return -ENOMEM; + return -BCH_ERR_ENOMEM_mark_snapshot; if (new.k->type == KEY_TYPE_snapshot) { struct bkey_s_c_snapshot s = bkey_s_c_to_snapshot(new); @@ -158,6 +159,7 @@ static int bch2_snapshot_set_equiv(struct btree_trans *trans, struct bkey_s_c k) for (i = 0; i < 2; i++) { int ret = snapshot_live(trans, child[i]); + if (ret < 0) return ret; @@ -278,8 +280,8 @@ int bch2_fs_check_snapshots(struct bch_fs *c) bch2_trans_init(&trans, c, 0, 0); - ret = for_each_btree_key_commit(&trans, iter, BTREE_ID_snapshots, - POS(BCACHEFS_ROOT_INO, 0), + ret = for_each_btree_key_commit(&trans, iter, + BTREE_ID_snapshots, POS_MIN, BTREE_ITER_PREFETCH, k, NULL, NULL, BTREE_INSERT_LAZY_RW|BTREE_INSERT_NOFAIL, check_snapshot(&trans, &iter, k)); @@ -360,7 +362,7 @@ int bch2_fs_snapshots_start(struct bch_fs *c) for_each_btree_key2(&trans, iter, BTREE_ID_snapshots, POS_MIN, 0, k, - bch2_mark_snapshot(&trans, bkey_s_c_null, k, 0) ?: + bch2_mark_snapshot(&trans, BTREE_ID_snapshots, 0, bkey_s_c_null, k, 0) ?: bch2_snapshot_set_equiv(&trans, k)); bch2_trans_exit(&trans); @@ -376,33 +378,22 @@ int bch2_fs_snapshots_start(struct bch_fs *c) static int bch2_snapshot_node_set_deleted(struct btree_trans *trans, u32 id) { struct btree_iter iter; - struct bkey_s_c k; struct bkey_i_snapshot *s; int ret = 0; bch2_trans_iter_init(trans, &iter, BTREE_ID_snapshots, POS(0, id), BTREE_ITER_INTENT); - k = bch2_btree_iter_peek_slot(&iter); - ret = bkey_err(k); - if (ret) - goto err; - - if (k.k->type != KEY_TYPE_snapshot) { - bch2_fs_inconsistent(trans->c, "missing snapshot %u", id); - ret = -ENOENT; + s = bch2_bkey_get_mut_typed(trans, &iter, snapshot); + ret = PTR_ERR_OR_ZERO(s); + if (unlikely(ret)) { + bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing snapshot %u", id); goto err; } /* already deleted? */ - if (BCH_SNAPSHOT_DELETED(bkey_s_c_to_snapshot(k).v)) + if (BCH_SNAPSHOT_DELETED(&s->v)) goto err; - s = bch2_trans_kmalloc(trans, sizeof(*s)); - ret = PTR_ERR_OR_ZERO(s); - if (ret) - goto err; - - bkey_reassemble(&s->k_i, k); SET_BCH_SNAPSHOT_DELETED(&s->v, true); SET_BCH_SNAPSHOT_SUBVOL(&s->v, false); s->v.subvol = 0; @@ -420,7 +411,6 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) struct btree_iter iter, p_iter = (struct btree_iter) { NULL }; struct bkey_s_c k; struct bkey_s_c_snapshot s; - struct bkey_i_snapshot *parent; u32 parent_id; unsigned i; int ret = 0; @@ -444,26 +434,17 @@ static int bch2_snapshot_node_delete(struct btree_trans *trans, u32 id) parent_id = le32_to_cpu(s.v->parent); if (parent_id) { + struct bkey_i_snapshot *parent; + bch2_trans_iter_init(trans, &p_iter, BTREE_ID_snapshots, POS(0, parent_id), BTREE_ITER_INTENT); - k = bch2_btree_iter_peek_slot(&p_iter); - ret = bkey_err(k); - if (ret) - goto err; - - if (k.k->type != KEY_TYPE_snapshot) { - bch2_fs_inconsistent(trans->c, "missing snapshot %u", parent_id); - ret = -ENOENT; - goto err; - } - - parent = bch2_trans_kmalloc(trans, sizeof(*parent)); + parent = bch2_bkey_get_mut_typed(trans, &p_iter, snapshot); ret = PTR_ERR_OR_ZERO(parent); - if (ret) + if (unlikely(ret)) { + bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing snapshot %u", parent_id); goto err; - - bkey_reassemble(&parent->k_i, k); + } for (i = 0; i < 2; i++) if (le32_to_cpu(parent->v.children[i]) == id) @@ -517,17 +498,15 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, goto err; if (!k.k || !k.k->p.offset) { - ret = -ENOSPC; + ret = -BCH_ERR_ENOSPC_snapshot_create; goto err; } - n = bch2_trans_kmalloc(trans, sizeof(*n)); + n = bch2_bkey_alloc(trans, &iter, snapshot); ret = PTR_ERR_OR_ZERO(n); if (ret) goto err; - bkey_snapshot_init(&n->k_i); - n->k.p = iter.pos; n->v.flags = 0; n->v.parent = cpu_to_le32(parent); n->v.subvol = cpu_to_le32(snapshot_subvols[i]); @@ -535,7 +514,8 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, SET_BCH_SNAPSHOT_SUBVOL(&n->v, true); ret = bch2_trans_update(trans, &iter, &n->k_i, 0) ?: - bch2_mark_snapshot(trans, bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); + bch2_mark_snapshot(trans, BTREE_ID_snapshots, 0, + bkey_s_c_null, bkey_i_to_s_c(&n->k_i), 0); if (ret) goto err; @@ -544,23 +524,13 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, if (parent) { bch2_btree_iter_set_pos(&iter, POS(0, parent)); - k = bch2_btree_iter_peek(&iter); - ret = bkey_err(k); - if (ret) - goto err; - - if (k.k->type != KEY_TYPE_snapshot) { - bch_err(trans->c, "snapshot %u not found", parent); - ret = -ENOENT; - goto err; - } - - n = bch2_trans_kmalloc(trans, sizeof(*n)); + n = bch2_bkey_get_mut_typed(trans, &iter, snapshot); ret = PTR_ERR_OR_ZERO(n); - if (ret) + if (unlikely(ret)) { + if (ret == -ENOENT) + bch_err(trans->c, "snapshot %u not found", parent); goto err; - - bkey_reassemble(&n->k_i, k); + } if (n->v.children[0] || n->v.children[1]) { bch_err(trans->c, "Trying to add child snapshot nodes to parent that already has children"); @@ -572,7 +542,7 @@ int bch2_snapshot_node_create(struct btree_trans *trans, u32 parent, n->v.children[1] = cpu_to_le32(new_snapids[1]); n->v.subvol = 0; SET_BCH_SNAPSHOT_SUBVOL(&n->v, false); - ret = bch2_trans_update(trans, &iter, &n->k_i, 0); + ret = bch2_trans_update(trans, &iter, &n->k_i, 0); if (ret) goto err; } @@ -591,7 +561,7 @@ static int snapshot_delete_key(struct btree_trans *trans, struct bch_fs *c = trans->c; u32 equiv = snapshot_t(c, k.k->p.snapshot)->equiv; - if (bkey_cmp(k.k->p, *last_pos)) + if (!bkey_eq(k.k->p, *last_pos)) equiv_seen->nr = 0; *last_pos = k.k->p; @@ -738,16 +708,14 @@ static void bch2_delete_dead_snapshots_work(struct work_struct *work) struct bch_fs *c = container_of(work, struct bch_fs, snapshot_delete_work); bch2_delete_dead_snapshots(c); - percpu_ref_put(&c->writes); + bch2_write_ref_put(c, BCH_WRITE_REF_delete_dead_snapshots); } void bch2_delete_dead_snapshots_async(struct bch_fs *c) { - if (!percpu_ref_tryget_live(&c->writes)) - return; - - if (!queue_work(system_long_wq, &c->snapshot_delete_work)) - percpu_ref_put(&c->writes); + if (bch2_write_ref_tryget(c, BCH_WRITE_REF_delete_dead_snapshots) && + !queue_work(system_long_wq, &c->snapshot_delete_work)) + bch2_write_ref_put(c, BCH_WRITE_REF_delete_dead_snapshots); } static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, @@ -767,18 +735,18 @@ static int bch2_delete_dead_snapshots_hook(struct btree_trans *trans, /* Subvolumes: */ int bch2_subvolume_invalid(const struct bch_fs *c, struct bkey_s_c k, - int rw, struct printbuf *err) + unsigned flags, struct printbuf *err) { - if (bkey_cmp(k.k->p, SUBVOL_POS_MIN) < 0 || - bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) { + if (bkey_lt(k.k->p, SUBVOL_POS_MIN) || + bkey_gt(k.k->p, SUBVOL_POS_MAX)) { prt_printf(err, "invalid pos"); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } if (bkey_val_bytes(k.k) != sizeof(struct bch_subvolume)) { prt_printf(err, "incorrect value size (%zu != %zu)", bkey_val_bytes(k.k), sizeof(struct bch_subvolume)); - return -EINVAL; + return -BCH_ERR_invalid_bkey; } return 0; @@ -794,10 +762,11 @@ void bch2_subvolume_to_text(struct printbuf *out, struct bch_fs *c, le32_to_cpu(s.v->snapshot)); } -int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, - bool inconsistent_if_not_found, - int iter_flags, - struct bch_subvolume *s) +static __always_inline int +bch2_subvolume_get_inlined(struct btree_trans *trans, unsigned subvol, + bool inconsistent_if_not_found, + int iter_flags, + struct bch_subvolume *s) { struct btree_iter iter; struct bkey_s_c k; @@ -817,6 +786,14 @@ int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, return ret; } +int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol, + bool inconsistent_if_not_found, + int iter_flags, + struct bch_subvolume *s) +{ + return bch2_subvolume_get_inlined(trans, subvol, inconsistent_if_not_found, iter_flags, s); +} + int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot, struct bch_subvolume *subvol) { @@ -832,12 +809,12 @@ int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol, struct bch_subvolume s; int ret; - ret = bch2_subvolume_get(trans, subvol, true, - BTREE_ITER_CACHED| - BTREE_ITER_WITH_UPDATES, - &s); - - *snapid = le32_to_cpu(s.snapshot); + ret = bch2_subvolume_get_inlined(trans, subvol, true, + BTREE_ITER_CACHED| + BTREE_ITER_WITH_UPDATES, + &s); + if (!ret) + *snapid = le32_to_cpu(s.snapshot); return ret; } @@ -923,7 +900,7 @@ void bch2_subvolume_wait_for_pagecache_and_delete(struct work_struct *work) darray_exit(&s); } - percpu_ref_put(&c->writes); + bch2_write_ref_put(c, BCH_WRITE_REF_snapshot_delete_pagecache); } struct subvolume_unlink_hook { @@ -946,18 +923,17 @@ int bch2_subvolume_wait_for_pagecache_and_delete_hook(struct btree_trans *trans, if (ret) return ret; - if (unlikely(!percpu_ref_tryget_live(&c->writes))) + if (!bch2_write_ref_tryget(c, BCH_WRITE_REF_snapshot_delete_pagecache)) return -EROFS; if (!queue_work(system_long_wq, &c->snapshot_wait_for_pagecache_and_delete_work)) - percpu_ref_put(&c->writes); + bch2_write_ref_put(c, BCH_WRITE_REF_snapshot_delete_pagecache); return 0; } int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) { struct btree_iter iter; - struct bkey_s_c k; struct bkey_i_subvolume *n; struct subvolume_unlink_hook *h; int ret = 0; @@ -966,23 +942,13 @@ int bch2_subvolume_unlink(struct btree_trans *trans, u32 subvolid) POS(0, subvolid), BTREE_ITER_CACHED| BTREE_ITER_INTENT); - k = bch2_btree_iter_peek_slot(&iter); - ret = bkey_err(k); - if (ret) - goto err; - - if (k.k->type != KEY_TYPE_subvolume) { - bch2_fs_inconsistent(trans->c, "missing subvolume %u", subvolid); - ret = -EIO; - goto err; - } - - n = bch2_trans_kmalloc(trans, sizeof(*n)); + n = bch2_bkey_get_mut_typed(trans, &iter, subvolume); ret = PTR_ERR_OR_ZERO(n); - if (ret) + if (unlikely(ret)) { + bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, "missing subvolume %u", subvolid); goto err; + } - bkey_reassemble(&n->k_i, k); SET_BCH_SUBVOLUME_UNLINKED(&n->v, true); ret = bch2_trans_update(trans, &iter, &n->k_i, 0); @@ -1018,7 +984,7 @@ int bch2_subvolume_create(struct btree_trans *trans, u64 inode, for_each_btree_key(trans, dst_iter, BTREE_ID_subvolumes, SUBVOL_POS_MIN, BTREE_ITER_SLOTS|BTREE_ITER_INTENT, k, ret) { - if (bkey_cmp(k.k->p, SUBVOL_POS_MAX) > 0) + if (bkey_gt(k.k->p, SUBVOL_POS_MAX)) break; /* @@ -1031,7 +997,7 @@ int bch2_subvolume_create(struct btree_trans *trans, u64 inode, } if (!ret) - ret = -ENOSPC; + ret = -BCH_ERR_ENOSPC_subvolume_create; goto err; found_slot: snapshot_subvols[0] = dst_iter.pos.offset; @@ -1039,27 +1005,19 @@ found_slot: if (src_subvolid) { /* Creating a snapshot: */ - src_subvol = bch2_trans_kmalloc(trans, sizeof(*src_subvol)); - ret = PTR_ERR_OR_ZERO(src_subvol); - if (ret) - goto err; bch2_trans_iter_init(trans, &src_iter, BTREE_ID_subvolumes, POS(0, src_subvolid), BTREE_ITER_CACHED| BTREE_ITER_INTENT); - k = bch2_btree_iter_peek_slot(&src_iter); - ret = bkey_err(k); - if (ret) - goto err; - - if (k.k->type != KEY_TYPE_subvolume) { - bch_err(c, "subvolume %u not found", src_subvolid); - ret = -ENOENT; + src_subvol = bch2_bkey_get_mut_typed(trans, &src_iter, subvolume); + ret = PTR_ERR_OR_ZERO(src_subvol); + if (unlikely(ret)) { + bch2_fs_inconsistent_on(ret == -ENOENT, trans->c, + "subvolume %u not found", src_subvolid); goto err; } - bkey_reassemble(&src_subvol->k_i, k); parent = le32_to_cpu(src_subvol->v.snapshot); } @@ -1076,18 +1034,16 @@ found_slot: goto err; } - new_subvol = bch2_trans_kmalloc(trans, sizeof(*new_subvol)); + new_subvol = bch2_bkey_alloc(trans, &dst_iter, subvolume); ret = PTR_ERR_OR_ZERO(new_subvol); if (ret) goto err; - bkey_subvolume_init(&new_subvol->k_i); new_subvol->v.flags = 0; new_subvol->v.snapshot = cpu_to_le32(new_nodes[0]); new_subvol->v.inode = cpu_to_le64(inode); SET_BCH_SUBVOLUME_RO(&new_subvol->v, ro); SET_BCH_SUBVOLUME_SNAP(&new_subvol->v, src_subvolid != 0); - new_subvol->k.p = dst_iter.pos; ret = bch2_trans_update(trans, &dst_iter, &new_subvol->k_i, 0); if (ret) goto err;