FAILED: patch "[PATCH] mm, compaction: make capture control handling safe wrt" failed to apply to 5.4-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From b9e20f0da1f5c9c68689450a8cb436c9486434c8 Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <[email protected]>
Date: Thu, 25 Jun 2020 20:29:24 -0700
Subject: [PATCH] mm, compaction: make capture control handling safe wrt
interrupts
Hugh reports:
"While stressing compaction, one run oopsed on NULL capc->cc in
__free_one_page()'s task_capc(zone): compact_zone_order() had been interrupted, and a page was being freed in the return from interrupt.
Though you would not expect it from the source, both gccs I was using (4.8.1 and 7.5.0) had chosen to compile compact_zone_order() with the ".cc = &cc" implemented by mov %rbx,-0xb0(%rbp) immediately before callq compact_zone - long after the "current->capture_control = &capc". An interrupt in between those finds capc->cc NULL (zeroed by an earlier rep stos).
This could presumably be fixed by a barrier() before setting current->capture_control in compact_zone_order(); but would also need more care on return from compact_zone(), in order not to risk leaking a page captured by interrupt just before capture_control is reset.
Maybe that is the preferable fix, but I felt safer for task_capc() to exclude the rather surprising possibility of capture at interrupt time"
I have checked that gcc10 also behaves the same.
The advantage of fix in compact_zone_order() is that we don't add another test in the page freeing hot path, and that it might prevent future problems if we stop exposing pointers to uninitialized structures in current task.
So this patch implements the suggestion for compact_zone_order() with barrier() (and WRITE_ONCE() to prevent store tearing) for setting current->capture_control, and prevents page leaking with WRITE_ONCE/READ_ONCE in the proper order.
mm/compaction.c +14 -3
@@ -2316,15 +2316,26 @@ static enum compact_result compact_zone_order(struct zone *zone, int order, .page = NULL, }; - current->capture_control = &capc; +/* +* Make sure the structs are really initialized before we expose the +* capture control, in case we are interrupted and the interrupt handler +* frees a page. +*/ +barrier (); +WRITE_ONCE (current->capture_control, &capc); ret =compact_zone (&cc, &capc);VM_BUG_ON (!list_empty (&cc.freepages));VM_BUG_ON (!list_empty (&cc.migratepages)); - *capture = capc.page; - current->capture_control =NULL ; +/* +* Make sure we hide capture control first before we read the captured +* page pointer, otherwise an interrupt could free and capture a page +* and we would leak it. +*/ +WRITE_ONCE (current->capture_control,NULL ); + *capture =READ_ONCE (capc.page);return ret; }
Quoted 9 lines · On 6/29/20 1:07 PM, [email protected] wrote:
The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.thanks,
greg k-h
Hi, please simply cherrypick commit 6467552ca64c ("mm, compaction: fully assume capture is not NULL in compact_zone_order()") first and then cherrypicking b9e20f0da1f5c9c68689450a8cb436c9486434c8 will apply cleanly.
Thanks,
Vlastimil
Quoted 90 lines
------------------ original commit in Linus's tree ------------------
From
b9e20f0da1f5c9c68689450a8cb436c9486434c8Mon Sep 17 00:00:00 2001
From: Vlastimil Babka <[email protected]>
Date: Thu, 25 Jun 2020 20:29:24 -0700
Subject: [PATCH] mm, compaction: make capture control handling safe wrt
interruptsHugh reports:
"While stressing compaction, one run oopsed on NULL
capc->ccin
__free_one_page()'stask_capc(zone):compact_zone_order()had been interrupted, and a page was being freed in the return from interrupt.Though you would not expect it from the source, both gccs I was using (4.8.1 and 7.5.0) had chosen to compile
compact_zone_order()with the ".cc = &cc" implemented by mov %rbx,-0xb0(%rbp) immediately before callqcompact_zone- long after the "current->capture_control= &capc". An interrupt in between those findscapc->ccNULL (zeroed by an earlier rep stos).This could presumably be fixed by a
barrier()before settingcurrent->capture_controlincompact_zone_order(); but would also need more care on return fromcompact_zone(), in order not to risk leaking a page captured by interrupt just beforecapture_controlis reset.Maybe that is the preferable fix, but I felt safer for
task_capc()to exclude the rather surprising possibility of capture at interrupt time"I have checked that gcc10 also behaves the same.
The advantage of fix in
compact_zone_order()is that we don't add another test in the page freeing hot path, and that it might prevent future problems if we stop exposing pointers to uninitialized structures in current task.So this patch implements the suggestion for
compact_zone_order()withbarrier()(andWRITE_ONCE()to prevent store tearing) for settingcurrent->capture_control, and prevents page leaking with WRITE_ONCE/READ_ONCE in the proper order.Fixes 5e1f0f098b46 ("mm, compaction: capture a page under direct compaction")Signed-off-by Vlastimil Babka <[email protected]>Reported-by Hugh Dickins <[email protected]>Suggested-by Hugh Dickins <[email protected]>Acked-by Hugh Dickins <[email protected]>Cc Alex Shi <[email protected]>Cc Li Wang <[email protected]>Cc Mel Gorman <[email protected]>Cc <[email protected]> [5.1+]Signed-off-by Andrew Morton <[email protected]>Signed-off-by Linus Torvalds <[email protected]>mm/compaction.c +14
-3@@ -2316,15 +2316,26 @@ static enum compact_result compact_zone_order(struct zone *zone, int order, .page = NULL, }; - current->capture_control = &capc; +/* +* Make sure the structs are really initialized before we expose the +* capture control, in case we are interrupted and the interrupt handler +* frees a page. +*/ +barrier (); +WRITE_ONCE (current->capture_control, &capc); ret =compact_zone (&cc, &capc);VM_BUG_ON (!list_empty (&cc.freepages));VM_BUG_ON (!list_empty (&cc.migratepages)); - *capture = capc.page; - current->capture_control =NULL ; +/* +* Make sure we hide capture control first before we read the captured +* page pointer, otherwise an interrupt could free and capture a page +* and we would leak it. +*/ +WRITE_ONCE (current->capture_control,NULL ); + *capture =READ_ONCE (capc.page);return ret; }
Greg KH
maintainerQuoted 7 lines · Vlastimil Babka
Quoted 6 lines · On 6/29/20 1:07 PM, [email protected] wrote:
The patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Quoted 7 lines
Quoted 3 lines
thanks,
greg k-h
Hi, please simply cherrypick commit
6467552ca64c("mm, compaction: fully assume capture is not NULL incompact_zone_order()") first and then cherrypickingb9e20f0da1f5c9c68689450a8cb436c9486434c8will apply cleanly.
Thanks, that worked!
greg k-h