diff options
author | Nicolai Stange <nicstange@gmail.com> | 2015-08-06 18:46:16 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-08-06 21:39:40 -0400 |
commit | d3cd131d935ab3bab700491edbbd7cad4040ce50 (patch) | |
tree | 50d9755ae9dfbb3105761b3f87e37fe9454d7a1b /mm/page_alloc.c | |
parent | 7ace99170789bc53cbb7e9e352d7a3851208fbcf (diff) |
mm, meminit: replace rwsem with completion
Commit 0e1cc95b4cc7 ("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>
Diffstat (limited to 'mm/page_alloc.c')
-rw-r--r-- | mm/page_alloc.c | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/mm/page_alloc.c b/mm/page_alloc.c index ea0e6a6e7a11..322628278ae4 100644 --- a/mm/page_alloc.c +++ b/mm/page_alloc.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #include <linux/mm.h> | 18 | #include <linux/mm.h> |
19 | #include <linux/swap.h> | 19 | #include <linux/swap.h> |
20 | #include <linux/interrupt.h> | 20 | #include <linux/interrupt.h> |
21 | #include <linux/rwsem.h> | ||
22 | #include <linux/pagemap.h> | 21 | #include <linux/pagemap.h> |
23 | #include <linux/jiffies.h> | 22 | #include <linux/jiffies.h> |
24 | #include <linux/bootmem.h> | 23 | #include <linux/bootmem.h> |
@@ -1060,7 +1059,15 @@ static void __init deferred_free_range(struct page *page, | |||
1060 | __free_pages_boot_core(page, pfn, 0); | 1059 | __free_pages_boot_core(page, pfn, 0); |
1061 | } | 1060 | } |
1062 | 1061 | ||
1063 | static __initdata DECLARE_RWSEM(pgdat_init_rwsem); | 1062 | /* Completion tracking for deferred_init_memmap() threads */ |
1063 | static atomic_t pgdat_init_n_undone __initdata; | ||
1064 | static __initdata DECLARE_COMPLETION(pgdat_init_all_done_comp); | ||
1065 | |||
1066 | static inline void __init pgdat_init_report_one_done(void) | ||
1067 | { | ||
1068 | if (atomic_dec_and_test(&pgdat_init_n_undone)) | ||
1069 | complete(&pgdat_init_all_done_comp); | ||
1070 | } | ||
1064 | 1071 | ||
1065 | /* Initialise remaining memory on a node */ | 1072 | /* Initialise remaining memory on a node */ |
1066 | static int __init deferred_init_memmap(void *data) | 1073 | static int __init deferred_init_memmap(void *data) |
@@ -1077,7 +1084,7 @@ static int __init deferred_init_memmap(void *data) | |||
1077 | const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); | 1084 | const struct cpumask *cpumask = cpumask_of_node(pgdat->node_id); |
1078 | 1085 | ||
1079 | if (first_init_pfn == ULONG_MAX) { | 1086 | if (first_init_pfn == ULONG_MAX) { |
1080 | up_read(&pgdat_init_rwsem); | 1087 | pgdat_init_report_one_done(); |
1081 | return 0; | 1088 | return 0; |
1082 | } | 1089 | } |
1083 | 1090 | ||
@@ -1177,7 +1184,8 @@ free_range: | |||
1177 | 1184 | ||
1178 | pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages, | 1185 | pr_info("node %d initialised, %lu pages in %ums\n", nid, nr_pages, |
1179 | jiffies_to_msecs(jiffies - start)); | 1186 | jiffies_to_msecs(jiffies - start)); |
1180 | up_read(&pgdat_init_rwsem); | 1187 | |
1188 | pgdat_init_report_one_done(); | ||
1181 | return 0; | 1189 | return 0; |
1182 | } | 1190 | } |
1183 | 1191 | ||
@@ -1185,14 +1193,14 @@ void __init page_alloc_init_late(void) | |||
1185 | { | 1193 | { |
1186 | int nid; | 1194 | int nid; |
1187 | 1195 | ||
1196 | /* There will be num_node_state(N_MEMORY) threads */ | ||
1197 | atomic_set(&pgdat_init_n_undone, num_node_state(N_MEMORY)); | ||
1188 | for_each_node_state(nid, N_MEMORY) { | 1198 | for_each_node_state(nid, N_MEMORY) { |
1189 | down_read(&pgdat_init_rwsem); | ||
1190 | kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid); | 1199 | kthread_run(deferred_init_memmap, NODE_DATA(nid), "pgdatinit%d", nid); |
1191 | } | 1200 | } |
1192 | 1201 | ||
1193 | /* Block until all are initialised */ | 1202 | /* Block until all are initialised */ |
1194 | down_write(&pgdat_init_rwsem); | 1203 | wait_for_completion(&pgdat_init_all_done_comp); |
1195 | up_write(&pgdat_init_rwsem); | ||
1196 | } | 1204 | } |
1197 | #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ | 1205 | #endif /* CONFIG_DEFERRED_STRUCT_PAGE_INIT */ |
1198 | 1206 | ||