quota: Factor out setup of quota inode
authorJan Kara <jack@suse.cz>
Fri, 1 Nov 2019 16:45:31 +0000 (17:45 +0100)
committerJan Kara <jack@suse.cz>
Mon, 4 Nov 2019 08:58:01 +0000 (09:58 +0100)
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>
fs/quota/dquot.c
include/linux/quotaops.h

index 6e826b4..9e8eb6e 100644 (file)
@@ -2299,28 +2299,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;
@@ -2352,27 +2384,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;
@@ -2380,7 +2394,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;
@@ -2395,18 +2409,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 185d948..2625766 100644 (file)
@@ -89,6 +89,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,