diff options
| author | Len Brown <len.brown@intel.com> | 2011-01-12 18:06:06 -0500 |
|---|---|---|
| committer | Len Brown <len.brown@intel.com> | 2011-01-12 18:06:06 -0500 |
| commit | 56dbed129df3fdd4caf9018b6e7599ee258a5420 (patch) | |
| tree | b902491aef3a99efe0d9d49edd0f6e414dba654f /kernel/rcutorture.c | |
| parent | 2a2d31c8dc6f1ebcf5eab1d93a0cb0fb4ed57c7c (diff) | |
| parent | f878133bf022717b880d0e0995b8f91436fd605c (diff) | |
Merge branch 'linus' into idle-test
Diffstat (limited to 'kernel/rcutorture.c')
| -rw-r--r-- | kernel/rcutorture.c | 270 |
1 files changed, 259 insertions, 11 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 9d8e8fb2515f..89613f97ff26 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
| @@ -47,6 +47,7 @@ | |||
| 47 | #include <linux/srcu.h> | 47 | #include <linux/srcu.h> |
| 48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
| 49 | #include <asm/byteorder.h> | 49 | #include <asm/byteorder.h> |
| 50 | #include <linux/sched.h> | ||
| 50 | 51 | ||
| 51 | MODULE_LICENSE("GPL"); | 52 | MODULE_LICENSE("GPL"); |
| 52 | MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and " | 53 | MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com> and " |
| @@ -64,6 +65,9 @@ static int irqreader = 1; /* RCU readers from irq (timers). */ | |||
| 64 | static int fqs_duration = 0; /* Duration of bursts (us), 0 to disable. */ | 65 | static int fqs_duration = 0; /* Duration of bursts (us), 0 to disable. */ |
| 65 | static int fqs_holdoff = 0; /* Hold time within burst (us). */ | 66 | static int fqs_holdoff = 0; /* Hold time within burst (us). */ |
| 66 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ | 67 | static int fqs_stutter = 3; /* Wait time between bursts (s). */ |
| 68 | static int test_boost = 1; /* Test RCU prio boost: 0=no, 1=maybe, 2=yes. */ | ||
| 69 | static int test_boost_interval = 7; /* Interval between boost tests, seconds. */ | ||
| 70 | static int test_boost_duration = 4; /* Duration of each boost test, seconds. */ | ||
| 67 | static char *torture_type = "rcu"; /* What RCU implementation to torture. */ | 71 | static char *torture_type = "rcu"; /* What RCU implementation to torture. */ |
| 68 | 72 | ||
| 69 | module_param(nreaders, int, 0444); | 73 | module_param(nreaders, int, 0444); |
| @@ -88,6 +92,12 @@ module_param(fqs_holdoff, int, 0444); | |||
| 88 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); | 92 | MODULE_PARM_DESC(fqs_holdoff, "Holdoff time within fqs bursts (us)"); |
| 89 | module_param(fqs_stutter, int, 0444); | 93 | module_param(fqs_stutter, int, 0444); |
| 90 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); | 94 | MODULE_PARM_DESC(fqs_stutter, "Wait time between fqs bursts (s)"); |
| 95 | module_param(test_boost, int, 0444); | ||
| 96 | MODULE_PARM_DESC(test_boost, "Test RCU prio boost: 0=no, 1=maybe, 2=yes."); | ||
| 97 | module_param(test_boost_interval, int, 0444); | ||
| 98 | MODULE_PARM_DESC(test_boost_interval, "Interval between boost tests, seconds."); | ||
| 99 | module_param(test_boost_duration, int, 0444); | ||
| 100 | MODULE_PARM_DESC(test_boost_duration, "Duration of each boost test, seconds."); | ||
| 91 | module_param(torture_type, charp, 0444); | 101 | module_param(torture_type, charp, 0444); |
| 92 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); | 102 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); |
| 93 | 103 | ||
| @@ -109,6 +119,7 @@ static struct task_struct *stats_task; | |||
| 109 | static struct task_struct *shuffler_task; | 119 | static struct task_struct *shuffler_task; |
| 110 | static struct task_struct *stutter_task; | 120 | static struct task_struct *stutter_task; |
| 111 | static struct task_struct *fqs_task; | 121 | static struct task_struct *fqs_task; |
| 122 | static struct task_struct *boost_tasks[NR_CPUS]; | ||
| 112 | 123 | ||
| 113 | #define RCU_TORTURE_PIPE_LEN 10 | 124 | #define RCU_TORTURE_PIPE_LEN 10 |
| 114 | 125 | ||
| @@ -134,6 +145,12 @@ static atomic_t n_rcu_torture_alloc_fail; | |||
| 134 | static atomic_t n_rcu_torture_free; | 145 | static atomic_t n_rcu_torture_free; |
| 135 | static atomic_t n_rcu_torture_mberror; | 146 | static atomic_t n_rcu_torture_mberror; |
| 136 | static atomic_t n_rcu_torture_error; | 147 | static atomic_t n_rcu_torture_error; |
| 148 | static long n_rcu_torture_boost_ktrerror; | ||
| 149 | static long n_rcu_torture_boost_rterror; | ||
| 150 | static long n_rcu_torture_boost_allocerror; | ||
| 151 | static long n_rcu_torture_boost_afferror; | ||
| 152 | static long n_rcu_torture_boost_failure; | ||
| 153 | static long n_rcu_torture_boosts; | ||
| 137 | static long n_rcu_torture_timers; | 154 | static long n_rcu_torture_timers; |
| 138 | static struct list_head rcu_torture_removed; | 155 | static struct list_head rcu_torture_removed; |
| 139 | static cpumask_var_t shuffle_tmp_mask; | 156 | static cpumask_var_t shuffle_tmp_mask; |
| @@ -147,6 +164,16 @@ static int stutter_pause_test; | |||
| 147 | #endif | 164 | #endif |
| 148 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; | 165 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; |
| 149 | 166 | ||
| 167 | #ifdef CONFIG_RCU_BOOST | ||
| 168 | #define rcu_can_boost() 1 | ||
| 169 | #else /* #ifdef CONFIG_RCU_BOOST */ | ||
| 170 | #define rcu_can_boost() 0 | ||
| 171 | #endif /* #else #ifdef CONFIG_RCU_BOOST */ | ||
| 172 | |||
| 173 | static unsigned long boost_starttime; /* jiffies of next boost test start. */ | ||
| 174 | DEFINE_MUTEX(boost_mutex); /* protect setting boost_starttime */ | ||
| 175 | /* and boost task create/destroy. */ | ||
| 176 | |||
| 150 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ | 177 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ |
| 151 | 178 | ||
| 152 | #define FULLSTOP_DONTSTOP 0 /* Normal operation. */ | 179 | #define FULLSTOP_DONTSTOP 0 /* Normal operation. */ |
| @@ -277,6 +304,7 @@ struct rcu_torture_ops { | |||
| 277 | void (*fqs)(void); | 304 | void (*fqs)(void); |
| 278 | int (*stats)(char *page); | 305 | int (*stats)(char *page); |
| 279 | int irq_capable; | 306 | int irq_capable; |
| 307 | int can_boost; | ||
| 280 | char *name; | 308 | char *name; |
| 281 | }; | 309 | }; |
| 282 | 310 | ||
| @@ -366,6 +394,7 @@ static struct rcu_torture_ops rcu_ops = { | |||
| 366 | .fqs = rcu_force_quiescent_state, | 394 | .fqs = rcu_force_quiescent_state, |
| 367 | .stats = NULL, | 395 | .stats = NULL, |
| 368 | .irq_capable = 1, | 396 | .irq_capable = 1, |
| 397 | .can_boost = rcu_can_boost(), | ||
| 369 | .name = "rcu" | 398 | .name = "rcu" |
| 370 | }; | 399 | }; |
| 371 | 400 | ||
| @@ -408,6 +437,7 @@ static struct rcu_torture_ops rcu_sync_ops = { | |||
| 408 | .fqs = rcu_force_quiescent_state, | 437 | .fqs = rcu_force_quiescent_state, |
| 409 | .stats = NULL, | 438 | .stats = NULL, |
| 410 | .irq_capable = 1, | 439 | .irq_capable = 1, |
| 440 | .can_boost = rcu_can_boost(), | ||
| 411 | .name = "rcu_sync" | 441 | .name = "rcu_sync" |
| 412 | }; | 442 | }; |
| 413 | 443 | ||
| @@ -424,6 +454,7 @@ static struct rcu_torture_ops rcu_expedited_ops = { | |||
| 424 | .fqs = rcu_force_quiescent_state, | 454 | .fqs = rcu_force_quiescent_state, |
| 425 | .stats = NULL, | 455 | .stats = NULL, |
| 426 | .irq_capable = 1, | 456 | .irq_capable = 1, |
| 457 | .can_boost = rcu_can_boost(), | ||
| 427 | .name = "rcu_expedited" | 458 | .name = "rcu_expedited" |
| 428 | }; | 459 | }; |
| 429 | 460 | ||
| @@ -684,6 +715,110 @@ static struct rcu_torture_ops sched_expedited_ops = { | |||
| 684 | }; | 715 | }; |
| 685 | 716 | ||
| 686 | /* | 717 | /* |
| 718 | * RCU torture priority-boost testing. Runs one real-time thread per | ||
| 719 | * CPU for moderate bursts, repeatedly registering RCU callbacks and | ||
| 720 | * spinning waiting for them to be invoked. If a given callback takes | ||
| 721 | * too long to be invoked, we assume that priority inversion has occurred. | ||
| 722 | */ | ||
| 723 | |||
| 724 | struct rcu_boost_inflight { | ||
| 725 | struct rcu_head rcu; | ||
| 726 | int inflight; | ||
| 727 | }; | ||
| 728 | |||
| 729 | static void rcu_torture_boost_cb(struct rcu_head *head) | ||
| 730 | { | ||
| 731 | struct rcu_boost_inflight *rbip = | ||
| 732 | container_of(head, struct rcu_boost_inflight, rcu); | ||
| 733 | |||
| 734 | smp_mb(); /* Ensure RCU-core accesses precede clearing ->inflight */ | ||
| 735 | rbip->inflight = 0; | ||
| 736 | } | ||
| 737 | |||
| 738 | static int rcu_torture_boost(void *arg) | ||
| 739 | { | ||
| 740 | unsigned long call_rcu_time; | ||
| 741 | unsigned long endtime; | ||
| 742 | unsigned long oldstarttime; | ||
| 743 | struct rcu_boost_inflight rbi = { .inflight = 0 }; | ||
| 744 | struct sched_param sp; | ||
| 745 | |||
| 746 | VERBOSE_PRINTK_STRING("rcu_torture_boost started"); | ||
| 747 | |||
| 748 | /* Set real-time priority. */ | ||
| 749 | sp.sched_priority = 1; | ||
| 750 | if (sched_setscheduler(current, SCHED_FIFO, &sp) < 0) { | ||
| 751 | VERBOSE_PRINTK_STRING("rcu_torture_boost RT prio failed!"); | ||
| 752 | n_rcu_torture_boost_rterror++; | ||
| 753 | } | ||
| 754 | |||
| 755 | /* Each pass through the following loop does one boost-test cycle. */ | ||
| 756 | do { | ||
| 757 | /* Wait for the next test interval. */ | ||
| 758 | oldstarttime = boost_starttime; | ||
| 759 | while (jiffies - oldstarttime > ULONG_MAX / 2) { | ||
| 760 | schedule_timeout_uninterruptible(1); | ||
| 761 | rcu_stutter_wait("rcu_torture_boost"); | ||
| 762 | if (kthread_should_stop() || | ||
| 763 | fullstop != FULLSTOP_DONTSTOP) | ||
| 764 | goto checkwait; | ||
| 765 | } | ||
| 766 | |||
| 767 | /* Do one boost-test interval. */ | ||
| 768 | endtime = oldstarttime + test_boost_duration * HZ; | ||
| 769 | call_rcu_time = jiffies; | ||
| 770 | while (jiffies - endtime > ULONG_MAX / 2) { | ||
| 771 | /* If we don't have a callback in flight, post one. */ | ||
| 772 | if (!rbi.inflight) { | ||
| 773 | smp_mb(); /* RCU core before ->inflight = 1. */ | ||
| 774 | rbi.inflight = 1; | ||
| 775 | call_rcu(&rbi.rcu, rcu_torture_boost_cb); | ||
| 776 | if (jiffies - call_rcu_time > | ||
| 777 | test_boost_duration * HZ - HZ / 2) { | ||
| 778 | VERBOSE_PRINTK_STRING("rcu_torture_boost boosting failed"); | ||
| 779 | n_rcu_torture_boost_failure++; | ||
| 780 | } | ||
| 781 | call_rcu_time = jiffies; | ||
| 782 | } | ||
| 783 | cond_resched(); | ||
| 784 | rcu_stutter_wait("rcu_torture_boost"); | ||
| 785 | if (kthread_should_stop() || | ||
| 786 | fullstop != FULLSTOP_DONTSTOP) | ||
| 787 | goto checkwait; | ||
| 788 | } | ||
| 789 | |||
| 790 | /* | ||
| 791 | * Set the start time of the next test interval. | ||
| 792 | * Yes, this is vulnerable to long delays, but such | ||
| 793 | * delays simply cause a false negative for the next | ||
| 794 | * interval. Besides, we are running at RT priority, | ||
| 795 | * so delays should be relatively rare. | ||
| 796 | */ | ||
| 797 | while (oldstarttime == boost_starttime) { | ||
| 798 | if (mutex_trylock(&boost_mutex)) { | ||
| 799 | boost_starttime = jiffies + | ||
| 800 | test_boost_interval * HZ; | ||
| 801 | n_rcu_torture_boosts++; | ||
| 802 | mutex_unlock(&boost_mutex); | ||
| 803 | break; | ||
| 804 | } | ||
| 805 | schedule_timeout_uninterruptible(1); | ||
| 806 | } | ||
| 807 | |||
| 808 | /* Go do the stutter. */ | ||
| 809 | checkwait: rcu_stutter_wait("rcu_torture_boost"); | ||
| 810 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); | ||
| 811 | |||
| 812 | /* Clean up and exit. */ | ||
| 813 | VERBOSE_PRINTK_STRING("rcu_torture_boost task stopping"); | ||
| 814 | rcutorture_shutdown_absorb("rcu_torture_boost"); | ||
| 815 | while (!kthread_should_stop() || rbi.inflight) | ||
| 816 | schedule_timeout_uninterruptible(1); | ||
| 817 | smp_mb(); /* order accesses to ->inflight before stack-frame death. */ | ||
| 818 | return 0; | ||
| 819 | } | ||
| 820 | |||
| 821 | /* | ||
| 687 | * RCU torture force-quiescent-state kthread. Repeatedly induces | 822 | * RCU torture force-quiescent-state kthread. Repeatedly induces |
| 688 | * bursts of calls to force_quiescent_state(), increasing the probability | 823 | * bursts of calls to force_quiescent_state(), increasing the probability |
| 689 | * of occurrence of some important types of race conditions. | 824 | * of occurrence of some important types of race conditions. |
| @@ -933,7 +1068,8 @@ rcu_torture_printk(char *page) | |||
| 933 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); | 1068 | cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG); |
| 934 | cnt += sprintf(&page[cnt], | 1069 | cnt += sprintf(&page[cnt], |
| 935 | "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " | 1070 | "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d " |
| 936 | "rtmbe: %d nt: %ld", | 1071 | "rtmbe: %d rtbke: %ld rtbre: %ld rtbae: %ld rtbafe: %ld " |
| 1072 | "rtbf: %ld rtb: %ld nt: %ld", | ||
| 937 | rcu_torture_current, | 1073 | rcu_torture_current, |
| 938 | rcu_torture_current_version, | 1074 | rcu_torture_current_version, |
| 939 | list_empty(&rcu_torture_freelist), | 1075 | list_empty(&rcu_torture_freelist), |
| @@ -941,8 +1077,19 @@ rcu_torture_printk(char *page) | |||
| 941 | atomic_read(&n_rcu_torture_alloc_fail), | 1077 | atomic_read(&n_rcu_torture_alloc_fail), |
| 942 | atomic_read(&n_rcu_torture_free), | 1078 | atomic_read(&n_rcu_torture_free), |
| 943 | atomic_read(&n_rcu_torture_mberror), | 1079 | atomic_read(&n_rcu_torture_mberror), |
| 1080 | n_rcu_torture_boost_ktrerror, | ||
| 1081 | n_rcu_torture_boost_rterror, | ||
| 1082 | n_rcu_torture_boost_allocerror, | ||
| 1083 | n_rcu_torture_boost_afferror, | ||
| 1084 | n_rcu_torture_boost_failure, | ||
| 1085 | n_rcu_torture_boosts, | ||
| 944 | n_rcu_torture_timers); | 1086 | n_rcu_torture_timers); |
| 945 | if (atomic_read(&n_rcu_torture_mberror) != 0) | 1087 | if (atomic_read(&n_rcu_torture_mberror) != 0 || |
| 1088 | n_rcu_torture_boost_ktrerror != 0 || | ||
| 1089 | n_rcu_torture_boost_rterror != 0 || | ||
| 1090 | n_rcu_torture_boost_allocerror != 0 || | ||
| 1091 | n_rcu_torture_boost_afferror != 0 || | ||
| 1092 | n_rcu_torture_boost_failure != 0) | ||
| 946 | cnt += sprintf(&page[cnt], " !!!"); | 1093 | cnt += sprintf(&page[cnt], " !!!"); |
| 947 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); | 1094 | cnt += sprintf(&page[cnt], "\n%s%s ", torture_type, TORTURE_FLAG); |
| 948 | if (i > 1) { | 1095 | if (i > 1) { |
| @@ -1094,22 +1241,91 @@ rcu_torture_stutter(void *arg) | |||
| 1094 | } | 1241 | } |
| 1095 | 1242 | ||
| 1096 | static inline void | 1243 | static inline void |
| 1097 | rcu_torture_print_module_parms(char *tag) | 1244 | rcu_torture_print_module_parms(struct rcu_torture_ops *cur_ops, char *tag) |
| 1098 | { | 1245 | { |
| 1099 | printk(KERN_ALERT "%s" TORTURE_FLAG | 1246 | printk(KERN_ALERT "%s" TORTURE_FLAG |
| 1100 | "--- %s: nreaders=%d nfakewriters=%d " | 1247 | "--- %s: nreaders=%d nfakewriters=%d " |
| 1101 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " | 1248 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " |
| 1102 | "shuffle_interval=%d stutter=%d irqreader=%d " | 1249 | "shuffle_interval=%d stutter=%d irqreader=%d " |
| 1103 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d\n", | 1250 | "fqs_duration=%d fqs_holdoff=%d fqs_stutter=%d " |
| 1251 | "test_boost=%d/%d test_boost_interval=%d " | ||
| 1252 | "test_boost_duration=%d\n", | ||
| 1104 | torture_type, tag, nrealreaders, nfakewriters, | 1253 | torture_type, tag, nrealreaders, nfakewriters, |
| 1105 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, | 1254 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, |
| 1106 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter); | 1255 | stutter, irqreader, fqs_duration, fqs_holdoff, fqs_stutter, |
| 1256 | test_boost, cur_ops->can_boost, | ||
| 1257 | test_boost_interval, test_boost_duration); | ||
| 1107 | } | 1258 | } |
| 1108 | 1259 | ||
| 1109 | static struct notifier_block rcutorture_nb = { | 1260 | static struct notifier_block rcutorture_shutdown_nb = { |
| 1110 | .notifier_call = rcutorture_shutdown_notify, | 1261 | .notifier_call = rcutorture_shutdown_notify, |
| 1111 | }; | 1262 | }; |
| 1112 | 1263 | ||
| 1264 | static void rcutorture_booster_cleanup(int cpu) | ||
| 1265 | { | ||
| 1266 | struct task_struct *t; | ||
| 1267 | |||
| 1268 | if (boost_tasks[cpu] == NULL) | ||
| 1269 | return; | ||
| 1270 | mutex_lock(&boost_mutex); | ||
| 1271 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_boost task"); | ||
| 1272 | t = boost_tasks[cpu]; | ||
| 1273 | boost_tasks[cpu] = NULL; | ||
| 1274 | mutex_unlock(&boost_mutex); | ||
| 1275 | |||
| 1276 | /* This must be outside of the mutex, otherwise deadlock! */ | ||
| 1277 | kthread_stop(t); | ||
| 1278 | } | ||
| 1279 | |||
| 1280 | static int rcutorture_booster_init(int cpu) | ||
| 1281 | { | ||
| 1282 | int retval; | ||
| 1283 | |||
| 1284 | if (boost_tasks[cpu] != NULL) | ||
| 1285 | return 0; /* Already created, nothing more to do. */ | ||
| 1286 | |||
| 1287 | /* Don't allow time recalculation while creating a new task. */ | ||
| 1288 | mutex_lock(&boost_mutex); | ||
| 1289 | VERBOSE_PRINTK_STRING("Creating rcu_torture_boost task"); | ||
| 1290 | boost_tasks[cpu] = kthread_create(rcu_torture_boost, NULL, | ||
| 1291 | "rcu_torture_boost"); | ||
| 1292 | if (IS_ERR(boost_tasks[cpu])) { | ||
| 1293 | retval = PTR_ERR(boost_tasks[cpu]); | ||
| 1294 | VERBOSE_PRINTK_STRING("rcu_torture_boost task create failed"); | ||
| 1295 | n_rcu_torture_boost_ktrerror++; | ||
| 1296 | boost_tasks[cpu] = NULL; | ||
| 1297 | mutex_unlock(&boost_mutex); | ||
| 1298 | return retval; | ||
| 1299 | } | ||
| 1300 | kthread_bind(boost_tasks[cpu], cpu); | ||
| 1301 | wake_up_process(boost_tasks[cpu]); | ||
| 1302 | mutex_unlock(&boost_mutex); | ||
| 1303 | return 0; | ||
| 1304 | } | ||
| 1305 | |||
| 1306 | static int rcutorture_cpu_notify(struct notifier_block *self, | ||
| 1307 | unsigned long action, void *hcpu) | ||
| 1308 | { | ||
| 1309 | long cpu = (long)hcpu; | ||
| 1310 | |||
| 1311 | switch (action) { | ||
| 1312 | case CPU_ONLINE: | ||
| 1313 | case CPU_DOWN_FAILED: | ||
| 1314 | (void)rcutorture_booster_init(cpu); | ||
| 1315 | break; | ||
| 1316 | case CPU_DOWN_PREPARE: | ||
| 1317 | rcutorture_booster_cleanup(cpu); | ||
| 1318 | break; | ||
| 1319 | default: | ||
| 1320 | break; | ||
| 1321 | } | ||
| 1322 | return NOTIFY_OK; | ||
| 1323 | } | ||
| 1324 | |||
| 1325 | static struct notifier_block rcutorture_cpu_nb = { | ||
| 1326 | .notifier_call = rcutorture_cpu_notify, | ||
| 1327 | }; | ||
| 1328 | |||
| 1113 | static void | 1329 | static void |
| 1114 | rcu_torture_cleanup(void) | 1330 | rcu_torture_cleanup(void) |
| 1115 | { | 1331 | { |
| @@ -1127,7 +1343,7 @@ rcu_torture_cleanup(void) | |||
| 1127 | } | 1343 | } |
| 1128 | fullstop = FULLSTOP_RMMOD; | 1344 | fullstop = FULLSTOP_RMMOD; |
| 1129 | mutex_unlock(&fullstop_mutex); | 1345 | mutex_unlock(&fullstop_mutex); |
| 1130 | unregister_reboot_notifier(&rcutorture_nb); | 1346 | unregister_reboot_notifier(&rcutorture_shutdown_nb); |
| 1131 | if (stutter_task) { | 1347 | if (stutter_task) { |
| 1132 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | 1348 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); |
| 1133 | kthread_stop(stutter_task); | 1349 | kthread_stop(stutter_task); |
| @@ -1184,6 +1400,12 @@ rcu_torture_cleanup(void) | |||
| 1184 | kthread_stop(fqs_task); | 1400 | kthread_stop(fqs_task); |
| 1185 | } | 1401 | } |
| 1186 | fqs_task = NULL; | 1402 | fqs_task = NULL; |
| 1403 | if ((test_boost == 1 && cur_ops->can_boost) || | ||
| 1404 | test_boost == 2) { | ||
| 1405 | unregister_cpu_notifier(&rcutorture_cpu_nb); | ||
| 1406 | for_each_possible_cpu(i) | ||
| 1407 | rcutorture_booster_cleanup(i); | ||
| 1408 | } | ||
| 1187 | 1409 | ||
| 1188 | /* Wait for all RCU callbacks to fire. */ | 1410 | /* Wait for all RCU callbacks to fire. */ |
| 1189 | 1411 | ||
| @@ -1195,9 +1417,9 @@ rcu_torture_cleanup(void) | |||
| 1195 | if (cur_ops->cleanup) | 1417 | if (cur_ops->cleanup) |
| 1196 | cur_ops->cleanup(); | 1418 | cur_ops->cleanup(); |
| 1197 | if (atomic_read(&n_rcu_torture_error)) | 1419 | if (atomic_read(&n_rcu_torture_error)) |
| 1198 | rcu_torture_print_module_parms("End of test: FAILURE"); | 1420 | rcu_torture_print_module_parms(cur_ops, "End of test: FAILURE"); |
| 1199 | else | 1421 | else |
| 1200 | rcu_torture_print_module_parms("End of test: SUCCESS"); | 1422 | rcu_torture_print_module_parms(cur_ops, "End of test: SUCCESS"); |
| 1201 | } | 1423 | } |
| 1202 | 1424 | ||
| 1203 | static int __init | 1425 | static int __init |
| @@ -1242,7 +1464,7 @@ rcu_torture_init(void) | |||
| 1242 | nrealreaders = nreaders; | 1464 | nrealreaders = nreaders; |
| 1243 | else | 1465 | else |
| 1244 | nrealreaders = 2 * num_online_cpus(); | 1466 | nrealreaders = 2 * num_online_cpus(); |
| 1245 | rcu_torture_print_module_parms("Start of test"); | 1467 | rcu_torture_print_module_parms(cur_ops, "Start of test"); |
| 1246 | fullstop = FULLSTOP_DONTSTOP; | 1468 | fullstop = FULLSTOP_DONTSTOP; |
| 1247 | 1469 | ||
| 1248 | /* Set up the freelist. */ | 1470 | /* Set up the freelist. */ |
| @@ -1263,6 +1485,12 @@ rcu_torture_init(void) | |||
| 1263 | atomic_set(&n_rcu_torture_free, 0); | 1485 | atomic_set(&n_rcu_torture_free, 0); |
| 1264 | atomic_set(&n_rcu_torture_mberror, 0); | 1486 | atomic_set(&n_rcu_torture_mberror, 0); |
| 1265 | atomic_set(&n_rcu_torture_error, 0); | 1487 | atomic_set(&n_rcu_torture_error, 0); |
| 1488 | n_rcu_torture_boost_ktrerror = 0; | ||
| 1489 | n_rcu_torture_boost_rterror = 0; | ||
| 1490 | n_rcu_torture_boost_allocerror = 0; | ||
| 1491 | n_rcu_torture_boost_afferror = 0; | ||
| 1492 | n_rcu_torture_boost_failure = 0; | ||
| 1493 | n_rcu_torture_boosts = 0; | ||
| 1266 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) | 1494 | for (i = 0; i < RCU_TORTURE_PIPE_LEN + 1; i++) |
| 1267 | atomic_set(&rcu_torture_wcount[i], 0); | 1495 | atomic_set(&rcu_torture_wcount[i], 0); |
| 1268 | for_each_possible_cpu(cpu) { | 1496 | for_each_possible_cpu(cpu) { |
| @@ -1376,7 +1604,27 @@ rcu_torture_init(void) | |||
| 1376 | goto unwind; | 1604 | goto unwind; |
| 1377 | } | 1605 | } |
| 1378 | } | 1606 | } |
| 1379 | register_reboot_notifier(&rcutorture_nb); | 1607 | if (test_boost_interval < 1) |
| 1608 | test_boost_interval = 1; | ||
| 1609 | if (test_boost_duration < 2) | ||
| 1610 | test_boost_duration = 2; | ||
| 1611 | if ((test_boost == 1 && cur_ops->can_boost) || | ||
| 1612 | test_boost == 2) { | ||
| 1613 | int retval; | ||
| 1614 | |||
| 1615 | boost_starttime = jiffies + test_boost_interval * HZ; | ||
| 1616 | register_cpu_notifier(&rcutorture_cpu_nb); | ||
| 1617 | for_each_possible_cpu(i) { | ||
| 1618 | if (cpu_is_offline(i)) | ||
| 1619 | continue; /* Heuristic: CPU can go offline. */ | ||
| 1620 | retval = rcutorture_booster_init(i); | ||
| 1621 | if (retval < 0) { | ||
| 1622 | firsterr = retval; | ||
| 1623 | goto unwind; | ||
| 1624 | } | ||
| 1625 | } | ||
| 1626 | } | ||
| 1627 | register_reboot_notifier(&rcutorture_shutdown_nb); | ||
| 1380 | mutex_unlock(&fullstop_mutex); | 1628 | mutex_unlock(&fullstop_mutex); |
| 1381 | return 0; | 1629 | return 0; |
| 1382 | 1630 | ||
