bcachefs: Fix quotas + snapshots
authorKent Overstreet <kent.overstreet@linux.dev>
Fri, 28 Apr 2023 07:50:57 +0000 (03:50 -0400)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:10:01 +0000 (17:10 -0400)
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 <kent.overstreet@linux.dev>
fs/bcachefs/fs-io.c
fs/bcachefs/quota.c
fs/bcachefs/subvolume.c
fs/bcachefs/subvolume.h

index ea50392546096a2d46726a481b6125e3d8f06f5b..64897cee849434f45191829e5acb39f0d8b31277 100644 (file)
@@ -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);
 
index 7734e0dfe5230291e5de42a6d1469d3f82763b2c..310eb9d26571477af0d99ac2ac9b14dc17f61ce8 100644 (file)
@@ -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;
 }
 
index 922360dec62779964a9be0e6d851146b11f0d06a..388fa12bbd8b497e9eac733461553c487547978e 100644 (file)
@@ -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);
index 1ee4562198a61299cb35c7818b27d2022b564b51..1a39f713db87c8731778d297f045a946c6835904 100644 (file)
@@ -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 *);