diff options
Diffstat (limited to 'kernel/rcutorture.c')
| -rw-r--r-- | kernel/rcutorture.c | 113 |
1 files changed, 68 insertions, 45 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 1cff28db56b6..7c4142a79f0a 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
| @@ -136,29 +136,47 @@ static int stutter_pause_test = 0; | |||
| 136 | #endif | 136 | #endif |
| 137 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; | 137 | int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT; |
| 138 | 138 | ||
| 139 | #define FULLSTOP_SHUTDOWN 1 /* Bail due to system shutdown/panic. */ | 139 | /* Mediate rmmod and system shutdown. Concurrent rmmod & shutdown illegal! */ |
| 140 | #define FULLSTOP_CLEANUP 2 /* Orderly shutdown. */ | 140 | |
| 141 | static int fullstop; /* stop generating callbacks at test end. */ | 141 | #define FULLSTOP_DONTSTOP 0 /* Normal operation. */ |
| 142 | DEFINE_MUTEX(fullstop_mutex); /* protect fullstop transitions and */ | 142 | #define FULLSTOP_SHUTDOWN 1 /* System shutdown with rcutorture running. */ |
| 143 | /* spawning of kthreads. */ | 143 | #define FULLSTOP_RMMOD 2 /* Normal rmmod of rcutorture. */ |
| 144 | static int fullstop = FULLSTOP_RMMOD; | ||
| 145 | DEFINE_MUTEX(fullstop_mutex); /* Protect fullstop transitions and spawning */ | ||
| 146 | /* of kthreads. */ | ||
| 144 | 147 | ||
| 145 | /* | 148 | /* |
| 146 | * Detect and respond to a signal-based shutdown. | 149 | * Detect and respond to a system shutdown. |
| 147 | */ | 150 | */ |
| 148 | static int | 151 | static int |
| 149 | rcutorture_shutdown_notify(struct notifier_block *unused1, | 152 | rcutorture_shutdown_notify(struct notifier_block *unused1, |
| 150 | unsigned long unused2, void *unused3) | 153 | unsigned long unused2, void *unused3) |
| 151 | { | 154 | { |
| 152 | if (fullstop) | ||
| 153 | return NOTIFY_DONE; | ||
| 154 | mutex_lock(&fullstop_mutex); | 155 | mutex_lock(&fullstop_mutex); |
| 155 | if (!fullstop) | 156 | if (fullstop == FULLSTOP_DONTSTOP) |
| 156 | fullstop = FULLSTOP_SHUTDOWN; | 157 | fullstop = FULLSTOP_SHUTDOWN; |
| 158 | else | ||
| 159 | printk(KERN_WARNING /* but going down anyway, so... */ | ||
| 160 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); | ||
| 157 | mutex_unlock(&fullstop_mutex); | 161 | mutex_unlock(&fullstop_mutex); |
| 158 | return NOTIFY_DONE; | 162 | return NOTIFY_DONE; |
| 159 | } | 163 | } |
| 160 | 164 | ||
| 161 | /* | 165 | /* |
| 166 | * Absorb kthreads into a kernel function that won't return, so that | ||
| 167 | * they won't ever access module text or data again. | ||
| 168 | */ | ||
| 169 | static void rcutorture_shutdown_absorb(char *title) | ||
| 170 | { | ||
| 171 | if (ACCESS_ONCE(fullstop) == FULLSTOP_SHUTDOWN) { | ||
| 172 | printk(KERN_NOTICE | ||
| 173 | "rcutorture thread %s parking due to system shutdown\n", | ||
| 174 | title); | ||
| 175 | schedule_timeout_uninterruptible(MAX_SCHEDULE_TIMEOUT); | ||
| 176 | } | ||
| 177 | } | ||
| 178 | |||
| 179 | /* | ||
| 162 | * Allocate an element from the rcu_tortures pool. | 180 | * Allocate an element from the rcu_tortures pool. |
| 163 | */ | 181 | */ |
| 164 | static struct rcu_torture * | 182 | static struct rcu_torture * |
| @@ -219,13 +237,14 @@ rcu_random(struct rcu_random_state *rrsp) | |||
| 219 | } | 237 | } |
| 220 | 238 | ||
| 221 | static void | 239 | static void |
| 222 | rcu_stutter_wait(void) | 240 | rcu_stutter_wait(char *title) |
| 223 | { | 241 | { |
| 224 | while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) { | 242 | while (stutter_pause_test || !rcutorture_runnable) { |
| 225 | if (rcutorture_runnable) | 243 | if (rcutorture_runnable) |
| 226 | schedule_timeout_interruptible(1); | 244 | schedule_timeout_interruptible(1); |
| 227 | else | 245 | else |
| 228 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); | 246 | schedule_timeout_interruptible(round_jiffies_relative(HZ)); |
| 247 | rcutorture_shutdown_absorb(title); | ||
| 229 | } | 248 | } |
| 230 | } | 249 | } |
| 231 | 250 | ||
| @@ -287,7 +306,7 @@ rcu_torture_cb(struct rcu_head *p) | |||
| 287 | int i; | 306 | int i; |
| 288 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); | 307 | struct rcu_torture *rp = container_of(p, struct rcu_torture, rtort_rcu); |
| 289 | 308 | ||
| 290 | if (fullstop) { | 309 | if (fullstop != FULLSTOP_DONTSTOP) { |
| 291 | /* Test is ending, just drop callbacks on the floor. */ | 310 | /* Test is ending, just drop callbacks on the floor. */ |
| 292 | /* The next initialization will pick up the pieces. */ | 311 | /* The next initialization will pick up the pieces. */ |
| 293 | return; | 312 | return; |
| @@ -619,10 +638,11 @@ rcu_torture_writer(void *arg) | |||
| 619 | } | 638 | } |
| 620 | rcu_torture_current_version++; | 639 | rcu_torture_current_version++; |
| 621 | oldbatch = cur_ops->completed(); | 640 | oldbatch = cur_ops->completed(); |
| 622 | rcu_stutter_wait(); | 641 | rcu_stutter_wait("rcu_torture_writer"); |
| 623 | } while (!kthread_should_stop() && !fullstop); | 642 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
| 624 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); | 643 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); |
| 625 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 644 | rcutorture_shutdown_absorb("rcu_torture_writer"); |
| 645 | while (!kthread_should_stop()) | ||
| 626 | schedule_timeout_uninterruptible(1); | 646 | schedule_timeout_uninterruptible(1); |
| 627 | return 0; | 647 | return 0; |
| 628 | } | 648 | } |
| @@ -643,11 +663,12 @@ rcu_torture_fakewriter(void *arg) | |||
| 643 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); | 663 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); |
| 644 | udelay(rcu_random(&rand) & 0x3ff); | 664 | udelay(rcu_random(&rand) & 0x3ff); |
| 645 | cur_ops->sync(); | 665 | cur_ops->sync(); |
| 646 | rcu_stutter_wait(); | 666 | rcu_stutter_wait("rcu_torture_fakewriter"); |
| 647 | } while (!kthread_should_stop() && !fullstop); | 667 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
| 648 | 668 | ||
| 649 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); | 669 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); |
| 650 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 670 | rcutorture_shutdown_absorb("rcu_torture_fakewriter"); |
| 671 | while (!kthread_should_stop()) | ||
| 651 | schedule_timeout_uninterruptible(1); | 672 | schedule_timeout_uninterruptible(1); |
| 652 | return 0; | 673 | return 0; |
| 653 | } | 674 | } |
| @@ -752,12 +773,13 @@ rcu_torture_reader(void *arg) | |||
| 752 | preempt_enable(); | 773 | preempt_enable(); |
| 753 | cur_ops->readunlock(idx); | 774 | cur_ops->readunlock(idx); |
| 754 | schedule(); | 775 | schedule(); |
| 755 | rcu_stutter_wait(); | 776 | rcu_stutter_wait("rcu_torture_reader"); |
| 756 | } while (!kthread_should_stop() && !fullstop); | 777 | } while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP); |
| 757 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); | 778 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); |
| 779 | rcutorture_shutdown_absorb("rcu_torture_reader"); | ||
| 758 | if (irqreader && cur_ops->irqcapable) | 780 | if (irqreader && cur_ops->irqcapable) |
| 759 | del_timer_sync(&t); | 781 | del_timer_sync(&t); |
| 760 | while (!kthread_should_stop() && fullstop != FULLSTOP_SHUTDOWN) | 782 | while (!kthread_should_stop()) |
| 761 | schedule_timeout_uninterruptible(1); | 783 | schedule_timeout_uninterruptible(1); |
| 762 | return 0; | 784 | return 0; |
| 763 | } | 785 | } |
| @@ -854,7 +876,8 @@ rcu_torture_stats(void *arg) | |||
| 854 | do { | 876 | do { |
| 855 | schedule_timeout_interruptible(stat_interval * HZ); | 877 | schedule_timeout_interruptible(stat_interval * HZ); |
| 856 | rcu_torture_stats_print(); | 878 | rcu_torture_stats_print(); |
| 857 | } while (!kthread_should_stop() && !fullstop); | 879 | rcutorture_shutdown_absorb("rcu_torture_stats"); |
| 880 | } while (!kthread_should_stop()); | ||
| 858 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); | 881 | VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping"); |
| 859 | return 0; | 882 | return 0; |
| 860 | } | 883 | } |
| @@ -866,52 +889,49 @@ static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ | |||
| 866 | */ | 889 | */ |
| 867 | static void rcu_torture_shuffle_tasks(void) | 890 | static void rcu_torture_shuffle_tasks(void) |
| 868 | { | 891 | { |
| 869 | cpumask_var_t tmp_mask; | 892 | cpumask_t tmp_mask; |
| 870 | int i; | 893 | int i; |
| 871 | 894 | ||
| 872 | if (!alloc_cpumask_var(&tmp_mask, GFP_KERNEL)) | 895 | cpus_setall(tmp_mask); |
| 873 | BUG(); | ||
| 874 | |||
| 875 | cpumask_setall(tmp_mask); | ||
| 876 | get_online_cpus(); | 896 | get_online_cpus(); |
| 877 | 897 | ||
| 878 | /* No point in shuffling if there is only one online CPU (ex: UP) */ | 898 | /* No point in shuffling if there is only one online CPU (ex: UP) */ |
| 879 | if (num_online_cpus() == 1) | 899 | if (num_online_cpus() == 1) { |
| 880 | goto out; | 900 | put_online_cpus(); |
| 901 | return; | ||
| 902 | } | ||
| 881 | 903 | ||
| 882 | if (rcu_idle_cpu != -1) | 904 | if (rcu_idle_cpu != -1) |
| 883 | cpumask_clear_cpu(rcu_idle_cpu, tmp_mask); | 905 | cpu_clear(rcu_idle_cpu, tmp_mask); |
| 884 | 906 | ||
| 885 | set_cpus_allowed_ptr(current, tmp_mask); | 907 | set_cpus_allowed_ptr(current, &tmp_mask); |
| 886 | 908 | ||
| 887 | if (reader_tasks) { | 909 | if (reader_tasks) { |
| 888 | for (i = 0; i < nrealreaders; i++) | 910 | for (i = 0; i < nrealreaders; i++) |
| 889 | if (reader_tasks[i]) | 911 | if (reader_tasks[i]) |
| 890 | set_cpus_allowed_ptr(reader_tasks[i], | 912 | set_cpus_allowed_ptr(reader_tasks[i], |
| 891 | tmp_mask); | 913 | &tmp_mask); |
| 892 | } | 914 | } |
| 893 | 915 | ||
| 894 | if (fakewriter_tasks) { | 916 | if (fakewriter_tasks) { |
| 895 | for (i = 0; i < nfakewriters; i++) | 917 | for (i = 0; i < nfakewriters; i++) |
| 896 | if (fakewriter_tasks[i]) | 918 | if (fakewriter_tasks[i]) |
| 897 | set_cpus_allowed_ptr(fakewriter_tasks[i], | 919 | set_cpus_allowed_ptr(fakewriter_tasks[i], |
| 898 | tmp_mask); | 920 | &tmp_mask); |
| 899 | } | 921 | } |
| 900 | 922 | ||
| 901 | if (writer_task) | 923 | if (writer_task) |
| 902 | set_cpus_allowed_ptr(writer_task, tmp_mask); | 924 | set_cpus_allowed_ptr(writer_task, &tmp_mask); |
| 903 | 925 | ||
| 904 | if (stats_task) | 926 | if (stats_task) |
| 905 | set_cpus_allowed_ptr(stats_task, tmp_mask); | 927 | set_cpus_allowed_ptr(stats_task, &tmp_mask); |
| 906 | 928 | ||
| 907 | if (rcu_idle_cpu == -1) | 929 | if (rcu_idle_cpu == -1) |
| 908 | rcu_idle_cpu = num_online_cpus() - 1; | 930 | rcu_idle_cpu = num_online_cpus() - 1; |
| 909 | else | 931 | else |
| 910 | rcu_idle_cpu--; | 932 | rcu_idle_cpu--; |
| 911 | 933 | ||
| 912 | out: | ||
| 913 | put_online_cpus(); | 934 | put_online_cpus(); |
| 914 | free_cpumask_var(tmp_mask); | ||
| 915 | } | 935 | } |
| 916 | 936 | ||
| 917 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the | 937 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the |
| @@ -925,7 +945,8 @@ rcu_torture_shuffle(void *arg) | |||
| 925 | do { | 945 | do { |
| 926 | schedule_timeout_interruptible(shuffle_interval * HZ); | 946 | schedule_timeout_interruptible(shuffle_interval * HZ); |
| 927 | rcu_torture_shuffle_tasks(); | 947 | rcu_torture_shuffle_tasks(); |
| 928 | } while (!kthread_should_stop() && !fullstop); | 948 | rcutorture_shutdown_absorb("rcu_torture_shuffle"); |
| 949 | } while (!kthread_should_stop()); | ||
| 929 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); | 950 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); |
| 930 | return 0; | 951 | return 0; |
| 931 | } | 952 | } |
| @@ -940,10 +961,11 @@ rcu_torture_stutter(void *arg) | |||
| 940 | do { | 961 | do { |
| 941 | schedule_timeout_interruptible(stutter * HZ); | 962 | schedule_timeout_interruptible(stutter * HZ); |
| 942 | stutter_pause_test = 1; | 963 | stutter_pause_test = 1; |
| 943 | if (!kthread_should_stop() && !fullstop) | 964 | if (!kthread_should_stop()) |
| 944 | schedule_timeout_interruptible(stutter * HZ); | 965 | schedule_timeout_interruptible(stutter * HZ); |
| 945 | stutter_pause_test = 0; | 966 | stutter_pause_test = 0; |
| 946 | } while (!kthread_should_stop() && !fullstop); | 967 | rcutorture_shutdown_absorb("rcu_torture_stutter"); |
| 968 | } while (!kthread_should_stop()); | ||
| 947 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); | 969 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); |
| 948 | return 0; | 970 | return 0; |
| 949 | } | 971 | } |
| @@ -970,15 +992,16 @@ rcu_torture_cleanup(void) | |||
| 970 | int i; | 992 | int i; |
| 971 | 993 | ||
| 972 | mutex_lock(&fullstop_mutex); | 994 | mutex_lock(&fullstop_mutex); |
| 973 | if (!fullstop) { | 995 | if (fullstop == FULLSTOP_SHUTDOWN) { |
| 974 | /* If being signaled, let it happen, then exit. */ | 996 | printk(KERN_WARNING /* but going down anyway, so... */ |
| 997 | "Concurrent 'rmmod rcutorture' and shutdown illegal!\n"); | ||
| 975 | mutex_unlock(&fullstop_mutex); | 998 | mutex_unlock(&fullstop_mutex); |
| 976 | schedule_timeout_interruptible(10 * HZ); | 999 | schedule_timeout_uninterruptible(10); |
| 977 | if (cur_ops->cb_barrier != NULL) | 1000 | if (cur_ops->cb_barrier != NULL) |
| 978 | cur_ops->cb_barrier(); | 1001 | cur_ops->cb_barrier(); |
| 979 | return; | 1002 | return; |
| 980 | } | 1003 | } |
| 981 | fullstop = FULLSTOP_CLEANUP; | 1004 | fullstop = FULLSTOP_RMMOD; |
| 982 | mutex_unlock(&fullstop_mutex); | 1005 | mutex_unlock(&fullstop_mutex); |
| 983 | unregister_reboot_notifier(&rcutorture_nb); | 1006 | unregister_reboot_notifier(&rcutorture_nb); |
| 984 | if (stutter_task) { | 1007 | if (stutter_task) { |
| @@ -1078,7 +1101,7 @@ rcu_torture_init(void) | |||
| 1078 | else | 1101 | else |
| 1079 | nrealreaders = 2 * num_online_cpus(); | 1102 | nrealreaders = 2 * num_online_cpus(); |
| 1080 | rcu_torture_print_module_parms("Start of test"); | 1103 | rcu_torture_print_module_parms("Start of test"); |
| 1081 | fullstop = 0; | 1104 | fullstop = FULLSTOP_DONTSTOP; |
| 1082 | 1105 | ||
| 1083 | /* Set up the freelist. */ | 1106 | /* Set up the freelist. */ |
| 1084 | 1107 | ||
