Skip to content

Commit 0c4f8ed

Browse files
joannekoongMiklos Szeredi
authored andcommitted
mm: skip folio reclaim in legacy memcg contexts for deadlockable mappings
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. If a filesystem (eg fuse) may deadlock due to reclaim waiting on writeback, then the filesystem needs to add inefficient messy workarounds to prevent this. To improve the performance of these filesystems, this commit adds two things: a) a AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM mapping flag that filesystems may set to indicate that reclaim should not wait on writeback b) if legacy memcg encounters a folio with this AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM flag set (eg case 3), the folio will be activated and skip reclaim (eg default to behavior in case 2) instead. Signed-off-by: Joanne Koong <[email protected]> Reviewed-by: Shakeel Butt <[email protected]> Reviewed-by: Jeff Layton <[email protected]> Acked-by: David Hildenbrand <[email protected]> Reviewed-by: Jingbo Xu <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 4fea593 commit 0c4f8ed

File tree

2 files changed

+20
-3
lines changed

2 files changed

+20
-3
lines changed

include/linux/pagemap.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ enum mapping_flags {
210210
AS_STABLE_WRITES = 7, /* must wait for writeback before modifying
211211
folio contents */
212212
AS_INACCESSIBLE = 8, /* Do not attempt direct R/W access to the mapping */
213+
AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM = 9,
213214
/* Bits 16-25 are used for FOLIO_ORDER */
214215
AS_FOLIO_ORDER_BITS = 5,
215216
AS_FOLIO_ORDER_MIN = 16,
@@ -335,6 +336,16 @@ static inline bool mapping_inaccessible(struct address_space *mapping)
335336
return test_bit(AS_INACCESSIBLE, &mapping->flags);
336337
}
337338

339+
static inline void mapping_set_writeback_may_deadlock_on_reclaim(struct address_space *mapping)
340+
{
341+
set_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags);
342+
}
343+
344+
static inline bool mapping_writeback_may_deadlock_on_reclaim(struct address_space *mapping)
345+
{
346+
return test_bit(AS_WRITEBACK_MAY_DEADLOCK_ON_RECLAIM, &mapping->flags);
347+
}
348+
338349
static inline gfp_t mapping_gfp_mask(struct address_space * mapping)
339350
{
340351
return mapping->gfp_mask;

mm/vmscan.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1187,8 +1187,10 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
11871187
* 2) Global or new memcg reclaim encounters a folio that is
11881188
* not marked for immediate reclaim, or the caller does not
11891189
* have __GFP_FS (or __GFP_IO if it's simply going to swap,
1190-
* not to fs). In this case mark the folio for immediate
1191-
* reclaim and continue scanning.
1190+
* not to fs), or the folio belongs to a mapping where
1191+
* waiting on writeback during reclaim may lead to a deadlock.
1192+
* In this case mark the folio for immediate reclaim and
1193+
* continue scanning.
11921194
*
11931195
* Require may_enter_fs() because we would wait on fs, which
11941196
* may not have submitted I/O yet. And the loop driver might
@@ -1213,6 +1215,8 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
12131215
* takes to write them to disk.
12141216
*/
12151217
if (folio_test_writeback(folio)) {
1218+
mapping = folio_mapping(folio);
1219+
12161220
/* Case 1 above */
12171221
if (current_is_kswapd() &&
12181222
folio_test_reclaim(folio) &&
@@ -1223,7 +1227,9 @@ static unsigned int shrink_folio_list(struct list_head *folio_list,
12231227
/* Case 2 above */
12241228
} else if (writeback_throttling_sane(sc) ||
12251229
!folio_test_reclaim(folio) ||
1226-
!may_enter_fs(folio, sc->gfp_mask)) {
1230+
!may_enter_fs(folio, sc->gfp_mask) ||
1231+
(mapping &&
1232+
mapping_writeback_may_deadlock_on_reclaim(mapping))) {
12271233
/*
12281234
* This is slightly racy -
12291235
* folio_end_writeback() might have

0 commit comments

Comments
 (0)