diff options
Diffstat (limited to 'kernel/rcu/srcutree.c')
-rw-r--r-- | kernel/rcu/srcutree.c | 50 |
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 | ||
52 | static void srcu_invoke_callbacks(struct work_struct *work); | 52 | static void srcu_invoke_callbacks(struct work_struct *work); |
53 | static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay); | 53 | static void srcu_reschedule(struct srcu_struct *sp, unsigned long delay); |
54 | static 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 | */ |
1197 | void process_srcu(struct work_struct *work) | 1207 | static 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 | } |
1206 | EXPORT_SYMBOL_GPL(process_srcu); | ||
1207 | 1216 | ||
1208 | void srcutorture_get_gp_data(enum rcutorture_type test_type, | 1217 | void 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 | } |
1218 | EXPORT_SYMBOL_GPL(srcutorture_get_gp_data); | 1227 | EXPORT_SYMBOL_GPL(srcutorture_get_gp_data); |
1219 | 1228 | ||
1229 | void 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 | } | ||
1264 | EXPORT_SYMBOL_GPL(srcu_torture_stats_print); | ||
1265 | |||
1220 | static int __init srcu_bootup_announce(void) | 1266 | static int __init srcu_bootup_announce(void) |
1221 | { | 1267 | { |
1222 | pr_info("Hierarchical SRCU implementation.\n"); | 1268 | pr_info("Hierarchical SRCU implementation.\n"); |