Commit d3cd131d authored by Nicolai Stange's avatar Nicolai Stange Committed by Linus Torvalds

mm, meminit: replace rwsem with completion

Commit 0e1cc95b ("mm: meminit: finish initialisation of struct pages
before basic setup") introduced a rwsem to signal completion of the
initialization workers.

Lockdep complains about possible recursive locking:
  =============================================
  [ INFO: possible recursive locking detected ]
  4.1.0-12802-g1dc51b82 #3 Not tainted
  ---------------------------------------------
  swapper/0/1 is trying to acquire lock:
  (pgdat_init_rwsem){++++.+},
    at: [<ffffffff8424c7fb>] page_alloc_init_late+0xc7/0xe6

  but task is already holding lock:
  (pgdat_init_rwsem){++++.+},
    at: [<ffffffff8424c772>] page_alloc_init_late+0x3e/0xe6

Replace the rwsem by a completion together with an atomic
"outstanding work counter".

[peterz@infradead.org: Barrier removal on the grounds of being pointless]
[mgorman@suse.de: Applied review feedback]
Signed-off-by: default avatarNicolai Stange <nicstange@gmail.com>
Signed-off-by: default avatarMel Gorman <mgorman@suse.de>
Acked-by: default avatarPeter Zijlstra (Intel) <peterz@infradead.org>
Cc: Dave Hansen <dave.hansen@intel.com>
Cc: Alex Ng <alexng@microsoft.com>
Cc: Fengguang Wu <fengguang.wu@intel.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7ace9917
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/swap.h> #include <linux/swap.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/rwsem.h>
#include <linux/pagemap.h> #include <linux/pagemap.h>
#include <linux/jiffies.h> #include <linux/jiffies.h>
#include <linux/bootmem.h> #include <linux/bootmem.h>
...@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page, ...@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
__free_pages_boot_core(page, pfn, 0); __free_pages_boot_core(page, pfn, 0);
} }
static __initdata DECLARE_RWSEM(pgdat_init_rwsem); /* Completion tracking for deferred_init_memmap() threads */
static atomic_t pgdat_init_n_undone __initdata;
static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp);
static inline void __init pgdat_init_report_one_done(void)
{
if (atomic_dec_and_test(&pgdat_init_n_undone))
complete(&pgdat_init_all_done_comp);
}
/* Initialise remaining memory on a node */ /* Initialise remaining memory on a node */
static int __init deferred_init_memmap(void *data) static int __init deferred_init_memmap(void *data)
...@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data) ...@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data)
const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id);
if (first_init_pfn == ULONG_MAX) { if (first_init_pfn == ULONG_MAX) {
up_read(&pgdat_init_rwsem); pgdat_init_report_one_done();
return 0; return 0;
} }
...@@ -1177,7 +1184,8 @@ static int __init deferred_init_memmap(void *data) ...@@ -1177,7 +1184,8 @@ static int __init deferred_init_memmap(void *data)
pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages, pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
jiffies_to_msecs(jiffies - start)); jiffies_to_msecs(jiffies - start));
up_read(&pgdat_init_rwsem);
pgdat_init_report_one_done();
return 0; return 0;
} }
...@@ -1185,14 +1193,14 @@ void __init page_alloc_init_late(void) ...@@ -1185,14 +1193,14 @@ void __init page_alloc_init_late(void)
{ {
int nid; int nid;
/* There will be num_node_state(N_MEMORY) threads */
atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY));
for_each_node_state(nid, N_MEMORY) { for_each_node_state(nid, N_MEMORY) {
down_read(&pgdat_init_rwsem);
kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid); kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
} }
/* Block until all are initialised */ /* Block until all are initialised */
down_write(&pgdat_init_rwsem); wait_for_completion(&pgdat_init_all_done_comp);
up_write(&pgdat_init_rwsem);
} }
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment