Commit 6c5026c1 authored by Jan Kara's avatar Jan Kara
Browse files

quota: Set nofs allocation context when acquiring dqio_sem



dqio_sem can be acquired during inode reclaim through dquot_drop() ->
dqput() -> dquot_release() -> write_file_info() context. In some cases
(most notably through dquot_get_next_id()) it can be acquired without
holding dquot->dq_lock (which already sets nofs allocation context). So
we need to set nofs allocation context when acquiring it as well.

Signed-off-by: default avatarJan Kara <jack@suse.cz>
parent c3e637c7
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -447,14 +447,17 @@ int ocfs2_global_write_info(struct super_block *sb, int type)
	int err;
	struct quota_info *dqopt = sb_dqopt(sb);
	struct ocfs2_mem_dqinfo *info = dqopt->info[type].dqi_priv;
	unsigned int memalloc;

	down_write(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	err = ocfs2_qinfo_lock(info, 1);
	if (err < 0)
		goto out_sem;
	err = __ocfs2_global_write_info(sb, type);
	ocfs2_qinfo_unlock(info, 1);
out_sem:
	memalloc_nofs_restore(memalloc);
	up_write(&dqopt->dqio_sem);
	return err;
}
@@ -601,6 +604,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
	struct ocfs2_super *osb = OCFS2_SB(sb);
	int status = 0;
	unsigned int memalloc;

	trace_ocfs2_sync_dquot_helper(from_kqid(&init_user_ns, dquot->dq_id),
				      dquot->dq_id.type,
@@ -618,6 +622,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
		goto out_ilock;
	}
	down_write(&sb_dqopt(sb)->dqio_sem);
	memalloc = memalloc_nofs_save();
	status = ocfs2_sync_dquot(dquot);
	if (status < 0)
		mlog_errno(status);
@@ -625,6 +630,7 @@ static int ocfs2_sync_dquot_helper(struct dquot *dquot, unsigned long type)
	status = ocfs2_local_write_dquot(dquot);
	if (status < 0)
		mlog_errno(status);
	memalloc_nofs_restore(memalloc);
	up_write(&sb_dqopt(sb)->dqio_sem);
	ocfs2_commit_trans(osb, handle);
out_ilock:
@@ -662,6 +668,7 @@ static int ocfs2_write_dquot(struct dquot *dquot)
	handle_t *handle;
	struct ocfs2_super *osb = OCFS2_SB(dquot->dq_sb);
	int status = 0;
	unsigned int memalloc;

	trace_ocfs2_write_dquot(from_kqid(&init_user_ns, dquot->dq_id),
				dquot->dq_id.type);
@@ -673,7 +680,9 @@ static int ocfs2_write_dquot(struct dquot *dquot)
		goto out;
	}
	down_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
	memalloc = memalloc_nofs_save();
	status = ocfs2_local_write_dquot(dquot);
	memalloc_nofs_restore(memalloc);
	up_write(&sb_dqopt(dquot->dq_sb)->dqio_sem);
	ocfs2_commit_trans(osb, handle);
out:
@@ -920,6 +929,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
	struct ocfs2_mem_dqinfo *oinfo = sb_dqinfo(sb, type)->dqi_priv;
	handle_t *handle;
	struct ocfs2_super *osb = OCFS2_SB(sb);
	unsigned int memalloc;

	trace_ocfs2_mark_dquot_dirty(from_kqid(&init_user_ns, dquot->dq_id),
				     type);
