quota: Factor out setup of quota inode

[ Upstream commit c7d3d28360fdb3ed3a5aa0bab19315e0fdc994a1 ]

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>
This commit is contained in:
Jan Kara 2019-11-01 17:45:31 +01:00 committed by Greg Kroah-Hartman
parent ecb9d0d2e1
commit 3da22d06e0
2 changed files with 69 additions and 41 deletions

View File

@ -2306,28 +2306,60 @@ EXPORT_SYMBOL(dquot_quota_off);
* Turn quotas on on a device * Turn quotas on on a device
*/ */
/* static int vfs_setup_quota_inode(struct inode *inode, int type)
* Helper function to turn quotas on when we already have the inode of {
* quota file and no quota information is loaded. struct super_block *sb = inode->i_sb;
*/ struct quota_info *dqopt = sb_dqopt(sb);
static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
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) unsigned int flags)
{ {
struct quota_format_type *fmt = find_quota_format(format_id); struct quota_format_type *fmt = find_quota_format(format_id);
struct super_block *sb = inode->i_sb;
struct quota_info *dqopt = sb_dqopt(sb); struct quota_info *dqopt = sb_dqopt(sb);
int error; int error;
if (!fmt) if (!fmt)
return -ESRCH; 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 || if (!sb->s_op->quota_write || !sb->s_op->quota_read ||
(type == PRJQUOTA && sb->dq_op->get_projid == NULL)) { (type == PRJQUOTA && sb->dq_op->get_projid == NULL)) {
error = -EINVAL; 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); 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; error = -EINVAL;
if (!fmt->qf_ops->check_quota_file(sb, type)) if (!fmt->qf_ops->check_quota_file(sb, type))
goto out_file_init; goto out_fmt;
dqopt->ops[type] = fmt->qf_ops; dqopt->ops[type] = fmt->qf_ops;
dqopt->info[type].dqi_format = fmt; 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); INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list);
error = dqopt->ops[type]->read_file_info(sb, type); error = dqopt->ops[type]->read_file_info(sb, type);
if (error < 0) if (error < 0)
goto out_file_init; goto out_fmt;
if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) { if (dqopt->flags & DQUOT_QUOTA_SYS_FILE) {
spin_lock(&dq_data_lock); spin_lock(&dq_data_lock);
dqopt->info[type].dqi_flags |= DQF_SYS_FILE; 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); dquot_disable(sb, type, flags);
return error; 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: out_fmt:
put_quota_format(fmt); put_quota_format(fmt);
return error; 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 */ /* Reenable quotas on remount RW */
int dquot_resume(struct super_block *sb, int type) int dquot_resume(struct super_block *sb, int type)

View 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, int dquot_enable(struct inode *inode, int type, int format_id,
unsigned int flags); 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, int dquot_quota_on(struct super_block *sb, int type, int format_id,
const struct path *path); const struct path *path);
int dquot_quota_on_mount(struct super_block *sb, char *qf_name, int dquot_quota_on_mount(struct super_block *sb, char *qf_name,