Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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-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: 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
Loading
Loading
Loading
Loading
+15 −7
Original line number Diff line number Diff line
@@ -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 @@ static int __init deferred_init_memmap(void *data)

	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 */