mirror of
https://github.com/torvalds/linux.git
synced 2026-06-07 05:55:44 +02:00
quota: Prevent memory allocation recursion while holding dq_lock
[ Upstream commit537e11cdc7] As described in commit02117b8ae9("f2fs: Set GF_NOFS in read_cache_page_gfp while doing f2fs_quota_read"), we must not enter filesystem reclaim while holding the dq_lock. Prevent this more generally by using memalloc_nofs_save() while holding the lock. Link: https://lore.kernel.org/r/20220605143815.2330891-2-willy@infradead.org Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
36cd19e7d4
commit
8656623bdc
|
|
@ -79,6 +79,7 @@
|
||||||
#include <linux/capability.h>
|
#include <linux/capability.h>
|
||||||
#include <linux/quotaops.h>
|
#include <linux/quotaops.h>
|
||||||
#include <linux/blkdev.h>
|
#include <linux/blkdev.h>
|
||||||
|
#include <linux/sched/mm.h>
|
||||||
#include "../internal.h" /* ugh */
|
#include "../internal.h" /* ugh */
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
|
|
@ -427,9 +428,11 @@ EXPORT_SYMBOL(mark_info_dirty);
|
||||||
int dquot_acquire(struct dquot *dquot)
|
int dquot_acquire(struct dquot *dquot)
|
||||||
{
|
{
|
||||||
int ret = 0, ret2 = 0;
|
int ret = 0, ret2 = 0;
|
||||||
|
unsigned int memalloc;
|
||||||
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
||||||
|
|
||||||
mutex_lock(&dquot->dq_lock);
|
mutex_lock(&dquot->dq_lock);
|
||||||
|
memalloc = memalloc_nofs_save();
|
||||||
if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
|
if (!test_bit(DQ_READ_B, &dquot->dq_flags)) {
|
||||||
ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
|
ret = dqopt->ops[dquot->dq_id.type]->read_dqblk(dquot);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
|
|
@ -460,6 +463,7 @@ int dquot_acquire(struct dquot *dquot)
|
||||||
smp_mb__before_atomic();
|
smp_mb__before_atomic();
|
||||||
set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
|
set_bit(DQ_ACTIVE_B, &dquot->dq_flags);
|
||||||
out_iolock:
|
out_iolock:
|
||||||
|
memalloc_nofs_restore(memalloc);
|
||||||
mutex_unlock(&dquot->dq_lock);
|
mutex_unlock(&dquot->dq_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -471,9 +475,11 @@ EXPORT_SYMBOL(dquot_acquire);
|
||||||
int dquot_commit(struct dquot *dquot)
|
int dquot_commit(struct dquot *dquot)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
unsigned int memalloc;
|
||||||
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
||||||
|
|
||||||
mutex_lock(&dquot->dq_lock);
|
mutex_lock(&dquot->dq_lock);
|
||||||
|
memalloc = memalloc_nofs_save();
|
||||||
if (!clear_dquot_dirty(dquot))
|
if (!clear_dquot_dirty(dquot))
|
||||||
goto out_lock;
|
goto out_lock;
|
||||||
/* Inactive dquot can be only if there was error during read/init
|
/* Inactive dquot can be only if there was error during read/init
|
||||||
|
|
@ -483,6 +489,7 @@ int dquot_commit(struct dquot *dquot)
|
||||||
else
|
else
|
||||||
ret = -EIO;
|
ret = -EIO;
|
||||||
out_lock:
|
out_lock:
|
||||||
|
memalloc_nofs_restore(memalloc);
|
||||||
mutex_unlock(&dquot->dq_lock);
|
mutex_unlock(&dquot->dq_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
@ -494,9 +501,11 @@ EXPORT_SYMBOL(dquot_commit);
|
||||||
int dquot_release(struct dquot *dquot)
|
int dquot_release(struct dquot *dquot)
|
||||||
{
|
{
|
||||||
int ret = 0, ret2 = 0;
|
int ret = 0, ret2 = 0;
|
||||||
|
unsigned int memalloc;
|
||||||
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
struct quota_info *dqopt = sb_dqopt(dquot->dq_sb);
|
||||||
|
|
||||||
mutex_lock(&dquot->dq_lock);
|
mutex_lock(&dquot->dq_lock);
|
||||||
|
memalloc = memalloc_nofs_save();
|
||||||
/* Check whether we are not racing with some other dqget() */
|
/* Check whether we are not racing with some other dqget() */
|
||||||
if (dquot_is_busy(dquot))
|
if (dquot_is_busy(dquot))
|
||||||
goto out_dqlock;
|
goto out_dqlock;
|
||||||
|
|
@ -512,6 +521,7 @@ int dquot_release(struct dquot *dquot)
|
||||||
}
|
}
|
||||||
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
|
clear_bit(DQ_ACTIVE_B, &dquot->dq_flags);
|
||||||
out_dqlock:
|
out_dqlock:
|
||||||
|
memalloc_nofs_restore(memalloc);
|
||||||
mutex_unlock(&dquot->dq_lock);
|
mutex_unlock(&dquot->dq_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user