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
|
* 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)
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user