From 6c5026c1ef5b57a8d1ddeb6f2bf0c1624d6a849f Mon Sep 17 00:00:00 2001 From: Jan Kara Date: Mon, 22 Jan 2024 13:31:21 +0100 Subject: 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: Jan Kara --- fs/quota/quota_v1.c | 6 ++++++ fs/quota/quota_v2.c | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) (limited to 'fs/quota') diff --git a/fs/quota/quota_v1.c b/fs/quota/quota_v1.c index a0db3f195e95..3f3e8acc05db 100644 --- a/fs/quota/quota_v1.c +++ b/fs/quota/quota_v1.c @@ -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; } diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index ae99e7b88205..48e0d610ceef 100644 --- a/fs/quota/quota_v2.c +++ b/fs/quota/quota_v2.c @@ -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 @@ out_free: 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; } -- cgit v1.2.3