diff options
author | Jan Kara <jack@suse.cz> | 2024-01-22 15:31:21 +0300 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2024-01-23 21:21:11 +0300 |
commit | 6c5026c1ef5b57a8d1ddeb6f2bf0c1624d6a849f (patch) | |
tree | 22c41faebed7ced474c72b3a83ae6570ae142f21 /fs | |
parent | c3e637c7f0c9aea051b3e49fc243ad83e19348c6 (diff) | |
download | linux-6c5026c1ef5b57a8d1ddeb6f2bf0c1624d6a849f.tar.xz |
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 <jack@suse.cz>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/quota_global.c | 12 | ||||
-rw-r--r-- | fs/ocfs2/quota_local.c | 3 | ||||
-rw-r--r-- | fs/quota/quota_v1.c | 6 | ||||
-rw-r--r-- | fs/quota/quota_v2.c | 18 |
4 files changed, 39 insertions, 0 deletions
diff --git a/fs/ocfs2/quota_global.c b/fs/ocfs2/quota_global.c index dc9f76ab7e13..0575c2d060eb 100644 --- a/fs/ocfs2/quota_global.c +++ b/fs/ocfs2/quota_global.c @@ -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: diff --git a/fs/ocfs2/quota_local.c b/fs/ocfs2/quota_local.c index e09842fc9d4d..8ce462c64c51 100644 --- a/fs/ocfs2/quota_local.c +++ b/fs/ocfs2/quota_local.c @@ -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: 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; } |