@@ -946,6 +956,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
		goto out_ilock;
	}
	down_write(&sb_dqopt(sb)->dqio_sem);
	memalloc = memalloc_nofs_save();
	status = ocfs2_sync_dquot(dquot);
	if (status < 0) {
		mlog_errno(status);
@@ -954,6 +965,7 @@ static int ocfs2_mark_dquot_dirty(struct dquot *dquot)
	/* Now write updated local dquot structure */
	status = ocfs2_local_write_dquot(dquot);
out_dlock:
	memalloc_nofs_restore(memalloc);
	up_write(&sb_dqopt(sb)->dqio_sem);
	ocfs2_commit_trans(osb, handle);
out_ilock:
+3 −0
Original line number Diff line number Diff line
@@ -470,6 +470,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
	int bit, chunk;
	struct ocfs2_recovery_chunk *rchunk, *next;
	qsize_t spacechange, inodechange;
	unsigned int memalloc;

	trace_ocfs2_recover_local_quota_file((unsigned long)lqinode->i_ino, type);

@@ -521,6 +522,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
				goto out_drop_lock;
			}
			down_write(&sb_dqopt(sb)->dqio_sem);
			memalloc = memalloc_nofs_save();
			spin_lock(&dquot->dq_dqb_lock);
			/* Add usage from quota entry into quota changes
			 * of our node. Auxiliary variables are important
@@ -553,6 +555,7 @@ static int ocfs2_recover_local_quota_file(struct inode *lqinode,
			unlock_buffer(qbh);
			ocfs2_journal_dirty(handle, qbh);
out_commit:
			memalloc_nofs_restore(memalloc);
			up_write(&sb_dqopt(sb)->dqio_sem);
			ocfs2_commit_trans(OCFS2_SB(sb), handle);
out_drop_lock:
+6 −0
Original line number Diff line number Diff line
@@ -160,9 +160,11 @@ static int v1_read_file_info(struct super_block *sb, int type)
{
	struct quota_info *dqopt = sb_dqopt(sb);
	struct v1_disk_dqblk dqblk;
	unsigned int memalloc;
	int ret;

	down_read(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
				sizeof(struct v1_disk_dqblk), v1_dqoff(0));
	if (ret != sizeof(struct v1_disk_dqblk)) {
@@ -179,6 +181,7 @@ static int v1_read_file_info(struct super_block *sb, int type)
	dqopt->info[type].dqi_bgrace =
			dqblk.dqb_btime ? dqblk.dqb_btime : MAX_DQ_TIME;
out:
	memalloc_nofs_restore(memalloc);
	up_read(&dqopt->dqio_sem);
	return ret;
}
@@ -187,9 +190,11 @@ static int v1_write_file_info(struct super_block *sb, int type)
{
	struct quota_info *dqopt = sb_dqopt(sb);
	struct v1_disk_dqblk dqblk;
	unsigned int memalloc;
	int ret;

	down_write(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = sb->s_op->quota_read(sb, type, (char *)&dqblk,
				sizeof(struct v1_disk_dqblk), v1_dqoff(0));
	if (ret != sizeof(struct v1_disk_dqblk)) {
@@ -209,6 +214,7 @@ static int v1_write_file_info(struct super_block *sb, int type)
	else if (ret >= 0)
		ret = -EIO;
out:
	memalloc_nofs_restore(memalloc);
	up_write(&dqopt->dqio_sem);
	return ret;
}
+18 −0
Original line number Diff line number Diff line
@@ -96,9 +96,11 @@ static int v2_read_file_info(struct super_block *sb, int type)
	struct qtree_mem_dqinfo *qinfo;
	ssize_t size;
	unsigned int version;
	unsigned int memalloc;
	int ret;

	down_read(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = v2_read_header(sb, type, &dqhead);
	if (ret < 0)
		goto out;
@@ -183,6 +185,7 @@ static int v2_read_file_info(struct super_block *sb, int type)
		info->dqi_priv = NULL;
	}
out:
	memalloc_nofs_restore(memalloc);
	up_read(&dqopt->dqio_sem);
	return ret;
}
@@ -195,8 +198,10 @@ static int v2_write_file_info(struct super_block *sb, int type)
	struct mem_dqinfo *info = &dqopt->info[type];
	struct qtree_mem_dqinfo *qinfo = info->dqi_priv;
	ssize_t size;
	unsigned int memalloc;

	down_write(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	spin_lock(&dq_data_lock);
	info->dqi_flags &= ~DQF_INFO_DIRTY;
	dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
@@ -209,6 +214,7 @@ static int v2_write_file_info(struct super_block *sb, int type)
	dinfo.dqi_free_entry = cpu_to_le32(qinfo->dqi_free_entry);
	size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
	       sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
	memalloc_nofs_restore(memalloc);
	up_write(&dqopt->dqio_sem);
	if (size != sizeof(struct v2_disk_dqinfo)) {
		quota_error(sb, "Can't write info structure");
@@ -328,11 +334,14 @@ static int v2_read_dquot(struct dquot *dquot)
{
	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
	int ret;
	unsigned int memalloc;

	down_read(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = qtree_read_dquot(
			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
			dquot);
	memalloc_nofs_restore(memalloc);
	up_read(&dqopt->dqio_sem);
	return ret;
}
@@ -342,6 +351,7 @@ static int v2_write_dquot(struct dquot *dquot)
	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
	int ret;
	bool alloc = false;
	unsigned int memalloc;

	/*
	 * If space for dquot is already allocated, we don't need any
@@ -355,9 +365,11 @@ static int v2_write_dquot(struct dquot *dquot)
	} else {
		down_read(&dqopt->dqio_sem);
	}
	memalloc = memalloc_nofs_save();
	ret = qtree_write_dquot(
			sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv,
			dquot);
	memalloc_nofs_restore(memalloc);
	if (alloc)
		up_write(&dqopt->dqio_sem);
	else
@@ -368,10 +380,13 @@ static int v2_write_dquot(struct dquot *dquot)
static int v2_release_dquot(struct dquot *dquot)
{
	struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
	unsigned int memalloc;
	int ret;

	down_write(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = qtree_release_dquot(sb_dqinfo(dquot->dq_sb, dquot->dq_id.type)->dqi_priv, dquot);
	memalloc_nofs_restore(memalloc);
	up_write(&dqopt->dqio_sem);

	return ret;
@@ -386,10 +401,13 @@ static int v2_free_file_info(struct super_block *sb, int type)
static int v2_get_next_id(struct super_block *sb, struct kqid *qid)
{
	struct quota_info *dqopt = sb_dqopt(sb);
	unsigned int memalloc;
	int ret;

	down_read(&dqopt->dqio_sem);
	memalloc = memalloc_nofs_save();
	ret = qtree_get_next_id(sb_dqinfo(sb, qid->type)->dqi_priv, qid);
	memalloc_nofs_restore(memalloc);
	up_read(&dqopt->dqio_sem);
	return ret;
}