diff options
Diffstat (limited to 'kernel/rcu/rcutorture.c')
| -rw-r--r-- | kernel/rcu/rcutorture.c | 66 |
1 files changed, 38 insertions, 28 deletions
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c index 4d559baf06e0..30d42aa55d83 100644 --- a/kernel/rcu/rcutorture.c +++ b/kernel/rcu/rcutorture.c | |||
| @@ -244,7 +244,8 @@ struct rcu_torture_ops { | |||
| 244 | int (*readlock)(void); | 244 | int (*readlock)(void); |
| 245 | void (*read_delay)(struct torture_random_state *rrsp); | 245 | void (*read_delay)(struct torture_random_state *rrsp); |
| 246 | void (*readunlock)(int idx); | 246 | void (*readunlock)(int idx); |
| 247 | int (*completed)(void); | 247 | unsigned long (*started)(void); |
| 248 | unsigned long (*completed)(void); | ||
| 248 | void (*deferred_free)(struct rcu_torture *p); | 249 | void (*deferred_free)(struct rcu_torture *p); |
| 249 | void (*sync)(void); | 250 | void (*sync)(void); |
| 250 | void (*exp_sync)(void); | 251 | void (*exp_sync)(void); |
| @@ -296,11 +297,6 @@ static void rcu_torture_read_unlock(int idx) __releases(RCU) | |||
| 296 | rcu_read_unlock(); | 297 | rcu_read_unlock(); |
| 297 | } | 298 | } |
| 298 | 299 | ||
| 299 | static int rcu_torture_completed(void) | ||
| 300 | { | ||
| 301 | return rcu_batches_completed(); | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | 300 | /* |
| 305 | * Update callback in the pipe. This should be invoked after a grace period. | 301 | * Update callback in the pipe. This should be invoked after a grace period. |
| 306 | */ | 302 | */ |
| @@ -356,7 +352,7 @@ rcu_torture_cb(struct rcu_head *p) | |||
| 356 | cur_ops->deferred_free(rp); | 352 | cur_ops->deferred_free(rp); |
| 357 | } | 353 | } |
| 358 | 354 | ||
| 359 | static int rcu_no_completed(void) | 355 | static unsigned long rcu_no_completed(void) |
| 360 | { | 356 | { |
| 361 | return 0; | 357 | return 0; |
| 362 | } | 358 | } |
| @@ -377,7 +373,8 @@ static struct rcu_torture_ops rcu_ops = { | |||
| 377 | .readlock = rcu_torture_read_lock, | 373 | .readlock = rcu_torture_read_lock, |
| 378 | .read_delay = rcu_read_delay, | 374 | .read_delay = rcu_read_delay, |
| 379 | .readunlock = rcu_torture_read_unlock, | 375 | .readunlock = rcu_torture_read_unlock, |
| 380 | .completed = rcu_torture_completed, | 376 | .started = rcu_batches_started, |
| 377 | .completed = rcu_batches_completed, | ||
| 381 | .deferred_free = rcu_torture_deferred_free, | 378 | .deferred_free = rcu_torture_deferred_free, |
| 382 | .sync = synchronize_rcu, | 379 | .sync = synchronize_rcu, |
| 383 | .exp_sync = synchronize_rcu_expedited, | 380 | .exp_sync = synchronize_rcu_expedited, |
| @@ -407,11 +404,6 @@ static void rcu_bh_torture_read_unlock(int idx) __releases(RCU_BH) | |||
| 407 | rcu_read_unlock_bh(); | 404 | rcu_read_unlock_bh(); |
| 408 | } | 405 | } |
| 409 | 406 | ||
| 410 | static int rcu_bh_torture_completed(void) | ||
| 411 | { | ||
| 412 | return rcu_batches_completed_bh(); | ||
| 413 | } | ||
| 414 | |||
| 415 | static void rcu_bh_torture_deferred_free(struct rcu_torture *p) | 407 | static void rcu_bh_torture_deferred_free(struct rcu_torture *p) |
| 416 | { | 408 | { |
| 417 | call_rcu_bh(&p->rtort_rcu, rcu_torture_cb); | 409 | call_rcu_bh(&p->rtort_rcu, rcu_torture_cb); |
| @@ -423,7 +415,8 @@ static struct rcu_torture_ops rcu_bh_ops = { | |||
| 423 | .readlock = rcu_bh_torture_read_lock, | 415 | .readlock = rcu_bh_torture_read_lock, |
| 424 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ | 416 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ |
| 425 | .readunlock = rcu_bh_torture_read_unlock, | 417 | .readunlock = rcu_bh_torture_read_unlock, |
| 426 | .completed = rcu_bh_torture_completed, | 418 | .started = rcu_batches_started_bh, |
| 419 | .completed = rcu_batches_completed_bh, | ||
| 427 | .deferred_free = rcu_bh_torture_deferred_free, | 420 | .deferred_free = rcu_bh_torture_deferred_free, |
| 428 | .sync = synchronize_rcu_bh, | 421 | .sync = synchronize_rcu_bh, |
| 429 | .exp_sync = synchronize_rcu_bh_expedited, | 422 | .exp_sync = synchronize_rcu_bh_expedited, |
| @@ -466,6 +459,7 @@ static struct rcu_torture_ops rcu_busted_ops = { | |||
| 466 | .readlock = rcu_torture_read_lock, | 459 | .readlock = rcu_torture_read_lock, |
| 467 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ | 460 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ |
| 468 | .readunlock = rcu_torture_read_unlock, | 461 | .readunlock = rcu_torture_read_unlock, |
| 462 | .started = rcu_no_completed, | ||
| 469 | .completed = rcu_no_completed, | 463 | .completed = rcu_no_completed, |
| 470 | .deferred_free = rcu_busted_torture_deferred_free, | 464 | .deferred_free = rcu_busted_torture_deferred_free, |
| 471 | .sync = synchronize_rcu_busted, | 465 | .sync = synchronize_rcu_busted, |
| @@ -510,7 +504,7 @@ static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl) | |||
| 510 | srcu_read_unlock(&srcu_ctl, idx); | 504 | srcu_read_unlock(&srcu_ctl, idx); |
| 511 | } | 505 | } |
| 512 | 506 | ||
| 513 | static int srcu_torture_completed(void) | 507 | static unsigned long srcu_torture_completed(void) |
| 514 | { | 508 | { |
| 515 | return srcu_batches_completed(&srcu_ctl); | 509 | return srcu_batches_completed(&srcu_ctl); |
| 516 | } | 510 | } |
| @@ -564,6 +558,7 @@ static struct rcu_torture_ops srcu_ops = { | |||
| 564 | .readlock = srcu_torture_read_lock, | 558 | .readlock = srcu_torture_read_lock, |
| 565 | .read_delay = srcu_read_delay, | 559 | .read_delay = srcu_read_delay, |
| 566 | .readunlock = srcu_torture_read_unlock, | 560 | .readunlock = srcu_torture_read_unlock, |
| 561 | .started = NULL, | ||
| 567 | .completed = srcu_torture_completed, | 562 | .completed = srcu_torture_completed, |
| 568 | .deferred_free = srcu_torture_deferred_free, | 563 | .deferred_free = srcu_torture_deferred_free, |
| 569 | .sync = srcu_torture_synchronize, | 564 | .sync = srcu_torture_synchronize, |
| @@ -600,7 +595,8 @@ static struct rcu_torture_ops sched_ops = { | |||
| 600 | .readlock = sched_torture_read_lock, | 595 | .readlock = sched_torture_read_lock, |
| 601 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ | 596 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ |
| 602 | .readunlock = sched_torture_read_unlock, | 597 | .readunlock = sched_torture_read_unlock, |
| 603 | .completed = rcu_no_completed, | 598 | .started = rcu_batches_started_sched, |
| 599 | .completed = rcu_batches_completed_sched, | ||
| 604 | .deferred_free = rcu_sched_torture_deferred_free, | 600 | .deferred_free = rcu_sched_torture_deferred_free, |
| 605 | .sync = synchronize_sched, | 601 | .sync = synchronize_sched, |
| 606 | .exp_sync = synchronize_sched_expedited, | 602 | .exp_sync = synchronize_sched_expedited, |
| @@ -638,6 +634,7 @@ static struct rcu_torture_ops tasks_ops = { | |||
| 638 | .readlock = tasks_torture_read_lock, | 634 | .readlock = tasks_torture_read_lock, |
| 639 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ | 635 | .read_delay = rcu_read_delay, /* just reuse rcu's version. */ |
| 640 | .readunlock = tasks_torture_read_unlock, | 636 | .readunlock = tasks_torture_read_unlock, |
| 637 | .started = rcu_no_completed, | ||
| 641 | .completed = rcu_no_completed, | 638 | .completed = rcu_no_completed, |
| 642 | .deferred_free = rcu_tasks_torture_deferred_free, | 639 | .deferred_free = rcu_tasks_torture_deferred_free, |
| 643 | .sync = synchronize_rcu_tasks, | 640 | .sync = synchronize_rcu_tasks, |
| @@ -1015,8 +1012,8 @@ static void rcutorture_trace_dump(void) | |||
| 1015 | static void rcu_torture_timer(unsigned long unused) | 1012 | static void rcu_torture_timer(unsigned long unused) |
| 1016 | { | 1013 | { |
| 1017 | int idx; | 1014 | int idx; |
| 1018 | int completed; | 1015 | unsigned long started; |
| 1019 | int completed_end; | 1016 | unsigned long completed; |
| 1020 | static DEFINE_TORTURE_RANDOM(rand); | 1017 | static DEFINE_TORTURE_RANDOM(rand); |
| 1021 | static DEFINE_SPINLOCK(rand_lock); | 1018 | static DEFINE_SPINLOCK(rand_lock); |
| 1022 | struct rcu_torture *p; | 1019 | struct rcu_torture *p; |
| @@ -1024,7 +1021,10 @@ static void rcu_torture_timer(unsigned long unused) | |||
| 1024 | unsigned long long ts; | 1021 | unsigned long long ts; |
| 1025 | 1022 | ||
| 1026 | idx = cur_ops->readlock(); | 1023 | idx = cur_ops->readlock(); |
| 1027 | completed = cur_ops->completed(); | 1024 | if (cur_ops->started) |
| 1025 | started = cur_ops->started(); | ||
| 1026 | else | ||
| 1027 | started = cur_ops->completed(); | ||
| 1028 | ts = rcu_trace_clock_local(); | 1028 | ts = rcu_trace_clock_local(); |
| 1029 | p = rcu_dereference_check(rcu_torture_current, | 1029 | p = rcu_dereference_check(rcu_torture_current, |
| 1030 | rcu_read_lock_bh_held() || | 1030 | rcu_read_lock_bh_held() || |
| @@ -1047,14 +1047,16 @@ static void rcu_torture_timer(unsigned long unused) | |||
| 1047 | /* Should not happen, but... */ | 1047 | /* Should not happen, but... */ |
| 1048 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1048 | pipe_count = RCU_TORTURE_PIPE_LEN; |
| 1049 | } | 1049 | } |
| 1050 | completed_end = cur_ops->completed(); | 1050 | completed = cur_ops->completed(); |
| 1051 | if (pipe_count > 1) { | 1051 | if (pipe_count > 1) { |
| 1052 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts, | 1052 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, ts, |
| 1053 | completed, completed_end); | 1053 | started, completed); |
| 1054 | rcutorture_trace_dump(); | 1054 | rcutorture_trace_dump(); |
| 1055 | } | 1055 | } |
| 1056 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1056 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
| 1057 | completed = completed_end - completed; | 1057 | completed = completed - started; |
| 1058 | if (cur_ops->started) | ||
| 1059 | completed++; | ||
| 1058 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1060 | if (completed > RCU_TORTURE_PIPE_LEN) { |
| 1059 | /* Should not happen, but... */ | 1061 | /* Should not happen, but... */ |
| 1060 | completed = RCU_TORTURE_PIPE_LEN; | 1062 | completed = RCU_TORTURE_PIPE_LEN; |
| @@ -1073,8 +1075,8 @@ static void rcu_torture_timer(unsigned long unused) | |||
| 1073 | static int | 1075 | static int |
| 1074 | rcu_torture_reader(void *arg) | 1076 | rcu_torture_reader(void *arg) |
| 1075 | { | 1077 | { |
| 1076 | int completed; | 1078 | unsigned long started; |
| 1077 | int completed_end; | 1079 | unsigned long completed; |
| 1078 | int idx; | 1080 | int idx; |
| 1079 | DEFINE_TORTURE_RANDOM(rand); | 1081 | DEFINE_TORTURE_RANDOM(rand); |
| 1080 | struct rcu_torture *p; | 1082 | struct rcu_torture *p; |
| @@ -1093,7 +1095,10 @@ rcu_torture_reader(void *arg) | |||
| 1093 | mod_timer(&t, jiffies + 1); | 1095 | mod_timer(&t, jiffies + 1); |
| 1094 | } | 1096 | } |
| 1095 | idx = cur_ops->readlock(); | 1097 | idx = cur_ops->readlock(); |
| 1096 | completed = cur_ops->completed(); | 1098 | if (cur_ops->started) |
| 1099 | started = cur_ops->started(); | ||
| 1100 | else | ||
| 1101 | started = cur_ops->completed(); | ||
| 1097 | ts = rcu_trace_clock_local(); | 1102 | ts = rcu_trace_clock_local(); |
| 1098 | p = rcu_dereference_check(rcu_torture_current, | 1103 | p = rcu_dereference_check(rcu_torture_current, |
| 1099 | rcu_read_lock_bh_held() || | 1104 | rcu_read_lock_bh_held() || |
| @@ -1114,14 +1119,16 @@ rcu_torture_reader(void *arg) | |||
| 1114 | /* Should not happen, but... */ | 1119 | /* Should not happen, but... */ |
| 1115 | pipe_count = RCU_TORTURE_PIPE_LEN; | 1120 | pipe_count = RCU_TORTURE_PIPE_LEN; |
| 1116 | } | 1121 | } |
| 1117 | completed_end = cur_ops->completed(); | 1122 | completed = cur_ops->completed(); |
| 1118 | if (pipe_count > 1) { | 1123 | if (pipe_count > 1) { |
| 1119 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, | 1124 | do_trace_rcu_torture_read(cur_ops->name, &p->rtort_rcu, |
| 1120 | ts, completed, completed_end); | 1125 | ts, started, completed); |
| 1121 | rcutorture_trace_dump(); | 1126 | rcutorture_trace_dump(); |
| 1122 | } | 1127 | } |
| 1123 | __this_cpu_inc(rcu_torture_count[pipe_count]); | 1128 | __this_cpu_inc(rcu_torture_count[pipe_count]); |
| 1124 | completed = completed_end - completed; | 1129 | completed = completed - started; |
| 1130 | if (cur_ops->started) | ||
| 1131 | completed++; | ||
| 1125 | if (completed > RCU_TORTURE_PIPE_LEN) { | 1132 | if (completed > RCU_TORTURE_PIPE_LEN) { |
| 1126 | /* Should not happen, but... */ | 1133 | /* Should not happen, but... */ |
| 1127 | completed = RCU_TORTURE_PIPE_LEN; | 1134 | completed = RCU_TORTURE_PIPE_LEN; |
| @@ -1420,6 +1427,9 @@ static int rcu_torture_barrier(void *arg) | |||
| 1420 | cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */ | 1427 | cur_ops->cb_barrier(); /* Implies smp_mb() for wait_event(). */ |
| 1421 | if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) { | 1428 | if (atomic_read(&barrier_cbs_invoked) != n_barrier_cbs) { |
| 1422 | n_rcu_torture_barrier_error++; | 1429 | n_rcu_torture_barrier_error++; |
| 1430 | pr_err("barrier_cbs_invoked = %d, n_barrier_cbs = %d\n", | ||
| 1431 | atomic_read(&barrier_cbs_invoked), | ||
| 1432 | n_barrier_cbs); | ||
| 1423 | WARN_ON_ONCE(1); | 1433 | WARN_ON_ONCE(1); |
| 1424 | } | 1434 | } |
| 1425 | n_barrier_successes++; | 1435 | n_barrier_successes++; |
