diff options
author | Davidlohr Bueso <dave@stgolabs.net> | 2017-10-03 19:15:03 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-10-03 20:54:24 -0400 |
commit | 6818600ff094ca255a7fe31838ad50c29656c3c5 (patch) | |
tree | 43ed936d9217cf7b097f8b44e55200844151e35d /mm/compaction.c | |
parent | a1b2289cef92ef0e9a92afcd2e1ea71d5bcaaf64 (diff) |
mm,compaction: serialize waitqueue_active() checks (for real)
Andrea brought to my attention that the L->{L,S} guarantees are
completely bogus for this case. I was looking at the diagram, from the
offending commit, when that _is_ the race, we had the load reordered
already.
What we need is at least S->L semantics, thus simply use
wq_has_sleeper() to serialize the call for good.
Link: http://lkml.kernel.org/r/20170914175313.GB811@linux-80c1.suse
Fixes: 46acef048a6 (mm,compaction: serialize waitqueue_active() checks)
Signed-off-by: Davidlohr Bueso <dbueso@suse.de>
Reported-by: Andrea Parri <parri.andrea@gmail.com>
Cc: Vlastimil Babka <vbabka@suse.cz>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm/compaction.c')
-rw-r--r-- | mm/compaction.c | 13 |
1 files changed, 5 insertions, 8 deletions
diff --git a/mm/compaction.c b/mm/compaction.c index fb548e4c7bd4..03d31a875341 100644 --- a/mm/compaction.c +++ b/mm/compaction.c | |||
@@ -1999,17 +1999,14 @@ void wakeup_kcompactd(pg_data_t *pgdat, int order, int classzone_idx) | |||
1999 | if (pgdat->kcompactd_max_order < order) | 1999 | if (pgdat->kcompactd_max_order < order) |
2000 | pgdat->kcompactd_max_order = order; | 2000 | pgdat->kcompactd_max_order = order; |
2001 | 2001 | ||
2002 | /* | ||
2003 | * Pairs with implicit barrier in wait_event_freezable() | ||
2004 | * such that wakeups are not missed in the lockless | ||
2005 | * waitqueue_active() call. | ||
2006 | */ | ||
2007 | smp_acquire__after_ctrl_dep(); | ||
2008 | |||
2009 | if (pgdat->kcompactd_classzone_idx > classzone_idx) | 2002 | if (pgdat->kcompactd_classzone_idx > classzone_idx) |
2010 | pgdat->kcompactd_classzone_idx = classzone_idx; | 2003 | pgdat->kcompactd_classzone_idx = classzone_idx; |
2011 | 2004 | ||
2012 | if (!waitqueue_active(&pgdat->kcompactd_wait)) | 2005 | /* |
2006 | * Pairs with implicit barrier in wait_event_freezable() | ||
2007 | * such that wakeups are not missed. | ||
2008 | */ | ||
2009 | if (!wq_has_sleeper(&pgdat->kcompactd_wait)) | ||
2013 | return; | 2010 | return; |
2014 | 2011 | ||
2015 | if (!kcompactd_node_suitable(pgdat)) | 2012 | if (!kcompactd_node_suitable(pgdat)) |