Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3da22d06 authored by Jan Kara's avatar Jan Kara Committed by Greg Kroah-Hartman
Browse files

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: default avatarJan Kara <jack@suse.cz>
Stable-dep-of: d32387748476 ("ext4: fix bug_on in __es_tree_search caused by bad quota inode")
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent ecb9d0d2
Loading
Loading
Loading
Loading
+67 −41
Original line number Diff line number Diff line
@@ -2306,28 +2306,60 @@ EXPORT_SYMBOL(dquot_quota_off);
 *	Turn quotas on on a device
 */

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);
		/*
 * Helper function to turn quotas on when we already have the inode of
 * quota file and no quota information is loaded.
		 * When S_NOQUOTA is set, remove dquot references as no more
		 * references can be added
		 */
static int vfs_load_quota_inode(struct inode *inode, int type, int format_id,
		__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)
+2 −0
Original line number Diff line number Diff line
@@ -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,