]> git.baikalelectronics.ru Git - kernel.git/commitdiff
quota: Factor out setup of quota inode
authorJan Kara <jack@suse.cz>
Fri, 1 Nov 2019 16:45:31 +0000 (17:45 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 18 Jan 2023 10:42:02 +0000 (11:42 +0100)
[ Upstream commit 954472b900cc6eb2d86a5b81bc0ff7cf32513694 ]

Factor out setting up of quota inode and eventual error cleanup from
vfs_load_quota_inode(). This will simplify situation for filesystems
that don't have any quota inodes.

Signed-off-by: Jan Kara <jack@suse.cz>
Stable-dep-of: d32387748476 ("ext4: fix bug_on in __es_tree_search caused by bad quota inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/quota/dquot.c
include/linux/quotaops.h

index dc5f8654b277d2ef7bec961715c982e45958b9f8..84f61ab058906f74c6b24592ebdaec8c4f17f623 100644 (file)
@@ -2306,28 +2306,60 @@ EXPORT_SYMBOL(dquot_quota_off);
  *     Turn quotas on on a device
  */
 
-/*
- * Helper function to turn quotas on when we already have the inode of
- * quota file and no quota information is loaded.
- */
-static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+static int vfs_setup_quota_inode(struct inode *inode, int type)
+{
+       struct super_block *sb = inode->i_sb;
+       struct quota_info *dqopt = sb_dqopt(sb);
+
+       if (!S_ISREG(inode->i_mode))
+               return -EACCES;
+       if (IS_RDONLY(inode))
+               return -EROFS;
+       if (sb_has_quota_loaded(sb, type))
+               return -EBUSY;
+
+       dqopt->files[type] = igrab(inode);
+       if (!dqopt->files[type])
+               return -EIO;
+       if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+               /* We don't want quota and atime on quota files (deadlocks
+                * possible) Also nobody should write to the file - we use
+                * special IO operations which ignore the immutable bit. */
+               inode_lock(inode);
+               inode->i_flags |= S_NOQUOTA;
+               inode_unlock(inode);
+               /*
+                * When S_NOQUOTA is set, remove dquot references as no more
+                * references can be added
+                */
+               __dquot_drop(inode);
+       }
+       return 0;
+}
+
+static void vfs_cleanup_quota_inode(struct super_block *sb, int type)
+{
+       struct quota_info *dqopt = sb_dqopt(sb);
+       struct inode *inode = dqopt->files[type];
+
+       if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
+               inode_lock(inode);
+               inode->i_flags &= ~S_NOQUOTA;
+               inode_unlock(inode);
+       }
+       dqopt->files[type] = NULL;
+       iput(inode);
+}
+
+int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
        unsigned int flags)
 {
        struct quota_format_type *fmt = find_quota_format(format_id);
-       struct super_block *sb = inode->i_sb;
        struct quota_info *dqopt = sb_dqopt(sb);
        int error;
 
        if (!fmt)
                return -ESRCH;
-       if (!S_ISREG(inode->i_mode)) {
-               error = -EACCES;
-               goto out_fmt;
-       }
-       if (IS_RDONLY(inode)) {
-               error = -EROFS;
-               goto out_fmt;
-       }
        if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
            (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
                error = -EINVAL;
@@ -2359,27 +2391,9 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                invalidate_bdev(sb->s_bdev);
        }
 
-       if (!(dqopt->flags & DQUOT_QUOTA_SYS_FILE)) {
-               /* We don't want quota and atime on quota files (deadlocks
-                * possible) Also nobody should write to the file - we use
-                * special IO operations which ignore the immutable bit. */
-               inode_lock(inode);
-               inode->i_flags |= S_NOQUOTA;
-               inode_unlock(inode);
-               /*
-                * When S_NOQUOTA is set, remove dquot references as no more
-                * references can be added
-                */
-               __dquot_drop(inode);
-       }
-
-       error = -EIO;
-       dqopt->files[type] = igrab(inode);
-       if (!dqopt->files[type])
-               goto out_file_flags;
        error = -EINVAL;
        if (!fmt->qf_ops->check_quota_file(sb, type))
-               goto out_file_init;
+               goto out_fmt;
 
        dqopt->ops[type] = fmt->qf_ops;
        dqopt->info[type].dqi_format = fmt;
@@ -2387,7 +2401,7 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
        INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
        error = dqopt->ops[type]->read_file_info(sb, type);
        if (error < 0)
-               goto out_file_init;
+               goto out_fmt;
        if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) {
                spin_lock(&dq_data_lock);
                dqopt->info[type].dqi_flags |= DQF_SYS_FILE;
@@ -2402,18 +2416,30 @@ static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
                dquot_disable(sb, type, flags);
 
        return error;
-out_file_init:
-       dqopt->files[type] = NULL;
-       iput(inode);
-out_file_flags:
-       inode_lock(inode);
-       inode->i_flags &= ~S_NOQUOTA;
-       inode_unlock(inode);
 out_fmt:
        put_quota_format(fmt);
 
        return error;
 }
+EXPORT_SYMBOL(dquot_load_quota_sb);
+
+/*
+ * Helper function to turn quotas on when we already have the inode of
+ * quota file and no quota information is loaded.
+ */
+static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
+       unsigned int flags)
+{
+       int err;
+
+       err = vfs_setup_quota_inode(inode, type);
+       if (err < 0)
+               return err;
+       err = dquot_load_quota_sb(inode->i_sb, type, format_id, flags);
+       if (err < 0)
+               vfs_cleanup_quota_inode(inode->i_sb, type);
+       return err;
+}
 
 /* Reenable quotas on remount RW */
 int dquot_resume(struct super_block *sb, int type)
index 91e0b7624053e17801bb6c0363032a0c00fc96ca..ec10897f7f60c2e4902946b4006a7f3f13e548b5 100644 (file)
@@ -99,6 +99,8 @@ int dquot_file_open(struct inode *inode, struct file *file);
 
 int dquot_enable(struct inode *inode, int type, int format_id,
        unsigned int flags);
+int dquot_load_quota_sb(struct super_block *sb, int type, int format_id,
+       unsigned int flags);
 int dquot_quota_on(struct super_block *sb, int type, int format_id,
        const struct path *path);
 int dquot_quota_on_mount(struct super_block *sb, char *qf_name,