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:
parent
ecb9d0d2e1
commit
3da22d06e0
108
fs/quota/dquot.c
108
fs/quota/dquot.c
@ -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)
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user