From cb1b479dc1c78d1d224e4aa6aba212a7bd3263a4 Mon Sep 17 00:00:00 2001 From: Kent Overstreet Date: Fri, 28 Apr 2023 03:50:57 -0400 Subject: [PATCH] bcachefs: Fix quotas + snapshots Now that we can reliably designate and find the master subvolume out of a tree of snapshots, we can finally make quotas work with snapshots: That is - quotas will now _ignore_ snapshot subvolumes, and only be in effect for the master (non snapshot) subvolume. Signed-off-by: Kent Overstreet --- fs/bcachefs/fs-io.c | 7 ++++++- fs/bcachefs/quota.c | 25 ++++++++++++++----------- fs/bcachefs/subvolume.c | 10 +++++----- fs/bcachefs/subvolume.h | 2 ++ 4 files changed, 27 insertions(+), 17 deletions(-) diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c index ea5039254609..64897cee8494 100644 --- a/fs/bcachefs/fs-io.c +++ b/fs/bcachefs/fs-io.c @@ -333,6 +333,9 @@ static int bch2_quota_reservation_add(struct bch_fs *c, { int ret; + if (test_bit(EI_INODE_SNAPSHOT, &inode->ei_flags)) + return 0; + mutex_lock(&inode->ei_quota_lock); ret = bch2_quota_acct(c, inode->ei_qid, Q_SPC, sectors, check_enospc ? KEY_TYPE_QUOTA_PREALLOC : KEY_TYPE_QUOTA_NOCHECK); @@ -414,7 +417,9 @@ static void __i_sectors_acct(struct bch_fs *c, struct bch_inode_info *inode, inode->v.i_blocks += sectors; #ifdef CONFIG_BCACHEFS_QUOTA - if (quota_res && sectors > 0) { + if (quota_res && + !test_bit(EI_INODE_SNAPSHOT, &inode->ei_flags) && + sectors > 0) { BUG_ON(sectors > quota_res->sectors); BUG_ON(sectors > inode->ei_quota_reserved); diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c index 7734e0dfe523..310eb9d26571 100644 --- a/fs/bcachefs/quota.c +++ b/fs/bcachefs/quota.c @@ -2,6 +2,7 @@ #include "bcachefs.h" #include "btree_update.h" #include "errcode.h" +#include "error.h" #include "inode.h" #include "quota.h" #include "subvolume.h" @@ -556,23 +557,25 @@ static int bch2_fs_quota_read_inode(struct btree_trans *trans, { struct bch_fs *c = trans->c; struct bch_inode_unpacked u; - struct bch_subvolume subvolume; + struct bch_snapshot_tree s_t; int ret; - ret = bch2_snapshot_get_subvol(trans, k.k->p.snapshot, &subvolume); + ret = bch2_snapshot_tree_lookup(trans, + snapshot_t(c, k.k->p.snapshot)->tree, &s_t); + bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), c, + "%s: snapshot tree %u not found", __func__, + snapshot_t(c, k.k->p.snapshot)->tree); if (ret) return ret; - /* - * We don't do quota accounting in snapshots: - */ - if (BCH_SUBVOLUME_SNAP(&subvolume)) + if (!s_t.master_subvol) goto advance; - if (!bkey_is_inode(k.k)) - goto advance; - - ret = bch2_inode_unpack(k, &u); + ret = bch2_inode_find_by_inum_trans(trans, + (subvol_inum) { + le32_to_cpu(s_t.master_subvol), + k.k->p.offset, + }, &u); if (ret) return ret; @@ -581,7 +584,7 @@ static int bch2_fs_quota_read_inode(struct btree_trans *trans, bch2_quota_acct(c, bch_qid(&u), Q_INO, 1, KEY_TYPE_QUOTA_NOCHECK); advance: - bch2_btree_iter_set_pos(iter, POS(iter->pos.inode, iter->pos.offset + 1)); + bch2_btree_iter_set_pos(iter, bpos_nosnap_successor(iter->pos)); return 0; } diff --git a/fs/bcachefs/subvolume.c b/fs/bcachefs/subvolume.c index 922360dec627..388fa12bbd8b 100644 --- a/fs/bcachefs/subvolume.c +++ b/fs/bcachefs/subvolume.c @@ -34,8 +34,8 @@ int bch2_snapshot_tree_invalid(const struct bch_fs *c, struct bkey_s_c k, return 0; } -static int snapshot_tree_lookup(struct btree_trans *trans, u32 id, - struct bch_snapshot_tree *s) +int bch2_snapshot_tree_lookup(struct btree_trans *trans, u32 id, + struct bch_snapshot_tree *s) { return bch2_bkey_get_val_typed(trans, BTREE_ID_snapshot_trees, POS(0, id), BTREE_ITER_WITH_UPDATES, snapshot_tree, s); @@ -426,7 +426,7 @@ static int snapshot_tree_ptr_good(struct btree_trans *trans, u32 snap_id, u32 tree_id) { struct bch_snapshot_tree s_t; - int ret = snapshot_tree_lookup(trans, tree_id, &s_t); + int ret = bch2_snapshot_tree_lookup(trans, tree_id, &s_t); if (bch2_err_matches(ret, ENOENT)) return 0; @@ -462,7 +462,7 @@ static int snapshot_tree_ptr_repair(struct btree_trans *trans, tree_id = le32_to_cpu(root.v->tree); - ret = snapshot_tree_lookup(trans, tree_id, &s_t); + ret = bch2_snapshot_tree_lookup(trans, tree_id, &s_t); if (ret && !bch2_err_matches(ret, ENOENT)) return ret; @@ -659,7 +659,7 @@ static int check_subvol(struct btree_trans *trans, u32 snapshot_tree = snapshot_t(c, snapshot_root)->tree; struct bch_snapshot_tree st; - ret = snapshot_tree_lookup(trans, snapshot_tree, &st); + ret = bch2_snapshot_tree_lookup(trans, snapshot_tree, &st); bch2_fs_inconsistent_on(bch2_err_matches(ret, ENOENT), c, "%s: snapshot tree %u not found", __func__, snapshot_tree); diff --git a/fs/bcachefs/subvolume.h b/fs/bcachefs/subvolume.h index 1ee4562198a6..1a39f713db87 100644 --- a/fs/bcachefs/subvolume.h +++ b/fs/bcachefs/subvolume.h @@ -15,6 +15,8 @@ int bch2_snapshot_tree_invalid(const struct bch_fs *, struct bkey_s_c, .min_val_size = 8, \ }) +int bch2_snapshot_tree_lookup(struct btree_trans *, u32, struct bch_snapshot_tree *); + void bch2_snapshot_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); int bch2_snapshot_invalid(const struct bch_fs *, struct bkey_s_c, unsigned, struct printbuf *); -- 2.20.1