mm, meminit: replace rwsem with completion
Commit 0e1cc95b4c
("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-g1dc51b8 #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: Nicolai Stange <nicstange@gmail.com>
Signed-off-by: Mel Gorman <mgorman@suse.de>
Acked-by: Peter 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: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Родитель
7ace991707
Коммит
d3cd131d93
|
@ -18,7 +18,6 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/rwsem.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/bootmem.h>
|
||||
|
@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page,
|
|||
__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 */
|
||||
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);
|
||||
|
||||
if (first_init_pfn == ULONG_MAX) {
|
||||
up_read(&pgdat_init_rwsem);
|
||||
pgdat_init_report_one_done();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1177,7 +1184,8 @@ free_range:
|
|||
|
||||
pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages,
|
||||
jiffies_to_msecs(jiffies - start));
|
||||
up_read(&pgdat_init_rwsem);
|
||||
|
||||
pgdat_init_report_one_done();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1185,14 +1193,14 @@ void __init page_alloc_init_late(void)
|
|||
{
|
||||
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) {
|
||||
down_read(&pgdat_init_rwsem);
|
||||
kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid);
|
||||
}
|
||||
|
||||
/* Block until all are initialised */
|
||||
down_write(&pgdat_init_rwsem);
|
||||
up_write(&pgdat_init_rwsem);
|
||||
wait_for_completion(&pgdat_init_all_done_comp);
|
||||
}
|
||||
#endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче