summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKent Overstreet <kent.overstreet@gmail.com>2018-12-17 05:43:00 -0500
committerKent Overstreet <kent.overstreet@gmail.com>2018-12-27 11:38:37 -0500
commit7e46481c63bfb56a0a0ab43075555f9c2bb3fdcf (patch)
treee94581a49afa5b258cd9918aae716f525eb2bf0f
parentb9c7a6c411df15d77c1e7f1010258bc6d4a519a3 (diff)
bcachefs: bch2_fs_quota_transfer
improve quota transfer locking & make ei_qid usage more consistent
-rw-r--r--fs/bcachefs/fs-ioctl.c15
-rw-r--r--fs/bcachefs/fs.c67
-rw-r--r--fs/bcachefs/fs.h6
-rw-r--r--fs/bcachefs/quota.c7
-rw-r--r--fs/bcachefs/quota.h8
-rw-r--r--fs/bcachefs/quota_types.h6
6 files changed, 66 insertions, 43 deletions
diff --git a/fs/bcachefs/fs-ioctl.c b/fs/bcachefs/fs-ioctl.c
index 0eb0a0112a84..484787a6add3 100644
--- a/fs/bcachefs/fs-ioctl.c
+++ b/fs/bcachefs/fs-ioctl.c
@@ -107,21 +107,12 @@ static int bch2_set_projid(struct bch_fs *c,
u32 projid)
{
struct bch_qid qid = inode->ei_qid;
- int ret;
-
- if (projid == inode->ei_qid.q[QTYP_PRJ])
- return 0;
qid.q[QTYP_PRJ] = projid;
- return bch2_quota_transfer(c, 1 << QTYP_PRJ, qid, inode->ei_qid,
- inode->v.i_blocks +
- inode->ei_quota_reserved);
- if (ret)
- return ret;
-
- inode->ei_qid.q[QTYP_PRJ] = projid;
- return 0;
+ return bch2_fs_quota_transfer(c, inode, qid,
+ 1 << QTYP_PRJ,
+ KEY_TYPE_QUOTA_PREALLOC);
}
static int fssetxattr_inode_update_fn(struct bch_inode_info *inode,
diff --git a/fs/bcachefs/fs.c b/fs/bcachefs/fs.c
index 13670a638e0a..5c7d3f89959a 100644
--- a/fs/bcachefs/fs.c
+++ b/fs/bcachefs/fs.c
@@ -119,7 +119,6 @@ void bch2_inode_update_after_write(struct bch_fs *c,
inode->v.i_ctime = bch2_time_to_timespec(c, bi->bi_ctime);
inode->ei_inode = *bi;
- inode->ei_qid = bch_qid(bi);
bch2_inode_flags_to_vfs(inode);
}
@@ -197,6 +196,41 @@ retry:
return ret < 0 ? ret : 0;
}
+int bch2_fs_quota_transfer(struct bch_fs *c,
+ struct bch_inode_info *inode,
+ struct bch_qid new_qid,
+ unsigned qtypes,
+ enum quota_acct_mode mode)
+{
+ unsigned i;
+ int ret;
+
+ qtypes &= enabled_qtypes(c);
+
+ for (i = 0; i < QTYP_NR; i++)
+ if (new_qid.q[i] == inode->ei_qid.q[i])
+ qtypes &= ~(1U << i);
+
+ if (!qtypes)
+ return 0;
+
+ mutex_lock(&inode->ei_quota_lock);
+
+ ret = bch2_quota_transfer(c, qtypes, new_qid,
+ inode->ei_qid,
+ inode->v.i_blocks +
+ inode->ei_quota_reserved,
+ mode);
+ if (!ret)
+ for (i = 0; i < QTYP_NR; i++)
+ if (qtypes & (1 << i))
+ inode->ei_qid.q[i] = new_qid.q[i];
+
+ mutex_unlock(&inode->ei_quota_lock);
+
+ return ret;
+}
+
static struct inode *bch2_vfs_inode_get(struct bch_fs *c, u64 inum)
{
struct bch_inode_unpacked inode_u;
@@ -838,36 +872,26 @@ static int inode_update_for_setattr_fn(struct bch_inode_info *inode,
static int bch2_setattr_nonsize(struct bch_inode_info *inode, struct iattr *iattr)
{
struct bch_fs *c = inode->v.i_sb->s_fs_info;
- struct bch_qid qid = inode->ei_qid;
+ struct bch_qid qid;
struct btree_trans trans;
struct bch_inode_unpacked inode_u;
struct posix_acl *acl = NULL;
- unsigned qtypes = 0;
int ret;
mutex_lock(&inode->ei_update_lock);
- if (c->opts.usrquota &&
- (iattr->ia_valid & ATTR_UID) &&
- !uid_eq(iattr->ia_uid, inode->v.i_uid)) {
- qid.q[QTYP_USR] = from_kuid(&init_user_ns, iattr->ia_uid),
- qtypes |= 1 << QTYP_USR;
- }
+ qid = inode->ei_qid;
+
+ if (iattr->ia_valid & ATTR_UID)
+ qid.q[QTYP_USR] = from_kuid(&init_user_ns, iattr->ia_uid);
- if (c->opts.grpquota &&
- (iattr->ia_valid & ATTR_GID) &&
- !gid_eq(iattr->ia_gid, inode->v.i_gid)) {
+ if (iattr->ia_valid & ATTR_GID)
qid.q[QTYP_GRP] = from_kgid(&init_user_ns, iattr->ia_gid);
- qtypes |= 1 << QTYP_GRP;
- }
- if (qtypes) {
- ret = bch2_quota_transfer(c, qtypes, qid, inode->ei_qid,
- inode->v.i_blocks +
- inode->ei_quota_reserved);
- if (ret)
- goto err;
- }
+ ret = bch2_fs_quota_transfer(c, inode, qid, ~0,
+ KEY_TYPE_QUOTA_PREALLOC);
+ if (ret)
+ goto err;
bch2_trans_init(&trans, c);
retry:
@@ -1228,6 +1252,7 @@ static void bch2_vfs_inode_init(struct bch_fs *c,
inode->ei_journal_seq = 0;
inode->ei_quota_reserved = 0;
inode->ei_str_hash = bch2_hash_info_init(c, bi);
+ inode->ei_qid = bch_qid(bi);
inode->v.i_mapping->a_ops = &bch_address_space_operations;
diff --git a/fs/bcachefs/fs.h b/fs/bcachefs/fs.h
index a434c757e526..1a7bb7767c21 100644
--- a/fs/bcachefs/fs.h
+++ b/fs/bcachefs/fs.h
@@ -53,6 +53,12 @@ struct bch_inode_unpacked;
#ifndef NO_BCACHEFS_FS
+int bch2_fs_quota_transfer(struct bch_fs *,
+ struct bch_inode_info *,
+ struct bch_qid,
+ unsigned,
+ enum quota_acct_mode);
+
/* returns 0 if we want to do the update, or error is passed up */
typedef int (*inode_set_fn)(struct bch_inode_info *,
struct bch_inode_unpacked *, void *);
diff --git a/fs/bcachefs/quota.c b/fs/bcachefs/quota.c
index 95ff0caea199..44aacd40bfe2 100644
--- a/fs/bcachefs/quota.c
+++ b/fs/bcachefs/quota.c
@@ -269,7 +269,8 @@ static void __bch2_quota_transfer(struct bch_memquota *src_q,
int bch2_quota_transfer(struct bch_fs *c, unsigned qtypes,
struct bch_qid dst,
- struct bch_qid src, u64 space)
+ struct bch_qid src, u64 space,
+ enum quota_acct_mode mode)
{
struct bch_memquota_type *q;
struct bch_memquota *src_q[3], *dst_q[3];
@@ -295,13 +296,13 @@ int bch2_quota_transfer(struct bch_fs *c, unsigned qtypes,
ret = bch2_quota_check_limit(c, i, dst_q[i], &msgs, Q_SPC,
dst_q[i]->c[Q_SPC].v + space,
- KEY_TYPE_QUOTA_PREALLOC);
+ mode);
if (ret)
goto err;
ret = bch2_quota_check_limit(c, i, dst_q[i], &msgs, Q_INO,
dst_q[i]->c[Q_INO].v + 1,
- KEY_TYPE_QUOTA_PREALLOC);
+ mode);
if (ret)
goto err;
}
diff --git a/fs/bcachefs/quota.h b/fs/bcachefs/quota.h
index 0c3eb6973de1..eabb94c143a8 100644
--- a/fs/bcachefs/quota.h
+++ b/fs/bcachefs/quota.h
@@ -14,12 +14,6 @@ void bch2_quota_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c);
.val_to_text = bch2_quota_to_text, \
}
-enum quota_acct_mode {
- KEY_TYPE_QUOTA_PREALLOC,
- KEY_TYPE_QUOTA_WARN,
- KEY_TYPE_QUOTA_NOCHECK,
-};
-
static inline struct bch_qid bch_qid(struct bch_inode_unpacked *u)
{
return (struct bch_qid) {
@@ -42,7 +36,7 @@ int bch2_quota_acct(struct bch_fs *, struct bch_qid, enum quota_counters,
s64, enum quota_acct_mode);
int bch2_quota_transfer(struct bch_fs *, unsigned, struct bch_qid,
- struct bch_qid, u64);
+ struct bch_qid, u64, enum quota_acct_mode);
void bch2_fs_quota_exit(struct bch_fs *);
void bch2_fs_quota_init(struct bch_fs *);
diff --git a/fs/bcachefs/quota_types.h b/fs/bcachefs/quota_types.h
index bcaed4ea8345..e978dc54b6aa 100644
--- a/fs/bcachefs/quota_types.h
+++ b/fs/bcachefs/quota_types.h
@@ -7,6 +7,12 @@ struct bch_qid {
u32 q[QTYP_NR];
};
+enum quota_acct_mode {
+ KEY_TYPE_QUOTA_PREALLOC,
+ KEY_TYPE_QUOTA_WARN,
+ KEY_TYPE_QUOTA_NOCHECK,
+};
+
struct memquota_counter {
u64 v;
u64 hardlimit;