summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@linux.dev>2023-04-28 03:50:57 -0400
committerKent Overstreet <kent.overstreet@linux.dev>2023-05-13 00:22:05 -0400
commitcaf354f87146024d1fa103c429a9bde19439fdae (patch)
tree321762934de8f55130edf31d91f58a0cf3c4bafc
parenta96977b36928fa64a97ac38b044d65ec11f2d677 (diff)
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 <kent.overstreet@linux.dev>
-rw-r--r--fs/bcachefs/fs-io.c7
-rw-r--r--fs/bcachefs/quota.c25
-rw-r--r--fs/bcachefs/subvolume.c10
-rw-r--r--fs/bcachefs/subvolume.h2
4 files changed, 27 insertions, 17 deletions
diff --git a/fs/bcachefs/fs-io.c b/fs/bcachefs/fs-io.c
index c3749d728a91..3e104bf09055 100644
--- a/fs/bcachefs/fs-io.c
+++ b/fs/bcachefs/fs-io.c
@@ -290,6 +290,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);
@@ -371,7 +374,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 *);