diff options
| author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2018-08-14 17:41:49 -0400 |
|---|---|---|
| committer | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2018-08-30 19:10:49 -0400 |
| commit | 4e6ea4ef56f9425cd239ffdb6be45b3aeeb347fd (patch) | |
| tree | 81702573011d79ef39d2934e020372976256b9de /kernel/rcu | |
| parent | 55cda2290bf9d8510fbe7c1939a36680476c69c4 (diff) | |
srcu: Make early-boot call_srcu() reuse workqueue lists
Allocating a list_head structure that is almost never used, and, when
used, is used only during early boot (rcu_init() and earlier), is a bit
wasteful. This commit therefore eliminates that list_head in favor of
the one in the work_struct structure. This is safe because the work_struct
structure cannot be used until after rcu_init() returns.
Reported-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Lai Jiangshan <jiangshanlai@gmail.com>
Tested-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Diffstat (limited to 'kernel/rcu')
| -rw-r--r-- | kernel/rcu/srcutiny.c | 10 | ||||
| -rw-r--r-- | kernel/rcu/srcutree.c | 11 |
2 files changed, 10 insertions, 11 deletions
diff --git a/kernel/rcu/srcutiny.c b/kernel/rcu/srcutiny.c index d233f0c63f6f..b46e6683f8c9 100644 --- a/kernel/rcu/srcutiny.c +++ b/kernel/rcu/srcutiny.c | |||
| @@ -48,7 +48,7 @@ static int init_srcu_struct_fields(struct srcu_struct *sp) | |||
| 48 | sp->srcu_gp_waiting = false; | 48 | sp->srcu_gp_waiting = false; |
| 49 | sp->srcu_idx = 0; | 49 | sp->srcu_idx = 0; |
| 50 | INIT_WORK(&sp->srcu_work, srcu_drive_gp); | 50 | INIT_WORK(&sp->srcu_work, srcu_drive_gp); |
| 51 | INIT_LIST_HEAD(&sp->srcu_boot_entry); | 51 | INIT_LIST_HEAD(&sp->srcu_work.entry); |
| 52 | return 0; | 52 | return 0; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| @@ -185,8 +185,8 @@ void call_srcu(struct srcu_struct *sp, struct rcu_head *rhp, | |||
| 185 | if (!READ_ONCE(sp->srcu_gp_running)) { | 185 | if (!READ_ONCE(sp->srcu_gp_running)) { |
| 186 | if (likely(srcu_init_done)) | 186 | if (likely(srcu_init_done)) |
| 187 | schedule_work(&sp->srcu_work); | 187 | schedule_work(&sp->srcu_work); |
| 188 | else if (list_empty(&sp->srcu_boot_entry)) | 188 | else if (list_empty(&sp->srcu_work.entry)) |
| 189 | list_add(&sp->srcu_boot_entry, &srcu_boot_list); | 189 | list_add(&sp->srcu_work.entry, &srcu_boot_list); |
| 190 | } | 190 | } |
| 191 | } | 191 | } |
| 192 | EXPORT_SYMBOL_GPL(call_srcu); | 192 | EXPORT_SYMBOL_GPL(call_srcu); |
| @@ -224,8 +224,8 @@ void __init srcu_init(void) | |||
| 224 | srcu_init_done = true; | 224 | srcu_init_done = true; |
| 225 | while (!list_empty(&srcu_boot_list)) { | 225 | while (!list_empty(&srcu_boot_list)) { |
| 226 | sp = list_first_entry(&srcu_boot_list, | 226 | sp = list_first_entry(&srcu_boot_list, |
| 227 | struct srcu_struct, srcu_boot_entry); | 227 | struct srcu_struct, srcu_work.entry); |
| 228 | list_del_init(&sp->srcu_boot_entry); | 228 | list_del_init(&sp->srcu_work.entry); |
| 229 | schedule_work(&sp->srcu_work); | 229 | schedule_work(&sp->srcu_work); |
| 230 | } | 230 | } |
| 231 | } | 231 | } |
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c index 2e7f6b460150..86c7fd0a1bfe 100644 --- a/kernel/rcu/srcutree.c +++ b/kernel/rcu/srcutree.c | |||
| @@ -186,7 +186,6 @@ static int init_srcu_struct_fields(struct srcu_struct *sp, bool is_static) | |||
| 186 | mutex_init(&sp->srcu_barrier_mutex); | 186 | mutex_init(&sp->srcu_barrier_mutex); |
| 187 | atomic_set(&sp->srcu_barrier_cpu_cnt, 0); | 187 | atomic_set(&sp->srcu_barrier_cpu_cnt, 0); |
| 188 | INIT_DELAYED_WORK(&sp->work, process_srcu); | 188 | INIT_DELAYED_WORK(&sp->work, process_srcu); |
| 189 | INIT_LIST_HEAD(&sp->srcu_boot_entry); | ||
| 190 | if (!is_static) | 189 | if (!is_static) |
| 191 | sp->sda = alloc_percpu(struct srcu_data); | 190 | sp->sda = alloc_percpu(struct srcu_data); |
| 192 | init_srcu_struct_nodes(sp, is_static); | 191 | init_srcu_struct_nodes(sp, is_static); |
| @@ -708,8 +707,8 @@ static void srcu_funnel_gp_start(struct srcu_struct *sp, struct srcu_data *sdp, | |||
| 708 | if (likely(srcu_init_done)) | 707 | if (likely(srcu_init_done)) |
| 709 | queue_delayed_work(rcu_gp_wq, &sp->work, | 708 | queue_delayed_work(rcu_gp_wq, &sp->work, |
| 710 | srcu_get_delay(sp)); | 709 | srcu_get_delay(sp)); |
| 711 | else if (list_empty(&sp->srcu_boot_entry)) | 710 | else if (list_empty(&sp->work.work.entry)) |
| 712 | list_add(&sp->srcu_boot_entry, &srcu_boot_list); | 711 | list_add(&sp->work.work.entry, &srcu_boot_list); |
| 713 | } | 712 | } |
| 714 | spin_unlock_irqrestore_rcu_node(sp, flags); | 713 | spin_unlock_irqrestore_rcu_node(sp, flags); |
| 715 | } | 714 | } |
| @@ -1323,10 +1322,10 @@ void __init srcu_init(void) | |||
| 1323 | 1322 | ||
| 1324 | srcu_init_done = true; | 1323 | srcu_init_done = true; |
| 1325 | while (!list_empty(&srcu_boot_list)) { | 1324 | while (!list_empty(&srcu_boot_list)) { |
| 1326 | sp = list_first_entry(&srcu_boot_list, | 1325 | sp = list_first_entry(&srcu_boot_list, struct srcu_struct, |
| 1327 | struct srcu_struct, srcu_boot_entry); | 1326 | work.work.entry); |
| 1328 | check_init_srcu_struct(sp); | 1327 | check_init_srcu_struct(sp); |
| 1329 | list_del_init(&sp->srcu_boot_entry); | 1328 | list_del_init(&sp->work.work.entry); |
| 1330 | queue_work(rcu_gp_wq, &sp->work.work); | 1329 | queue_work(rcu_gp_wq, &sp->work.work); |
| 1331 | } | 1330 | } |
| 1332 | } | 1331 | } |
