aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/rcu/srcutree.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/rcu/srcutree.c')
-rw-r--r--kernel/rcu/srcutree.c50
1 files changed, 48 insertions, 2 deletions
diff --git a/kernel/rcu/srcutree.c b/kernel/rcu/srcutree.c
index d0ca524bf042..729a8706751d 100644
--- a/kernel/rcu/srcutree.c
+++ b/kernel/rcu/srcutree.c
@@ -51,6 +51,7 @@ module_param(counter_wrap_check, ulong, 0444);
51 51
52static void srcu_invoke_callbacks(struct work_struct *work); 52static void srcu_invoke_callbacks(struct work_struct *work);
53static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay); 53static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay);
54static void process_srcu(struct work_struct *work);
54 55
55/* 56/*
56 * Initialize SRCU combining tree. Note that statically allocated 57 * Initialize SRCU combining tree. Note that statically allocated
@@ -896,6 +897,15 @@ static void __synchronize_srcu(struct srcu_struct *sp, bool do_norm)
896 __call_srcu(sp, &rcu.head, wakeme_after_rcu, do_norm); 897 __call_srcu(sp, &rcu.head, wakeme_after_rcu, do_norm);
897 wait_for_completion(&rcu.completion); 898 wait_for_completion(&rcu.completion);
898 destroy_rcu_head_on_stack(&rcu.head); 899 destroy_rcu_head_on_stack(&rcu.head);
900
901 /*
902 * Make sure that later code is ordered after the SRCU grace
903 * period. This pairs with the raw_spin_lock_irq_rcu_node()
904 * in srcu_invoke_callbacks(). Unlike Tree RCU, this is needed
905 * because the current CPU might have been totally uninvolved with
906 * (and thus unordered against) that grace period.
907 */
908 smp_mb();
899} 909}
900 910
901/** 911/**
@@ -1194,7 +1204,7 @@ static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay)
1194/* 1204/*
1195 * This is the work-queue function that handles SRCU grace periods. 1205 * This is the work-queue function that handles SRCU grace periods.
1196 */ 1206 */
1197void process_srcu(struct work_struct *work) 1207static void process_srcu(struct work_struct *work)
1198{ 1208{
1199 struct srcu_struct *sp; 1209 struct srcu_struct *sp;
1200 1210
@@ -1203,7 +1213,6 @@ void process_srcu(struct work_struct *work)
1203 srcu_advance_state(sp); 1213 srcu_advance_state(sp);
1204 srcu_reschedule(sp, srcu_get_delay(sp)); 1214 srcu_reschedule(sp, srcu_get_delay(sp));
1205} 1215}
1206EXPORT_SYMBOL_GPL(process_srcu);
1207 1216
1208void srcutorture_get_gp_data(enum rcutorture_type test_type, 1217void srcutorture_get_gp_data(enum rcutorture_type test_type,
1209 struct srcu_struct *sp, int *flags, 1218 struct srcu_struct *sp, int *flags,
@@ -1217,6 +1226,43 @@ void srcutorture_get_gp_data(enum rcutorture_type test_type,
1217} 1226}
1218EXPORT_SYMBOL_GPL(srcutorture_get_gp_data); 1227EXPORT_SYMBOL_GPL(srcutorture_get_gp_data);
1219 1228
1229void srcu_torture_stats_print(struct srcu_struct *sp, char *tt, char *tf)
1230{
1231 int cpu;
1232 int idx;
1233 unsigned long s0 = 0, s1 = 0;
1234
1235 idx = sp->srcu_idx & 0x1;
1236 pr_alert("%s%s Tree SRCU per-CPU(idx=%d):", tt, tf, idx);
1237 for_each_possible_cpu(cpu) {
1238 unsigned long l0, l1;
1239 unsigned long u0, u1;
1240 long c0, c1;
1241 struct srcu_data *counts;
1242
1243 counts = per_cpu_ptr(sp->sda, cpu);
1244 u0 = counts->srcu_unlock_count[!idx];
1245 u1 = counts->srcu_unlock_count[idx];
1246
1247 /*
1248 * Make sure that a lock is always counted if the corresponding
1249 * unlock is counted.
1250 */
1251 smp_rmb();
1252
1253 l0 = counts->srcu_lock_count[!idx];
1254 l1 = counts->srcu_lock_count[idx];
1255
1256 c0 = l0 - u0;
1257 c1 = l1 - u1;
1258 pr_cont(" %d(%ld,%ld)", cpu, c0, c1);
1259 s0 += c0;
1260 s1 += c1;
1261 }
1262 pr_cont(" T(%ld,%ld)\n", s0, s1);
1263}
1264EXPORT_SYMBOL_GPL(srcu_torture_stats_print);
1265
1220static int __init srcu_bootup_announce(void) 1266static int __init srcu_bootup_announce(void)
1221{ 1267{
1222 pr_info("Hierarchical SRCU implementation.\n"); 1268 pr_info("Hierarchical SRCU implementation.\n");