Commit 9ca4853b authored by Kent Overstreet's avatar Kent Overstreet Committed by Kent Overstreet
Browse files

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: default avatarKent Overstreet <kent.overstreet@gmail.com>
parent b44a66a6
Loading
Loading
Loading
Loading
+20 −8
Original line number Diff line number Diff line
@@ -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 @@ __bch2_create(struct mnt_idmap *idmap,
	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 @@ __bch2_create(struct mnt_idmap *idmap,
		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;
+6 −0
Original line number Diff line number Diff line
@@ -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)

+6 −6
Original line number Diff line number Diff line
@@ -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,							\
+53 −16
Original line number Diff line number Diff line
@@ -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,31 +416,36 @@ static void bch2_sb_quota_read(struct bch_fs *c)
	}
}

int bch2_fs_quota_read(struct bch_fs *c)
static int bch2_fs_quota_read_inode(struct btree_trans *trans,
				    struct btree_iter *iter)
{
	unsigned i, qtypes = enabled_qtypes(c);
	struct bch_memquota_type *q;
	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;

	mutex_lock(&c->sb_lock);
	bch2_sb_quota_read(c);
	mutex_unlock(&c->sb_lock);
	k = bch2_btree_iter_peek(iter);
	ret = bkey_err(k);
	if (ret)
		return ret;

	for_each_set_qtype(c, i, q, qtypes) {
		ret = bch2_quota_init_type(c, i);
	if (!k.k)
		return 1;

	ret = bch2_snapshot_get_subvol(trans, k.k->p.snapshot, &subvolume);
	if (ret)
		return ret;
	}

	bch2_trans_init(&trans, c, 0, 0);
	/*
	 * We don't do quota accounting in snapshots:
	 */
	if (BCH_SUBVOLUME_SNAP(&subvolume))
		goto advance;

	if (!bkey_is_inode(k.k))
		goto advance;

	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;
@@ -448,12 +454,43 @@ int bch2_fs_quota_read(struct bch_fs *c)
			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;
	int ret;

	mutex_lock(&c->sb_lock);
	bch2_sb_quota_read(c);
	mutex_unlock(&c->sb_lock);

	for_each_set_qtype(c, i, q, qtypes) {
		ret = bch2_quota_init_type(c, i);
		if (ret)
			return ret;
	}

	bch2_trans_init(&trans, c, 0, 0);

	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: */
+9 −0
Original line number Diff line number Diff line
@@ -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)
{
Loading