Skip to content

Commit

Permalink
mm, meminit: replace rwsem with completion
Browse files Browse the repository at this point in the history
Commit 0e1cc95 ("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".

[[email protected]: Barrier removal on the grounds of being pointless]
[[email protected]: Applied review feedback]
Signed-off-by: Nicolai Stange <[email protected]>
Signed-off-by: Mel Gorman <[email protected]>
Acked-by: Peter Zijlstra (Intel) <[email protected]>
Cc: Dave Hansen <[email protected]>
Cc: Alex Ng <[email protected]>
Cc: Fengguang Wu <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
nicstange authored and torvalds committed Aug 7, 2015
1 parent 7ace991 commit d3cd131
Showing 1 changed file with 15 additions and 7 deletions.
22 changes: 15 additions & 7 deletions mm/page_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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)
Expand All @@ -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;
}

Expand Down Expand Up @@ -1177,22 +1184,23 @@ 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;
}

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

Expand Down

0 comments on commit d3cd131

Please sign in to comment.