summaryrefslogtreecommitdiff
path: root/fs/bcachefs
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2021-10-27 20:05:56 +0300
committerKent Overstreet <kent.overstreet@linux.dev>2023-10-23 00:09:17 +0300
commit9ca4853b98af5fa15a2ddc47a45f8e103027f95d (patch)
tree28b8be8ce679f0b5503de7fa68d9b0f2c5483bc9 /fs/bcachefs
parentb44a66a64123efb3e6aebaa0cedec722ecbfbba4 (diff)
downloadlinux-9ca4853b98af5fa15a2ddc47a45f8e103027f95d.tar.xz
bcachefs: Fix quota support for snapshots
Quota support was disabled when snapshots were released, because of some tricky interactions with snpashots. We're sidestepping that for now - we're simply disabling quota accounting on snapshot subvolumes. Signed-off-by: Kent Overstreet <kent.overstreet@gmail.com>
Diffstat (limited to 'fs/bcachefs')
-rw-r--r--fs/bcachefs/fs.c28
-rw-r--r--fs/bcachefs/fs.h6
-rw-r--r--fs/bcachefs/opts.h12
-rw-r--r--fs/bcachefs/quota.c69
-rw-r--r--fs/bcachefs/subvolume.c9
-rw-r--r--fs/bcachefs/subvolume.h2
6 files changed, 96 insertions, 30 deletions
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 61027d349cd8..31adc0e0d452 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -39,7 +39,8 @@ static struct kmem_cache *bch2_inode_cache;
static void bch2_vfs_inode_init(struct btree_trans *, subvol_inum,
struct bch_inode_info *,
- struct bch_inode_unpacked *);
+ struct bch_inode_unpacked *,
+ struct bch_subvolume *);
static void __pagecache_lock_put(struct pagecache_lock *lock, long i)
{
@@ -225,6 +226,7 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
struct bch_inode_unpacked inode_u;
struct bch_inode_info *inode;
struct btree_trans trans;
+ struct bch_subvolume subvol;
int ret;
inode = to_bch_ei(iget5_locked(c->vfs_sb,
@@ -239,10 +241,11 @@ struct inode *bch2_vfs_inode_get(struct bch_fs *c, subvol_inum inum)
bch2_trans_init(&trans, c, 8, 0);
ret = lockrestart_do(&trans,
+ bch2_subvolume_get(&trans, inum.subvol, true, 0, &subvol) ?:
bch2_inode_find_by_inum_trans(&trans, inum, &inode_u));
if (!ret)
- bch2_vfs_inode_init(&trans, inum, inode, &inode_u);
+ bch2_vfs_inode_init(&trans, inum, inode, &inode_u, &subvol);
bch2_trans_exit(&trans);
if (ret) {
@@ -268,6 +271,7 @@ __bch2_create(struct mnt_idmap *idmap,
struct bch_inode_unpacked inode_u;
struct posix_acl *default_acl = NULL, *acl = NULL;
subvol_inum inum;
+ struct bch_subvolume subvol;
u64 journal_seq = 0;
int ret;
@@ -310,7 +314,12 @@ retry:
if (unlikely(ret))
goto err_before_quota;
- ret = bch2_trans_commit(&trans, NULL, &journal_seq, 0);
+ inum.subvol = inode_u.bi_subvol ?: dir->ei_subvol;
+ inum.inum = inode_u.bi_inum;
+
+ ret = bch2_subvolume_get(&trans, inum.subvol, true,
+ BTREE_ITER_WITH_UPDATES, &subvol) ?:
+ bch2_trans_commit(&trans, NULL, &journal_seq, 0);
if (unlikely(ret)) {
bch2_quota_acct(c, bch_qid(&inode_u), Q_INO, -1,
KEY_TYPE_QUOTA_WARN);
@@ -326,11 +335,8 @@ err_before_quota:
mutex_unlock(&dir->ei_update_lock);
}
- inum.subvol = inode_u.bi_subvol ?: dir->ei_subvol;
- inum.inum = inode_u.bi_inum;
-
bch2_iget5_set(&inode->v, &inum);
- bch2_vfs_inode_init(&trans, inum, inode, &inode_u);
+ bch2_vfs_inode_init(&trans, inum, inode, &inode_u, &subvol);
set_cached_acl(&inode->v, ACL_TYPE_ACCESS, acl);
set_cached_acl(&inode->v, ACL_TYPE_DEFAULT, default_acl);
@@ -1352,10 +1358,16 @@ static const struct export_operations bch_export_ops = {
static void bch2_vfs_inode_init(struct btree_trans *trans, subvol_inum inum,
struct bch_inode_info *inode,
- struct bch_inode_unpacked *bi)
+ struct bch_inode_unpacked *bi,
+ struct bch_subvolume *subvol)
{
bch2_inode_update_after_write(trans, inode, bi, ~0);
+ if (BCH_SUBVOLUME_SNAP(subvol))
+ set_bit(EI_INODE_SNAPSHOT, &inode->ei_flags);
+ else
+ clear_bit(EI_INODE_SNAPSHOT, &inode->ei_flags);
+
inode->v.i_blocks = bi->bi_sectors;
inode->v.i_ino = bi->bi_inum;
inode->v.i_rdev = bi->bi_dev;
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index 530238780a88..a67ab1ad2a31 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -63,6 +63,12 @@ static inline subvol_inum inode_inum(struct bch_inode_info *inode)
*/
#define EI_INODE_ERROR 0
+/*
+ * Set in the inode is in a snapshot subvolume - we don't do quota accounting in
+ * those:
+ */
+#define EI_INODE_SNAPSHOT 1
+
#define to_bch_ei(_inode) \
container_of_or_null(_inode, struct bch_inode_info, v)
diff --git a/fs/bcachefs/opts.h b/fs/bcachefs/opts.h
index 10c022ec6ee0..896b8c9c1180 100644
--- a/fs/bcachefs/opts.h
+++ b/fs/bcachefs/opts.h
@@ -223,19 +223,19 @@ enum opt_type {
BCH_SB_POSIX_ACL, true, \
NULL, "Enable POSIX acls") \
x(usrquota, u8, \
- 0, \
+ OPT_FORMAT|OPT_MOUNT, \
OPT_BOOL(), \
- NO_SB_OPT, false, \
+ BCH_SB_USRQUOTA, false, \
NULL, "Enable user quotas") \
x(grpquota, u8, \
- 0, \
+ OPT_FORMAT|OPT_MOUNT, \
OPT_BOOL(), \
- NO_SB_OPT, false, \
+ BCH_SB_GRPQUOTA, false, \
NULL, "Enable group quotas") \
x(prjquota, u8, \
- 0, \
+ OPT_FORMAT|OPT_MOUNT, \
OPT_BOOL(), \
- NO_SB_OPT, false, \
+ BCH_SB_PRJQUOTA, false, \
NULL, "Enable project quotas") \
x(degraded, u8, \
OPT_MOUNT, \
diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c
index 5f1216da76d0..8f8f4b0accd6 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -3,6 +3,7 @@
#include "btree_update.h"
#include "inode.h"
#include "quota.h"
+#include "subvolume.h"
#include "super-io.h"
static const char *bch2_sb_validate_quota(struct bch_sb *sb,
@@ -415,14 +416,55 @@ static void bch2_sb_quota_read(struct bch_fs *c)
}
}
+static int bch2_fs_quota_read_inode(struct btree_trans *trans,
+ struct btree_iter *iter)
+{
+ struct bch_fs *c = trans->c;
+ struct bch_inode_unpacked u;
+ struct bch_subvolume subvolume;
+ struct bkey_s_c k;
+ int ret;
+
+ k = bch2_btree_iter_peek(iter);
+ ret = bkey_err(k);
+ if (ret)
+ return ret;
+
+ if (!k.k)
+ return 1;
+
+ ret = bch2_snapshot_get_subvol(trans, k.k->p.snapshot, &subvolume);
+ if (ret)
+ return ret;
+
+ /*
+ * We don't do quota accounting in snapshots:
+ */
+ if (BCH_SUBVOLUME_SNAP(&subvolume))
+ goto advance;
+
+ if (!bkey_is_inode(k.k))
+ goto advance;
+
+ ret = bch2_inode_unpack(k, &u);
+ if (ret)
+ return ret;
+
+ bch2_quota_acct(c, bch_qid(&u), Q_SPC, u.bi_sectors,
+ KEY_TYPE_QUOTA_NOCHECK);
+ 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));
+ return 0;
+}
+
int bch2_fs_quota_read(struct bch_fs *c)
{
unsigned i, qtypes = enabled_qtypes(c);
struct bch_memquota_type *q;
struct btree_trans trans;
struct btree_iter iter;
- struct bch_inode_unpacked u;
- struct bkey_s_c k;
int ret;
mutex_lock(&c->sb_lock);
@@ -437,23 +479,18 @@ int bch2_fs_quota_read(struct bch_fs *c)
bch2_trans_init(&trans, c, 0, 0);
- for_each_btree_key(&trans, iter, BTREE_ID_inodes, POS_MIN,
- BTREE_ITER_PREFETCH, k, ret) {
- if (bkey_is_inode(k.k)) {
- ret = bch2_inode_unpack(k, &u);
- if (ret)
- return ret;
-
- bch2_quota_acct(c, bch_qid(&u), Q_SPC, u.bi_sectors,
- KEY_TYPE_QUOTA_NOCHECK);
- bch2_quota_acct(c, bch_qid(&u), Q_INO, 1,
- KEY_TYPE_QUOTA_NOCHECK);
- }
- }
+ bch2_trans_iter_init(&trans, &iter, BTREE_ID_inodes, POS_MIN,
+ BTREE_ITER_INTENT|
+ BTREE_ITER_PREFETCH|
+ BTREE_ITER_ALL_SNAPSHOTS);
+ do {
+ ret = lockrestart_do(&trans,
+ bch2_fs_quota_read_inode(&trans, &iter));
+ } while (!ret);
bch2_trans_iter_exit(&trans, &iter);
bch2_trans_exit(&trans);
- return ret;
+ return ret < 0 ? ret : 0;
}
/* Enable/disable/delete quotas for an entire filesystem: */
diff --git a/fs/bcachefs/subvolume.c b/fs/bcachefs/subvolume.c
index 0ef625d21672..7e909a118189 100644
--- a/fs/bcachefs/subvolume.c
+++ b/fs/bcachefs/subvolume.c
@@ -789,6 +789,15 @@ int bch2_subvolume_get(struct btree_trans *trans, unsigned subvol,
return ret;
}
+int bch2_snapshot_get_subvol(struct btree_trans *trans, u32 snapshot,
+ struct bch_subvolume *subvol)
+{
+ struct bch_snapshot snap;
+
+ return snapshot_lookup(trans, snapshot, &snap) ?:
+ bch2_subvolume_get(trans, le32_to_cpu(snap.subvol), true, 0, subvol);
+}
+
int bch2_subvolume_get_snapshot(struct btree_trans *trans, u32 subvol,
u32 *snapid)
{
diff --git a/fs/bcachefs/subvolume.h b/fs/bcachefs/subvolume.h
index dde755b45392..e4c3fdcdf22f 100644
--- a/fs/bcachefs/subvolume.h
+++ b/fs/bcachefs/subvolume.h
@@ -118,6 +118,8 @@ void bch2_subvolume_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c)
int bch2_subvolume_get(struct btree_trans *, unsigned,
bool, int, struct bch_subvolume *);
+int bch2_snapshot_get_subvol(struct btree_trans *, u32,
+ struct bch_subvolume *);
int bch2_subvolume_get_snapshot(struct btree_trans *, u32, u32 *);
int bch2_subvolume_delete(struct btree_trans *, u32);