* [PATCH] mm: filemap: tighten dropbehind completion context check
@ 2026-08-20 14:29 Wenjie Qi
2026-08-20 14:34 ` Matthew Wilcox
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Wenjie Qi @ 2026-08-20 14:29 UTC (permalink / raw)
To: akpm
Cc: willy, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi
folio_end_dropbehind() uses in_task() to keep folio invalidation out of
interrupt context. Task context alone is not sufficient: preemption can
still be disabled, or the task can be in a preemptible RCU read-side
critical section, while filemap_end_dropbehind() may reach
folio_unmap_invalidate() and sleep.
Use the established conservative three-part atomic-context test: reject
preemptible RCU read-side sections, reject configurations without
PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe
completions retain the existing best-effort behavior and skip invalidation.
Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com>
---
mm/filemap.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/mm/filemap.c b/mm/filemap.c
index 6afec6368..0616057e6 100644
--- a/mm/filemap.c
+++ b/mm/filemap.c
@@ -45,6 +45,7 @@
#include <linux/migrate.h>
#include <linux/pipe_fs_i.h>
#include <linux/splice.h>
+#include <linux/rcupdate.h>
#include <linux/rcupdate_wait.h>
#include <linux/sched/mm.h>
#include <linux/sysctl.h>
@@ -1620,6 +1621,15 @@ static void filemap_end_dropbehind(struct folio *folio)
folio_unmap_invalidate(mapping, folio, 0);
}
+static bool folio_dropbehind_in_atomic(void)
+{
+ if (IS_ENABLED(CONFIG_PREEMPTION) && rcu_preempt_depth())
+ return true;
+ if (!IS_ENABLED(CONFIG_PREEMPT_COUNT))
+ return true;
+ return !preemptible();
+}
+
/*
* If folio was marked as dropbehind, then pages should be dropped when writeback
* completes. Do that now. If we fail, it's likely because of a big folio -
@@ -1631,13 +1641,12 @@ void folio_end_dropbehind(struct folio *folio)
return;
/*
- * Hitting !in_task() should not happen off RWF_DONTCACHE writeback,
- * but can happen if normal writeback just happens to find dirty folios
- * that were created as part of uncached writeback, and that writeback
- * would otherwise not need non-IRQ handling. Just skip the
+ * Hitting an atomic context should not happen from RWF_DONTCACHE
+ * writeback, but can happen if normal writeback just happens to find
+ * dirty folios created as part of uncached writeback. Just skip the
* invalidation in that case.
*/
- if (in_task() && folio_trylock(folio)) {
+ if (!folio_dropbehind_in_atomic() && folio_trylock(folio)) {
filemap_end_dropbehind(folio);
folio_unlock(folio);
}
--
2.43.0
^ permalink raw reply [flat|nested] 19+ messages in thread* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-20 14:29 [PATCH] mm: filemap: tighten dropbehind completion context check Wenjie Qi @ 2026-08-20 14:34 ` Matthew Wilcox 2026-08-21 1:23 ` Wenjie Qi 2026-08-29 1:10 ` Andrew Morton 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi 2 siblings, 1 reply; 19+ messages in thread From: Matthew Wilcox @ 2026-08-20 14:34 UTC (permalink / raw) To: Wenjie Qi Cc: akpm, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi On Thu, Aug 20, 2026 at 10:29:56PM +0800, Wenjie Qi wrote: > folio_end_dropbehind() uses in_task() to keep folio invalidation out of > interrupt context. Task context alone is not sufficient: preemption can > still be disabled, or the task can be in a preemptible RCU read-side > critical section, while filemap_end_dropbehind() may reach > folio_unmap_invalidate() and sleep. > > Use the established conservative three-part atomic-context test: reject > preemptible RCU read-side sections, reject configurations without > PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe > completions retain the existing best-effort behavior and skip invalidation. Have you seen this happen in practice, or is this based on code examination? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-20 14:34 ` Matthew Wilcox @ 2026-08-21 1:23 ` Wenjie Qi 2026-08-21 3:30 ` Matthew Wilcox 0 siblings, 1 reply; 19+ messages in thread From: Wenjie Qi @ 2026-08-21 1:23 UTC (permalink / raw) To: Matthew Wilcox Cc: akpm, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi This is based on code examination; I have not reproduced it in folio_end_dropbehind(). There is an analogous EROFS report where bio completion ran under an RCU read-side critical section and hit a sleeping-function warning even though in_atomic() and preempt_count were both zero: https://lore.kernel.org/r/20230621220848.3379029-1-dhavale@google.com That is not a reproducer for this path, but it shows why task context alone does not establish that sleeping is safe. Here, folio_unmap_invalidate() can reach unmap_mapping_folio(), which takes mapping->i_mmap_rwsem through i_mmap_lock_read(). I noticed the mismatch while comparing this path with the stricter bio_in_atomic() check used by the block dropbehind work. On Thu, Aug 20, 2026 at 10:34 PM Matthew Wilcox <willy@infradead.org> wrote: > > On Thu, Aug 20, 2026 at 10:29:56PM +0800, Wenjie Qi wrote: > > folio_end_dropbehind() uses in_task() to keep folio invalidation out of > > interrupt context. Task context alone is not sufficient: preemption can > > still be disabled, or the task can be in a preemptible RCU read-side > > critical section, while filemap_end_dropbehind() may reach > > folio_unmap_invalidate() and sleep. > > > > Use the established conservative three-part atomic-context test: reject > > preemptible RCU read-side sections, reject configurations without > > PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe > > completions retain the existing best-effort behavior and skip invalidation. > > Have you seen this happen in practice, or is this based on code > examination? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-21 1:23 ` Wenjie Qi @ 2026-08-21 3:30 ` Matthew Wilcox 2026-08-24 13:34 ` Wenjie Qi 0 siblings, 1 reply; 19+ messages in thread From: Matthew Wilcox @ 2026-08-21 3:30 UTC (permalink / raw) To: Wenjie Qi Cc: akpm, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi On Fri, Aug 21, 2026 at 09:23:12AM +0800, Wenjie Qi wrote: > This is based on code examination; I have not reproduced it in > folio_end_dropbehind(). > There is an analogous EROFS report where bio completion ran under an RCU > read-side critical section and hit a sleeping-function warning even though > in_atomic() and preempt_count were both zero: > > https://lore.kernel.org/r/20230621220848.3379029-1-dhavale@google.com > > That is not a reproducer for this path, but it shows why task context alone > does not establish that sleeping is safe. Here, folio_unmap_invalidate() can > reach unmap_mapping_folio(), which takes mapping->i_mmap_rwsem through > i_mmap_lock_read(). I noticed the mismatch while comparing this path with > the stricter bio_in_atomic() check used by the block dropbehind work. So your analysis is right as far as it goes. But if a folio has been marked as dropbehind, but was then mmaped, we clearly shouldn't be discarding it! I believe that we'll clear the dropbehind flag in __filemap_get_folio_mpol(), called from filemap_get_folio() called from filemap_fault(). If you can find a way to get a folio with both dropbehind & mapped set, I'm interested in hearing how. > On Thu, Aug 20, 2026 at 10:34 PM Matthew Wilcox <willy@infradead.org> wrote: > > > > On Thu, Aug 20, 2026 at 10:29:56PM +0800, Wenjie Qi wrote: > > > folio_end_dropbehind() uses in_task() to keep folio invalidation out of > > > interrupt context. Task context alone is not sufficient: preemption can > > > still be disabled, or the task can be in a preemptible RCU read-side > > > critical section, while filemap_end_dropbehind() may reach > > > folio_unmap_invalidate() and sleep. > > > > > > Use the established conservative three-part atomic-context test: reject > > > preemptible RCU read-side sections, reject configurations without > > > PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe > > > completions retain the existing best-effort behavior and skip invalidation. > > > > Have you seen this happen in practice, or is this based on code > > examination? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-21 3:30 ` Matthew Wilcox @ 2026-08-24 13:34 ` Wenjie Qi 0 siblings, 0 replies; 19+ messages in thread From: Wenjie Qi @ 2026-08-24 13:34 UTC (permalink / raw) To: Matthew Wilcox Cc: akpm, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi I think fault-around provides such a path. do_read_fault() calls do_fault_around() before ->fault. For generic file mappings this reaches filemap_map_pages(), which walks mapping->i_pages directly and maps ready folios without going through __filemap_get_folio_mpol(). It does not clear dropbehind or exclude dirty or writeback folios. If the mapped PTE range covers vmf->address, filemap_map_pages() returns VM_FAULT_NOPAGE, so do_read_fault() does not fall back to filemap_fault(). Both the faulting folio and speculative neighboring folios can therefore be mapped while retaining dropbehind. A fault-around PTE does not necessarily mean that every mapped folio was accessed, since neighboring folios are mapped speculatively. So I do not think folio_mapped() alone is sufficient to cancel dropbehind. Clearing it for the folio covering vmf->address may be more precise, but that would be a separate semantic change. If this distinction makes sense, I can send an RFC to clear dropbehind for the faulting folio in filemap_map_pages(). On Fri, Aug 21, 2026 at 11:30 AM Matthew Wilcox <willy@infradead.org> wrote: > > On Fri, Aug 21, 2026 at 09:23:12AM +0800, Wenjie Qi wrote: > > This is based on code examination; I have not reproduced it in > > folio_end_dropbehind(). > > There is an analogous EROFS report where bio completion ran under an RCU > > read-side critical section and hit a sleeping-function warning even though > > in_atomic() and preempt_count were both zero: > > > > https://lore.kernel.org/r/20230621220848.3379029-1-dhavale@google.com > > > > That is not a reproducer for this path, but it shows why task context alone > > does not establish that sleeping is safe. Here, folio_unmap_invalidate() can > > reach unmap_mapping_folio(), which takes mapping->i_mmap_rwsem through > > i_mmap_lock_read(). I noticed the mismatch while comparing this path with > > the stricter bio_in_atomic() check used by the block dropbehind work. > > So your analysis is right as far as it goes. But if a folio has > been marked as dropbehind, but was then mmaped, we clearly shouldn't > be discarding it! I believe that we'll clear the dropbehind flag in > __filemap_get_folio_mpol(), called from filemap_get_folio() called from > filemap_fault(). > > If you can find a way to get a folio with both dropbehind & mapped set, > I'm interested in hearing how. > > > On Thu, Aug 20, 2026 at 10:34 PM Matthew Wilcox <willy@infradead.org> wrote: > > > > > > On Thu, Aug 20, 2026 at 10:29:56PM +0800, Wenjie Qi wrote: > > > > folio_end_dropbehind() uses in_task() to keep folio invalidation out of > > > > interrupt context. Task context alone is not sufficient: preemption can > > > > still be disabled, or the task can be in a preemptible RCU read-side > > > > critical section, while filemap_end_dropbehind() may reach > > > > folio_unmap_invalidate() and sleep. > > > > > > > > Use the established conservative three-part atomic-context test: reject > > > > preemptible RCU read-side sections, reject configurations without > > > > PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe > > > > completions retain the existing best-effort behavior and skip invalidation. > > > > > > Have you seen this happen in practice, or is this based on code > > > examination? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-20 14:29 [PATCH] mm: filemap: tighten dropbehind completion context check Wenjie Qi 2026-08-20 14:34 ` Matthew Wilcox @ 2026-08-29 1:10 ` Andrew Morton 2026-08-29 12:13 ` Wenjie Qi 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi 2 siblings, 1 reply; 19+ messages in thread From: Andrew Morton @ 2026-08-29 1:10 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, Wenjie Qi On Thu, 20 Aug 2026 22:29:56 +0800 Wenjie Qi <qwjhust@gmail.com> wrote: > folio_end_dropbehind() uses in_task() to keep folio invalidation out of > interrupt context. Task context alone is not sufficient: preemption can > still be disabled, or the task can be in a preemptible RCU read-side > critical section, while filemap_end_dropbehind() may reach > folio_unmap_invalidate() and sleep. > > Use the established conservative three-part atomic-context test: reject > preemptible RCU read-side sections, reject configurations without > PREEMPT_COUNT, and otherwise require a preemptible context. Unsafe > completions retain the existing best-effort behavior and skip invalidation. > > ... > > +static bool folio_dropbehind_in_atomic(void) > +{ > + if (IS_ENABLED(CONFIG_PREEMPTION) && rcu_preempt_depth()) > + return true; > + if (!IS_ENABLED(CONFIG_PREEMPT_COUNT)) > + return true; > + return !preemptible(); > +} Cripes. There's nothing mm-specific about this function. If we have a use-case for such a thing then surely the function should be kernel-wide, it should live at the sched/rcu/etc layer and it should be elaborately documented? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-29 1:10 ` Andrew Morton @ 2026-08-29 12:13 ` Wenjie Qi 2026-08-30 8:45 ` Barry Song 0 siblings, 1 reply; 19+ messages in thread From: Wenjie Qi @ 2026-08-29 12:13 UTC (permalink / raw) To: akpm; +Cc: willy, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, qiwenjie I kept the helper private to avoid an MM dependency on <linux/bio.h>. After looking further at the mapped-folio case Matthew raised, I think the better fix is to retain a dropbehind folio once it is mapped. A mapping represents a competing cached user, and retaining it avoids the sleeping unmap path, so filemap no longer needs a stricter context helper; the existing in_task() guard remains. I will respin the patch on that basis. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH] mm: filemap: tighten dropbehind completion context check 2026-08-29 12:13 ` Wenjie Qi @ 2026-08-30 8:45 ` Barry Song 0 siblings, 0 replies; 19+ messages in thread From: Barry Song @ 2026-08-30 8:45 UTC (permalink / raw) To: Wenjie Qi Cc: akpm, willy, jack, linux-fsdevel, linux-mm, linux-kernel, qiwenjie On Sat, Aug 29, 2026 at 8:13 PM Wenjie Qi <qwjhust@gmail.com> wrote: > > I kept the helper private to avoid an MM dependency on <linux/bio.h>. > > After looking further at the mapped-folio case Matthew raised, I think the > better fix is to retain a dropbehind folio once it is mapped. A mapping > represents a competing cached user, and retaining it avoids the sleeping > unmap path, so filemap no longer needs a stricter context helper; the > existing in_task() guard remains. I will respin the patch on that basis. But we still have `bio_in_atomic()` in `include/linux/bio.h`: /** * bio_in_atomic - check if the current context is unsafe for bio completion * * Return: %true in atomic contexts (e.g. hard/soft IRQ, preempt-disabled); * %false when a bio can be safely completed in the current context. */ static inline bool bio_in_atomic(void) { if (IS_ENABLED(CONFIG_PREEMPTION) && rcu_preempt_depth()) return true; if (!IS_ENABLED(CONFIG_PREEMPT_COUNT)) return true; return !preemptible(); } Right now, it's used in three places, and I expect we'll see more users over time. 1 1925 block/bio.c <<bio_endio>> if (bio_flagged(bio, BIO_COMPLETE_IN_TASK) && bio_in_atomic()) 2 1451 fs/erofs/zdata.c <<z_erofs_decompress_kickoff>> if (bio_in_atomic()) { 3 403 include/linux/bio.h <<bio_complete_in_task>> if (!bio_in_atomic()) Yet it really has nothing to do with `bio` at all; it's purely a scheduler thing! So I fully agree with Andrew that we should move it to `sched` and continue the discussion there. Maybe the current `in_atomic()` helpers aren't really good enough? Best Regards Barry ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2] mm: filemap: retain mapped dropbehind folios 2026-08-20 14:29 [PATCH] mm: filemap: tighten dropbehind completion context check Wenjie Qi 2026-08-20 14:34 ` Matthew Wilcox 2026-08-29 1:10 ` Andrew Morton @ 2026-08-29 12:30 ` Wenjie Qi 2026-08-29 14:47 ` Matthew Wilcox ` (2 more replies) 2 siblings, 3 replies; 19+ messages in thread From: Wenjie Qi @ 2026-08-29 12:30 UTC (permalink / raw) To: willy, jack, akpm Cc: linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, qiwenjie, qwjhust From: Wenjie Qi <qiwenjie@xiaomi.com> Fault-around can map ready dropbehind folios without going through the normal page-cache lookup that clears dropbehind. A mapping represents a competing cached user, so retain the folio instead of forcibly unmapping it when writeback completes. Unmapped dropbehind folios continue through the existing invalidation path. Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> --- Changes since v1: - Retain mapped folios instead of adding a stricter context predicate. - Remove the private helper and RCU include. mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 6afec636881f..00fd89cf6f55 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struct folio *folio) return; if (!folio_test_clear_dropbehind(folio)) return; - if (mapping) + if (mapping && !folio_mapped(folio)) folio_unmap_invalidate(mapping, folio, 0); } -- 2.43.0 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2] mm: filemap: retain mapped dropbehind folios 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi @ 2026-08-29 14:47 ` Matthew Wilcox 2026-08-29 15:53 ` Tal Zussman 2026-08-29 17:36 ` [PATCH v3] " Wenjie Qi 2 siblings, 0 replies; 19+ messages in thread From: Matthew Wilcox @ 2026-08-29 14:47 UTC (permalink / raw) To: Wenjie Qi Cc: jack, akpm, linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, qiwenjie On Sat, Aug 29, 2026 at 08:30:47PM +0800, Wenjie Qi wrote: > From: Wenjie Qi <qiwenjie@xiaomi.com> > > Fault-around can map ready dropbehind folios without going through the > normal page-cache lookup that clears dropbehind. A mapping represents a > competing cached user, so retain the folio instead of forcibly unmapping it > when writeback completes. > > Unmapped dropbehind folios continue through the existing invalidation path. Yes, I think this is the right approach. Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2] mm: filemap: retain mapped dropbehind folios 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi 2026-08-29 14:47 ` Matthew Wilcox @ 2026-08-29 15:53 ` Tal Zussman 2026-08-29 16:09 ` Tal Zussman 2026-08-29 17:36 ` [PATCH v3] " Wenjie Qi 2 siblings, 1 reply; 19+ messages in thread From: Tal Zussman @ 2026-08-29 15:53 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, akpm, linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, qiwenjie On Sat, 29 Aug 2026 20:30:47 +0800, Wenjie Qi <qwjhust@gmail.com> wrote: > Fault-around can map ready dropbehind folios without going through the > normal page-cache lookup that clears dropbehind. A mapping represents a > competing cached user, so retain the folio instead of forcibly unmapping it > when writeback completes. > > Unmapped dropbehind folios continue through the existing invalidation path. > > Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> Overall looks good to me. It may be nice to add a sentence about the safety aspect of this in the commit message. Maybe something like: folio_unmap_invalidate() may sleep if the folio is mapped, so this also ensures that folio_end_dropbehind() is safe to call from non-preemptible task context. Reviewed-by: Tal Zussman <tz2294@columbia.edu> -- Tal Zussman <tz2294@columbia.edu> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2] mm: filemap: retain mapped dropbehind folios 2026-08-29 15:53 ` Tal Zussman @ 2026-08-29 16:09 ` Tal Zussman 0 siblings, 0 replies; 19+ messages in thread From: Tal Zussman @ 2026-08-29 16:09 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, akpm, linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, qiwenjie On 8/29/26 6:53 PM, Tal Zussman wrote: > On Sat, 29 Aug 2026 20:30:47 +0800, Wenjie Qi <qwjhust@gmail.com> wrote: >> Fault-around can map ready dropbehind folios without going through the >> normal page-cache lookup that clears dropbehind. A mapping represents a >> competing cached user, so retain the folio instead of forcibly unmapping it >> when writeback completes. >> >> Unmapped dropbehind folios continue through the existing invalidation path. >> >> Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> > > Overall looks good to me. It may be nice to add a sentence about the > safety aspect of this in the commit message. Maybe something like: > > folio_unmap_invalidate() may sleep if the folio is mapped, so this > also ensures that folio_end_dropbehind() is safe to call from > non-preemptible task context. > > Reviewed-by: Tal Zussman <tz2294@columbia.edu> > And maybe: Fixes: fb7d3bc41493 ("mm/filemap: drop streaming/uncached pages when writeback completes") ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v3] mm: filemap: retain mapped dropbehind folios 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi 2026-08-29 14:47 ` Matthew Wilcox 2026-08-29 15:53 ` Tal Zussman @ 2026-08-29 17:36 ` Wenjie Qi 2026-08-29 18:16 ` Andrew Morton 2 siblings, 1 reply; 19+ messages in thread From: Wenjie Qi @ 2026-08-29 17:36 UTC (permalink / raw) To: willy, jack, akpm Cc: linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, tz2294, qiwenjie, qwjhust From: Wenjie Qi <qiwenjie@xiaomi.com> Fault-around can map ready dropbehind folios without going through the normal page-cache lookup that clears dropbehind. A mapping represents a competing cached user, so retain the folio instead of forcibly unmapping it when writeback completes. For a mapped folio, folio_unmap_invalidate() can call unmap_mapping_folio(), which takes i_mmap_rwsem and may sleep. Retaining mapped folios avoids this path when folio_end_dropbehind() runs in non-preemptible task context. Unmapped dropbehind folios continue through the existing invalidation path. Fixes: fb7d3bc41493 ("mm/filemap: drop streaming/uncached pages when writeback completes") Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reviewed-by: Tal Zussman <tz2294@columbia.edu> --- Changes since v2: - Explain why retaining mapped folios avoids a sleepable unmap path. - Add the Fixes and Reviewed-by trailers. mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 6afec636881f..00fd89cf6f55 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struct folio *folio) return; if (!folio_test_clear_dropbehind(folio)) return; - if (mapping) + if (mapping && !folio_mapped(folio)) folio_unmap_invalidate(mapping, folio, 0); } -- 2.43.0 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v3] mm: filemap: retain mapped dropbehind folios 2026-08-29 17:36 ` [PATCH v3] " Wenjie Qi @ 2026-08-29 18:16 ` Andrew Morton 2026-08-30 3:25 ` [PATCH v4] " Wenjie Qi 0 siblings, 1 reply; 19+ messages in thread From: Andrew Morton @ 2026-08-29 18:16 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, linux-fsdevel, linux-mm, linux-kernel, baohua, axboe, trond.myklebust, tz2294, qiwenjie On Sun, 30 Aug 2026 01:36:12 +0800 Wenjie Qi <qwjhust@gmail.com> wrote: > From: Wenjie Qi <qiwenjie@xiaomi.com> > > Fault-around can map ready dropbehind folios without going through the > normal page-cache lookup that clears dropbehind. A mapping represents a > competing cached user, so retain the folio instead of forcibly unmapping it > when writeback completes. > > For a mapped folio, folio_unmap_invalidate() can call > unmap_mapping_folio(), which takes i_mmap_rwsem and may sleep. Retaining > mapped folios avoids this path when folio_end_dropbehind() runs in > non-preemptible task context. > > Unmapped dropbehind folios continue through the existing invalidation path. Thanks. When fixing a bug, please always provide a very clear description of the userspace-visible runtime effects of that bug. From the above it appears that the current code can trigger a sleeping-in-atomic warning? Has this been observed in any situation? Is there a report? chatgpt easily prepared a reproducer for me, which I haven't run. If I'm correct in the above, we should backport this fix with a cc:stable tag, do you agree? ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v4] mm: filemap: retain mapped dropbehind folios 2026-08-29 18:16 ` Andrew Morton @ 2026-08-30 3:25 ` Wenjie Qi 2026-08-30 8:35 ` Barry Song 2026-08-30 11:58 ` Tal Zussman 0 siblings, 2 replies; 19+ messages in thread From: Wenjie Qi @ 2026-08-30 3:25 UTC (permalink / raw) To: willy, jack, akpm Cc: linux-fsdevel, linux-mm, linux-kernel, stable, baohua, axboe, trond.myklebust, tz2294, jaegeuk, chao, qiwenjie, qwjhust From: Wenjie Qi <qiwenjie@xiaomi.com> Fault-around can map ready dropbehind folios without going through the normal page-cache lookup that clears dropbehind. A mapping represents a competing cached user, but writeback completion can currently unmap that folio. A later mmap access must then fault it back in. Retain mapped folios instead. For a mapped folio, folio_unmap_invalidate() can call unmap_mapping_folio(), which takes i_mmap_rwsem and may sleep. Retaining the folio also avoids this path when folio_end_dropbehind() runs in non-preemptible task context. Unmapped dropbehind folios continue through the existing invalidation path. Fixes: fb7d3bc41493 ("mm/filemap: drop streaming/uncached pages when writeback completes") Cc: stable@vger.kernel.org Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> Reviewed-by: Tal Zussman <tz2294@columbia.edu> --- The mapped-plus-dropbehind state was reproduced in QEMU. The patched kernel retained the mapped folio and continued to evict the unmapped dontcache folio. I did not reproduce the sleeping-in-atomic warning and am not aware of an existing report. Changes since v3: - Describe the forced-unmap/refault runtime effect. - Record the reproduction boundary and add Cc: stable@vger.kernel.org. mm/filemap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm/filemap.c b/mm/filemap.c index 6afec636881f..00fd89cf6f55 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struct folio *folio) return; if (!folio_test_clear_dropbehind(folio)) return; - if (mapping) + if (mapping && !folio_mapped(folio)) folio_unmap_invalidate(mapping, folio, 0); } -- 2.43.0 ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4] mm: filemap: retain mapped dropbehind folios 2026-08-30 3:25 ` [PATCH v4] " Wenjie Qi @ 2026-08-30 8:35 ` Barry Song 2026-08-30 9:13 ` Wenjie Qi 2026-08-30 11:58 ` Tal Zussman 1 sibling, 1 reply; 19+ messages in thread From: Barry Song @ 2026-08-30 8:35 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, akpm, linux-fsdevel, linux-mm, linux-kernel, stable, axboe, trond.myklebust, tz2294, jaegeuk, chao, qiwenjie On Sun, Aug 30, 2026 at 11:25 AM Wenjie Qi <qwjhust@gmail.com> wrote: > > From: Wenjie Qi <qiwenjie@xiaomi.com> > > Fault-around can map ready dropbehind folios without going through the > normal page-cache lookup that clears dropbehind. A mapping represents a > competing cached user, but writeback completion can currently unmap that > folio. A later mmap access must then fault it back in. Andrew is asking for a visible user-facing impact. I think the current mainline code might result in an extra fault-in and extra I/O. Maybe we should highlight this? On the other hand, my gut feeling is that this patch might only be 50% right, rather than 100% right. Fault-around might just end up mapping data that will never be accessed at all (fault-around mappings aren't really fault-mapped), while the user has explicitly requested "dropbehind", which seems like a strong hint that they don't need it :-) > > Retain mapped folios instead. For a mapped folio, > folio_unmap_invalidate() can call unmap_mapping_folio(), which takes > i_mmap_rwsem and may sleep. Retaining the folio also avoids this path when > folio_end_dropbehind() runs in non-preemptible task context. > I'm not quite sure this can be entirely avoided. Somehow, `folio_launder(mapping, folio)` could also be nasty. For example, NFS can still be problematic today: static int nfs_launder_folio(struct folio *folio) { struct inode *inode = folio->mapping->host; int ret; dfprintk(PAGECACHE, "NFS: launder_folio(%llu, %llu)\n", inode->i_ino, folio_pos(folio)); folio_wait_private_2(folio); /* [DEPRECATED] */ ret = nfs_wb_folio(inode, folio); trace_nfs_launder_folio_done(inode, folio_pos(folio), folio_size(folio), ret); return ret; } Best Regards Barry ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4] mm: filemap: retain mapped dropbehind folios 2026-08-30 8:35 ` Barry Song @ 2026-08-30 9:13 ` Wenjie Qi 2026-08-30 9:31 ` Barry Song 0 siblings, 1 reply; 19+ messages in thread From: Wenjie Qi @ 2026-08-30 9:13 UTC (permalink / raw) To: baohua Cc: willy, jack, akpm, linux-fsdevel, linux-mm, linux-kernel, stable, axboe, trond.myklebust, tz2294, jaegeuk, chao, qiwenjie, qwjhust Yes. The current path removes the folio from the page cache, so a later mmap access can incur both another fault and I/O. I should have stated that explicitly. For fault-around neighbors, folio_mapped() cannot distinguish the faulting page from a speculative neighbor. This patch takes the conservative policy that an installed PTE represents a competing cache user and wins over the writer's RWF_DONTCACHE hint. It can therefore retain a speculative neighbor which is never accessed. Distinguishing those cases seems to require fault-around to preserve the faulting folio while not mapping, or later dropping, dropbehind neighbors. I think that should be considered as a separate follow-up. For folio_launder(), filemap_end_dropbehind() holds the folio lock and returns if the folio is dirty or under writeback before calling folio_unmap_invalidate(). folio_launder() also immediately returns for a clean folio. I do not see how nfs_launder_folio() is reached from this completion path unless the locked, unmapped folio can become dirty between those checks. Is there a path I am missing? ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4] mm: filemap: retain mapped dropbehind folios 2026-08-30 9:13 ` Wenjie Qi @ 2026-08-30 9:31 ` Barry Song 0 siblings, 0 replies; 19+ messages in thread From: Barry Song @ 2026-08-30 9:31 UTC (permalink / raw) To: Wenjie Qi Cc: willy, jack, akpm, linux-fsdevel, linux-mm, linux-kernel, stable, axboe, trond.myklebust, tz2294, jaegeuk, chao, qiwenjie On Sun, Aug 30, 2026 at 5:13 PM Wenjie Qi <qwjhust@gmail.com> wrote: > > Yes. The current path removes the folio from the page cache, so a later > mmap access can incur both another fault and I/O. I should have stated > that explicitly. > > For fault-around neighbors, folio_mapped() cannot distinguish the faulting > page from a speculative neighbor. This patch takes the conservative policy > that an installed PTE represents a competing cache user and wins over the > writer's RWF_DONTCACHE hint. It can therefore retain a speculative neighbor > which is never accessed. Distinguishing those cases seems to require > fault-around to preserve the faulting folio while not mapping, or later > dropping, dropbehind neighbors. I think that should be considered as a > separate follow-up. Yes. Maybe we can skip mapping neighbors with the dropbehind flag in fault-around. > > For folio_launder(), filemap_end_dropbehind() holds the folio lock and returns > if the folio is dirty or under writeback before calling > folio_unmap_invalidate(). folio_launder() also immediately returns for a > clean folio. I do not see how nfs_launder_folio() is reached from this > completion path unless the locked, unmapped folio can become dirty between > those checks. Is there a path I am missing? You are probably right. I was referring to the bit wait in nfs_launder_folio(), though I'm not quite sure whether this can actually happen: folio_wait_private_2(folio); /* [DEPRECATED] */ I assume we won't wait for `private_2` while the folio is clean. If so, it should be fine. ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v4] mm: filemap: retain mapped dropbehind folios 2026-08-30 3:25 ` [PATCH v4] " Wenjie Qi 2026-08-30 8:35 ` Barry Song @ 2026-08-30 11:58 ` Tal Zussman 1 sibling, 0 replies; 19+ messages in thread From: Tal Zussman @ 2026-08-30 11:58 UTC (permalink / raw) To: Wenjie Qi, willy, jack, akpm Cc: linux-fsdevel, linux-mm, linux-kernel, stable, baohua, axboe, trond.myklebust, jaegeuk, chao, qiwenjie On 8/30/26 6:25 AM, Wenjie Qi wrote: > From: Wenjie Qi <qiwenjie@ xiaomi. com> Fault-around can map ready dropbehind > folios without going through the normal page-cache lookup that clears > dropbehind. A mapping represents a competing cached user, but writeback > completion can currently > ZjQcmQRYFpfptBannerStart > This Message Is From an External Sender > This message came from outside your organization. > ZjQcmQRYFpfptBannerEnd > > From: Wenjie Qi <qiwenjie@xiaomi.com> > > Fault-around can map ready dropbehind folios without going through the > normal page-cache lookup that clears dropbehind. A mapping represents a > competing cached user, but writeback completion can currently unmap that > folio. A later mmap access must then fault it back in. > > Retain mapped folios instead. For a mapped folio, > folio_unmap_invalidate() can call unmap_mapping_folio(), which takes > i_mmap_rwsem and may sleep. Retaining the folio also avoids this path when > folio_end_dropbehind() runs in non-preemptible task context. > > Unmapped dropbehind folios continue through the existing invalidation path. > > Fixes: fb7d3bc41493 ("mm/filemap: drop streaming/uncached pages when writeback completes") > Cc: stable@vger.kernel.org > Signed-off-by: Wenjie Qi <qiwenjie@xiaomi.com> > Reviewed-by: Matthew Wilcox (Oracle) <willy@infradead.org> > Reviewed-by: Tal Zussman <tz2294@columbia.edu> > --- > The mapped-plus-dropbehind state was reproduced in QEMU. The patched > kernel retained the mapped folio and continued to evict the unmapped > dontcache folio. I did not reproduce the sleeping-in-atomic warning and > am not aware of an existing report. > I was able to trigger the sleeping-while-atomic BUG on current mainline with some help from Claude. The reproducer itself is straightforward enough, but the configuration was a little finicky. The atomic context comes from using threadirqs so that virtblk_done() completes requests from the irq thread under local_bh_disable() and the vq spinlock with irqs off, so in_task() is true but the i_mmap_rwsem down_read() sleeps. It also needed 1 vCPU (so completion stays in the irq thread rather than softirq) and ext4 -o dioread_lock (so end_io runs inline instead of on a workqueue). With v4 applied the bug is gone, so: Tested-by: Tal Zussman <tz2294@columbia.edu> Full splat: [ 46.745106] BUG: sleeping function called from invalid context at kernel/locking/rwsem.c:1573 [ 46.745183] in_atomic(): 1, irqs_disabled(): 1, non_block: 0, pid: 61, name: irq/40-virtio1- [ 46.745211] preempt_count: 201, expected: 0 [ 46.745233] RCU nest depth: 0, expected: 0 [ 46.745292] locks held by irq/40-virtio1-/61: 1, last CPU#0: [ 46.745324] #0: ff1fce9901fc2f20 (&vblk->vqs[i].lock){....}-{3:3}, at: virtblk_done+0x56/0x100 [ 46.746801] irq event stamp: 1585 [ 46.748015] hardirqs last enabled at (1583): [<ffffffff88dc7c54>] finish_task_switch.isra.0+0xd4/0x360 [ 46.748224] hardirqs last disabled at (1585): [<ffffffff88e2b16c>] irq_forced_thread_fn+0x5c/0x60 [ 46.748405] softirqs last enabled at (1578): [<ffffffff88e2b159>] irq_forced_thread_fn+0x49/0x60 [ 46.748580] softirqs last disabled at (1584): [<ffffffff88e2b12d>] irq_forced_thread_fn+0x1d/0x60 [ 46.749233] CPU: 0 UID: 0 PID: 61 Comm: irq/40-virtio1- Not tainted 7.2.0+ #5 PREEMPT(full) [ 46.749323] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 46.749472] Call Trace: [ 46.749552] <TASK> [ 46.749653] dump_stack_lvl+0x66/0xa0 [ 46.749747] __might_resched+0x154/0x260 [ 46.749787] down_read+0x1e/0x170 [ 46.749806] unmap_mapping_folio+0x74/0xd0 [ 46.749854] folio_unmap_invalidate+0x92/0x200 [ 46.749886] folio_end_writeback+0x51/0xb0 [ 46.749906] ext4_finish_bio+0x36d/0x3a0 [ 46.749979] ext4_end_bio+0x51/0x140 [ 46.750010] blk_update_request+0x101/0x4d0 [ 46.750045] ? detach_buf_split_in_order+0x18c/0x1b0 [ 46.750098] blk_mq_end_request+0x20/0x130 [ 46.750135] virtblk_done+0x75/0x100 [ 46.750173] ? irq_thread+0xb3/0x2a0 [ 46.750190] vring_interrupt+0x8c/0xd0 [ 46.750205] irq_thread_fn+0x23/0x60 [ 46.750238] irq_forced_thread_fn+0x35/0x60 [ 46.750261] irq_thread+0x17c/0x2a0 [ 46.750274] ? __pfx_irq_forced_thread_fn+0x10/0x10 [ 46.750299] ? __pfx_irq_thread_dtor+0x10/0x10 [ 46.750333] ? __pfx_irq_thread+0x10/0x10 [ 46.750353] kthread+0xf6/0x130 [ 46.750369] ? __pfx_kthread+0x10/0x10 [ 46.750404] ret_from_fork+0x248/0x350 [ 46.750421] ? __pfx_kthread+0x10/0x10 [ 46.750442] ret_from_fork_asm+0x1a/0x30 [ 46.750585] </TASK> [ 46.752964] ============================= [ 46.753047] [ BUG: Invalid wait context ] [ 46.753230] 7.2.0+ #5 Tainted: G W [ 46.753353] ----------------------------- [ 46.753438] irq/40-virtio1-/61 is trying to lock: [ 46.753533] ff1fce99004e4990 (&mapping->i_mmap_rwsem){++++}-{4:4}, at: unmap_mapping_folio+0x74/0xd0 [ 46.753882] other info that might help us debug this: [ 46.754000] context-{5:5} [ 46.754062] locks held by irq/40-virtio1-/61: 1, last CPU#0: [ 46.754171] #0: ff1fce9901fc2f20 (&vblk->vqs[i].lock){....}-{3:3}, at: virtblk_done+0x56/0x100 [ 46.754371] stack backtrace: [ 46.754441] CPU: 0 UID: 0 PID: 61 Comm: irq/40-virtio1- Tainted: G W 7.2.0+ #5 PREEMPT(full) [ 46.754656] Tainted: [W]=WARN [ 46.754725] Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 46.754887] Call Trace: [ 46.754942] <TASK> [ 46.754996] dump_stack_lvl+0x66/0xa0 [ 46.755082] __lock_acquire+0x92e/0x1a80 [ 46.755197] lock_acquire+0xcd/0x2d0 [ 46.755282] ? unmap_mapping_folio+0x74/0xd0 [ 46.755403] down_read+0x42/0x170 [ 46.755476] ? unmap_mapping_folio+0x74/0xd0 [ 46.755565] unmap_mapping_folio+0x74/0xd0 [ 46.755664] folio_unmap_invalidate+0x92/0x200 [ 46.755763] folio_end_writeback+0x51/0xb0 [ 46.755851] ext4_finish_bio+0x36d/0x3a0 [ 46.755958] ext4_end_bio+0x51/0x140 [ 46.756043] blk_update_request+0x101/0x4d0 [ 46.756135] ? detach_buf_split_in_order+0x18c/0x1b0 [ 46.756254] blk_mq_end_request+0x20/0x130 [ 46.756349] virtblk_done+0x75/0x100 [ 46.756438] ? irq_thread+0xb3/0x2a0 [ 46.756515] vring_interrupt+0x8c/0xd0 [ 46.756595] irq_thread_fn+0x23/0x60 [ 46.756678] irq_forced_thread_fn+0x35/0x60 [ 46.756768] irq_thread+0x17c/0x2a0 [ 46.756842] ? __pfx_irq_forced_thread_fn+0x10/0x10 [ 46.756945] ? __pfx_irq_thread_dtor+0x10/0x10 [ 46.757045] ? __pfx_irq_thread+0x10/0x10 [ 46.757136] kthread+0xf6/0x130 [ 46.757207] ? __pfx_kthread+0x10/0x10 [ 46.757302] ret_from_fork+0x248/0x350 [ 46.757383] ? __pfx_kthread+0x10/0x10 [ 46.757466] ret_from_fork_asm+0x1a/0x30 [ 46.757594] </TASK> > Changes since v3: > - Describe the forced-unmap/refault runtime effect. > - Record the reproduction boundary and add Cc: stable@vger.kernel.org. > > mm/filemap.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/mm/filemap.c b/mm/filemap.c > index 6afec636881f..00fd89cf6f55 100644 > --- a/mm/filemap.c > +++ b/mm/filemap.c > @@ -1616,7 +1616,7 @@ static void filemap_end_dropbehind(struct folio *folio) > return; > if (!folio_test_clear_dropbehind(folio)) > return; > - if (mapping) > + if (mapping && !folio_mapped(folio)) > folio_unmap_invalidate(mapping, folio, 0); > } > > -- > 2.43.0 > ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-08-30 11:59 UTC | newest] Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2026-08-20 14:29 [PATCH] mm: filemap: tighten dropbehind completion context check Wenjie Qi 2026-08-20 14:34 ` Matthew Wilcox 2026-08-21 1:23 ` Wenjie Qi 2026-08-21 3:30 ` Matthew Wilcox 2026-08-24 13:34 ` Wenjie Qi 2026-08-29 1:10 ` Andrew Morton 2026-08-29 12:13 ` Wenjie Qi 2026-08-30 8:45 ` Barry Song 2026-08-29 12:30 ` [PATCH v2] mm: filemap: retain mapped dropbehind folios Wenjie Qi 2026-08-29 14:47 ` Matthew Wilcox 2026-08-29 15:53 ` Tal Zussman 2026-08-29 16:09 ` Tal Zussman 2026-08-29 17:36 ` [PATCH v3] " Wenjie Qi 2026-08-29 18:16 ` Andrew Morton 2026-08-30 3:25 ` [PATCH v4] " Wenjie Qi 2026-08-30 8:35 ` Barry Song 2026-08-30 9:13 ` Wenjie Qi 2026-08-30 9:31 ` Barry Song 2026-08-30 11:58 ` Tal Zussman
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®