1 From 60fce36afa9c77c7ccbf980c4f670f3be3651fce Mon Sep 17 00:00:00 2001
2 From: Mel Gorman <mgorman@techsingularity.net>
3 Date: Fri, 17 May 2019 14:31:41 -0700
4 Subject: mm/compaction.c: correct zone boundary handling when isolating pages from a pageblock
6 From: Mel Gorman <mgorman@techsingularity.net>
8 commit 60fce36afa9c77c7ccbf980c4f670f3be3651fce upstream.
10 syzbot reported the following error from a tree with a head commit of
11 baf76f0c58ae ("slip: make slhc_free() silently accept an error pointer")
13 BUG: unable to handle kernel paging request at ffffea0003348000
14 #PF error: [normal kernel read fault]
15 PGD 12c3f9067 P4D 12c3f9067 PUD 12c3f8067 PMD 0
16 Oops: 0000 [#1] PREEMPT SMP KASAN
17 CPU: 1 PID: 28916 Comm: syz-executor.2 Not tainted 5.1.0-rc6+ #89
18 Hardware name: Google Google Compute Engine/Google Compute Engine, BIOS Google 01/01/2011
19 RIP: 0010:constant_test_bit arch/x86/include/asm/bitops.h:314 [inline]
20 RIP: 0010:PageCompound include/linux/page-flags.h:186 [inline]
21 RIP: 0010:isolate_freepages_block+0x1c0/0xd40 mm/compaction.c:579
22 Code: 01 d8 ff 4d 85 ed 0f 84 ef 07 00 00 e8 29 00 d8 ff 4c 89 e0 83 85 38 ff
23 ff ff 01 48 c1 e8 03 42 80 3c 38 00 0f 85 31 0a 00 00 <4d> 8b 2c 24 31 ff 49
24 c1 ed 10 41 83 e5 01 44 89 ee e8 3a 01 d8 ff
25 RSP: 0018:ffff88802b31eab8 EFLAGS: 00010246
26 RAX: 1ffffd4000669000 RBX: 00000000000cd200 RCX: ffffc9000a235000
27 RDX: 000000000001ca5e RSI: ffffffff81988cc7 RDI: 0000000000000001
28 RBP: ffff88802b31ebd8 R08: ffff88805af700c0 R09: 0000000000000000
29 R10: 0000000000000000 R11: 0000000000000000 R12: ffffea0003348000
30 R13: 0000000000000000 R14: ffff88802b31f030 R15: dffffc0000000000
31 FS: 00007f61648dc700(0000) GS:ffff8880ae900000(0000) knlGS:0000000000000000
32 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
33 CR2: ffffea0003348000 CR3: 0000000037c64000 CR4: 00000000001426e0
35 fast_isolate_around mm/compaction.c:1243 [inline]
36 fast_isolate_freepages mm/compaction.c:1418 [inline]
37 isolate_freepages mm/compaction.c:1438 [inline]
38 compaction_alloc+0x1aee/0x22e0 mm/compaction.c:1550
40 There is no reproducer and it is difficult to hit -- 1 crash every few
41 days. The issue is very similar to the fix in commit 6b0868c820ff
42 ("mm/compaction.c: correct zone boundary handling when resetting pageblock
43 skip hints"). When isolating free pages around a target pageblock, the
44 boundary handling is off by one and can stray into the next pageblock.
45 Triggering the syzbot error requires that the end of pageblock is section
46 or zone aligned, and that the next section is unpopulated.
48 A more subtle consequence of the bug is that pageblocks were being
49 improperly used as migration targets which potentially hurts fragmentation
50 avoidance in the long-term one page at a time.
52 A debugging patch revealed that it's definitely possible to stray outside
53 of a pageblock which is not intended. While syzbot cannot be used to
54 verify this patch, it was confirmed that the debugging warning no longer
55 triggers with this patch applied. It has also been confirmed that the THP
56 allocation stress tests are not degraded by this patch.
58 Link: http://lkml.kernel.org/r/20190510182124.GI18914@techsingularity.net
59 Fixes: e332f741a8dd ("mm, compaction: be selective about what pageblocks to clear skip hints")
60 Signed-off-by: Mel Gorman <mgorman@techsingularity.net>
61 Reported-by: syzbot+d84c80f9fe26a0f7a734@syzkaller.appspotmail.com
62 Cc: Dmitry Vyukov <dvyukov@google.com>
63 Cc: Andrey Ryabinin <aryabinin@virtuozzo.com>
64 Cc: Qian Cai <cai@lca.pw>
65 Cc: Michal Hocko <mhocko@suse.com>
66 Cc: Vlastimil Babka <vbabka@suse.cz>
67 Cc: <stable@vger.kernel.org> # v5.1+
68 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
69 Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
70 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
73 mm/compaction.c | 4 ++--
74 1 file changed, 2 insertions(+), 2 deletions(-)
78 @@ -1228,7 +1228,7 @@ fast_isolate_around(struct compact_contr
80 /* Pageblock boundaries */
81 start_pfn = pageblock_start_pfn(pfn);
82 - end_pfn = min(start_pfn + pageblock_nr_pages, zone_end_pfn(cc->zone));
83 + end_pfn = min(pageblock_end_pfn(pfn), zone_end_pfn(cc->zone)) - 1;
86 if (start_pfn != pfn) {
87 @@ -1239,7 +1239,7 @@ fast_isolate_around(struct compact_contr
90 start_pfn = pfn + nr_isolated;
91 - if (start_pfn != end_pfn)
92 + if (start_pfn < end_pfn)
93 isolate_freepages_block(cc, &start_pfn, end_pfn, &cc->freepages, 1, false);
95 /* Skip this pageblock in the future as it's full or nearly full */