mm: skip reclaiming folios in legacy memcg writeback indeterminate contexts

Currently in shrink_folio_list(), reclaim for folios under writeback falls
into 3 different cases:

1) Reclaim is encountering an excessive number of folios under
   writeback and this folio has both the writeback and reclaim flags
   set
2) Dirty throttling is enabled (this happens if reclaim through cgroup
   is not enabled, if reclaim through cgroupv2 memcg is enabled, or
   if reclaim is on the root cgroup), or if the folio is not marked for
   immediate reclaim, or if the caller does not have __GFP_FS (or
   __GFP_IO if it's going to swap) set
3) Legacy cgroupv1 encounters a folio that already has the reclaim flag
   set and the caller did not have __GFP_FS (or __GFP_IO if swap) set

In cases 1) and 2), we activate the folio and skip reclaiming it while in
case 3), we wait for writeback to finish on the folio and then try to
reclaim the folio again.  In case 3, we wait on writeback because cgroupv1
does not have dirty folio throttling, as such this is a mitigation against
the case where there are too many folios in writeback with nothing else to
reclaim.

For filesystems where writeback may take an indeterminate amount of time
to write to disk, this has the possibility of stalling reclaim.

In this commit, if legacy memcg encounters a folio with the reclaim flag
set (eg case 3) and the folio belongs to a mapping that has the
AS_WRITEBACK_INDETERMINATE flag set, the folio will be activated and skip
reclaim (eg default to behavior in case 2) instead.

Link: https://lkml.kernel.org/r/20241122232359.429647-3-joannelkoong@gmail.com
Signed-off-by: Joanne Koong <joannelkoong@gmail.com>
Reviewed-by: Shakeel Butt <shakeel.butt@linux.dev>
Acked-by: Miklos Szeredi <mszeredi@redhat.com>
Cc: Bernd Schubert <bernd.schubert@fastmail.fm>
Cc: Jingbo Xu <jefflexu@linux.alibaba.com>
Cc: Josef Bacik <josef@toxicpanda.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
This commit is contained in:
Joanne Koong 2024-11-22 15:23:56 -08:00 committed by Andrew Morton
parent f43af7765e
commit 26942ed372

View File

@ -1165,8 +1165,9 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
* 2) Global or new memcg reclaim encounters a folio that is * 2) Global or new memcg reclaim encounters a folio that is
* not marked for immediate reclaim, or the caller does not * not marked for immediate reclaim, or the caller does not
* have __GFP_FS (or __GFP_IO if it's simply going to swap, * have __GFP_FS (or __GFP_IO if it's simply going to swap,
* not to fs). In this case mark the folio for immediate * not to fs), or the writeback may take an indeterminate
* reclaim and continue scanning. * amount of time to complete. In this case mark the folio
* for immediate reclaim and continue scanning.
* *
* Require may_enter_fs() because we would wait on fs, which * Require may_enter_fs() because we would wait on fs, which
* may not have submitted I/O yet. And the loop driver might * may not have submitted I/O yet. And the loop driver might
@ -1191,6 +1192,8 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
* takes to write them to disk. * takes to write them to disk.
*/ */
if (folio_test_writeback(folio)) { if (folio_test_writeback(folio)) {
mapping = folio_mapping(folio);
/* Case 1 above */ /* Case 1 above */
if (current_is_kswapd() && if (current_is_kswapd() &&
folio_test_reclaim(folio) && folio_test_reclaim(folio) &&
@ -1201,7 +1204,8 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
/* Case 2 above */ /* Case 2 above */
} else if (writeback_throttling_sane(sc) || } else if (writeback_throttling_sane(sc) ||
!folio_test_reclaim(folio) || !folio_test_reclaim(folio) ||
!may_enter_fs(folio, sc->gfp_mask)) { !may_enter_fs(folio, sc->gfp_mask) ||
(mapping && mapping_writeback_indeterminate(mapping))) {
/* /*
* This is slightly racy - * This is slightly racy -
* folio_end_writeback() might have * folio_end_writeback() might have