]>
Commit | Line | Data |
---|---|---|
5032628c GKH |
1 | From 62be1511b1db8066220b18b7d4da2e6b9fdc69fb Mon Sep 17 00:00:00 2001 |
2 | From: Vlastimil Babka <vbabka@suse.cz> | |
3 | Date: Mon, 8 May 2017 15:59:46 -0700 | |
4 | Subject: mm: prevent potential recursive reclaim due to clearing PF_MEMALLOC | |
5 | ||
6 | From: Vlastimil Babka <vbabka@suse.cz> | |
7 | ||
8 | commit 62be1511b1db8066220b18b7d4da2e6b9fdc69fb upstream. | |
9 | ||
10 | Patch series "more robust PF_MEMALLOC handling" | |
11 | ||
12 | This series aims to unify the setting and clearing of PF_MEMALLOC, which | |
13 | prevents recursive reclaim. There are some places that clear the flag | |
14 | unconditionally from current->flags, which may result in clearing a | |
15 | pre-existing flag. This already resulted in a bug report that Patch 1 | |
16 | fixes (without the new helpers, to make backporting easier). Patch 2 | |
17 | introduces the new helpers, modelled after existing memalloc_noio_* and | |
18 | memalloc_nofs_* helpers, and converts mm core to use them. Patches 3 | |
19 | and 4 convert non-mm code. | |
20 | ||
21 | This patch (of 4): | |
22 | ||
23 | __alloc_pages_direct_compact() sets PF_MEMALLOC to prevent deadlock | |
24 | during page migration by lock_page() (see the comment in | |
25 | __unmap_and_move()). Then it unconditionally clears the flag, which can | |
26 | clear a pre-existing PF_MEMALLOC flag and result in recursive reclaim. | |
27 | This was not a problem until commit a8161d1ed609 ("mm, page_alloc: | |
28 | restructure direct compaction handling in slowpath"), because direct | |
29 | compation was called only after direct reclaim, which was skipped when | |
30 | PF_MEMALLOC flag was set. | |
31 | ||
32 | Even now it's only a theoretical issue, as the new callsite of | |
33 | __alloc_pages_direct_compact() is reached only for costly orders and | |
34 | when gfp_pfmemalloc_allowed() is true, which means either | |
35 | __GFP_NOMEMALLOC is in gfp_flags or in_interrupt() is true. There is no | |
36 | such known context, but let's play it safe and make | |
37 | __alloc_pages_direct_compact() robust for cases where PF_MEMALLOC is | |
38 | already set. | |
39 | ||
40 | Fixes: a8161d1ed609 ("mm, page_alloc: restructure direct compaction handling in slowpath") | |
41 | Link: http://lkml.kernel.org/r/20170405074700.29871-2-vbabka@suse.cz | |
42 | Signed-off-by: Vlastimil Babka <vbabka@suse.cz> | |
43 | Reported-by: Andrey Ryabinin <aryabinin@virtuozzo.com> | |
44 | Acked-by: Michal Hocko <mhocko@suse.com> | |
45 | Acked-by: Hillf Danton <hillf.zj@alibaba-inc.com> | |
46 | Cc: Mel Gorman <mgorman@techsingularity.net> | |
47 | Cc: Johannes Weiner <hannes@cmpxchg.org> | |
48 | Cc: Boris Brezillon <boris.brezillon@free-electrons.com> | |
49 | Cc: Chris Leech <cleech@redhat.com> | |
50 | Cc: "David S. Miller" <davem@davemloft.net> | |
51 | Cc: Eric Dumazet <edumazet@google.com> | |
52 | Cc: Josef Bacik <jbacik@fb.com> | |
53 | Cc: Lee Duncan <lduncan@suse.com> | |
54 | Cc: Michal Hocko <mhocko@suse.com> | |
55 | Cc: Richard Weinberger <richard@nod.at> | |
56 | Signed-off-by: Andrew Morton <akpm@linux-foundation.org> | |
57 | Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> | |
58 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
59 | ||
60 | --- | |
61 | mm/page_alloc.c | 3 ++- | |
62 | 1 file changed, 2 insertions(+), 1 deletion(-) | |
63 | ||
64 | --- a/mm/page_alloc.c | |
65 | +++ b/mm/page_alloc.c | |
66 | @@ -3245,6 +3245,7 @@ __alloc_pages_direct_compact(gfp_t gfp_m | |
67 | enum compact_priority prio, enum compact_result *compact_result) | |
68 | { | |
69 | struct page *page; | |
70 | + unsigned int noreclaim_flag = current->flags & PF_MEMALLOC; | |
71 | ||
72 | if (!order) | |
73 | return NULL; | |
74 | @@ -3252,7 +3253,7 @@ __alloc_pages_direct_compact(gfp_t gfp_m | |
75 | current->flags |= PF_MEMALLOC; | |
76 | *compact_result = try_to_compact_pages(gfp_mask, order, alloc_flags, ac, | |
77 | prio); | |
78 | - current->flags &= ~PF_MEMALLOC; | |
79 | + current->flags = (current->flags & ~PF_MEMALLOC) | noreclaim_flag; | |
80 | ||
81 | if (*compact_result <= COMPACT_INACTIVE) | |
82 | return NULL; |