bcachefs: bch2_fs_quota_transfer
authorKent Overstreet <kent.overstreet@gmail.com>
Mon, 17 Dec 2018 10:43:00 +0000 (05:43 -0500)
committerKent Overstreet <kent.overstreet@linux.dev>
Sun, 22 Oct 2023 21:08:13 +0000 (17:08 -0400)
improve quota transfer locking & make ei_qid usage more consistent

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>
fs/bcachefs/fs-ioctl.c
fs/bcachefs/fs.c
fs/bcachefs/fs.h
fs/bcachefs/quota.c
fs/bcachefs/quota.h
fs/bcachefs/quota_types.h

index a89786f295cf1b841fbaa3d6a20e95a0d37fe202..701882ce602450e8c2643df0f89be893193ddb56 100644 (file)
@@ -108,21 +108,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,
index 8f0b049aa1ec63b98789eb1383ccc05a7f283643..d22b9e7e208295b12b239662248cfd6bf419338a 100644 (file)
@@ -170,7 +170,6 @@ void bch2_inode_update_after_write(struct bch_fs *c,
                inode_set_ctime_to_ts(&inode->v, bch2_time_to_timespec(c, bi->bi_ctime));
 
        inode->ei_inode         = *bi;
-       inode->ei_qid           = bch_qid(bi);
 
        bch2_inode_flags_to_vfs(inode);
 }
@@ -248,6 +247,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;
@@ -913,37 +947,27 @@ static int bch2_setattr_nonsize(struct mnt_idmap *idmap,
                                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;
        struct inode_write_setattr s = { iattr, idmap };
-       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(i_user_ns(&inode->v), iattr->ia_uid),
-               qtypes |= 1 << QTYP_USR;
-       }
+       qid = inode->ei_qid;
+
+       if (iattr->ia_valid & ATTR_UID)
+               qid.q[QTYP_USR] = from_kuid(i_user_ns(&inode->v), 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(i_user_ns(&inode->v), 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:
@@ -1312,6 +1336,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;
 
index 4fdc11762cd7e41515e423288817e37b49a3094e..fbb31976bc559aa52bf7b0a2906727fb836acf68 100644 (file)
@@ -70,6 +70,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 *);
index 7c38daac1cac2dde60ad20666b29cf340a3a2922..113a2ca88ffcb5662ca05e03c8557c404110a3f4 100644 (file)
@@ -270,7 +270,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];
@@ -296,13 +297,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;
        }
index 294a04db84bf4e52395af855f377370b79a8f8c3..72b5ea0d77c52a0ae5cf2117acf1457bee34c28b 100644 (file)
@@ -15,12 +15,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) {
@@ -43,7 +37,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 *);
@@ -62,7 +56,8 @@ static inline int bch2_quota_acct(struct bch_fs *c, struct bch_qid qid,
 
 static inline 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)
 {
        return 0;
 }
index 9eda6c3637368f9bed248946bdee7eba138ee655..6a136083d3899d29ac96222eb46a26dd113060b2 100644 (file)
@@ -8,6 +8,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;