Commit 343e9099c8152daff20e10d6269edec21da44fc0

Authored by Paul E. McKenney
Committed by Ingo Molnar
1 parent 29cbda77a6

rcu: fix rcutorture behavior during reboot

Impact: fix very rare reboot hang

Because rcutorture ignored all signals, it does not terminate in
response to the signals sent at shutdown time.  This can cause strange
failures due to its continuing to make use of kernel function too late
in the shutdown sequence.  This patch therefore adds a shutdown notifier
to rcutorture, causing it to shut down in response to a reboot or an
orderly shutdown.

Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

Showing 1 changed file with 56 additions and 10 deletions Side-by-side Diff

... ... @@ -39,6 +39,7 @@
39 39 #include <linux/moduleparam.h>
40 40 #include <linux/percpu.h>
41 41 #include <linux/notifier.h>
  42 +#include <linux/reboot.h>
42 43 #include <linux/freezer.h>
43 44 #include <linux/cpu.h>
44 45 #include <linux/delay.h>
... ... @@ -108,7 +109,6 @@
108 109 int rtort_mbtest;
109 110 };
110 111  
111   -static int fullstop = 0; /* stop generating callbacks at test end. */
112 112 static LIST_HEAD(rcu_torture_freelist);
113 113 static struct rcu_torture *rcu_torture_current = NULL;
114 114 static long rcu_torture_current_version = 0;
115 115  
... ... @@ -136,7 +136,31 @@
136 136 #endif
137 137 int rcutorture_runnable = RCUTORTURE_RUNNABLE_INIT;
138 138  
  139 +#define FULLSTOP_SIGNALED 1 /* Bail due to signal. */
  140 +#define FULLSTOP_CLEANUP 2 /* Orderly shutdown. */
  141 +static int fullstop; /* stop generating callbacks at test end. */
  142 +DEFINE_MUTEX(fullstop_mutex); /* protect fullstop transitions and */
  143 + /* spawning of kthreads. */
  144 +
139 145 /*
  146 + * Detect and respond to a signal-based shutdown.
  147 + */
  148 +static int
  149 +rcutorture_shutdown_notify(struct notifier_block *unused1,
  150 + unsigned long unused2, void *unused3)
  151 +{
  152 + if (fullstop)
  153 + return NOTIFY_DONE;
  154 + if (signal_pending(current)) {
  155 + mutex_lock(&fullstop_mutex);
  156 + if (!ACCESS_ONCE(fullstop))
  157 + fullstop = FULLSTOP_SIGNALED;
  158 + mutex_unlock(&fullstop_mutex);
  159 + }
  160 + return NOTIFY_DONE;
  161 +}
  162 +
  163 +/*
140 164 * Allocate an element from the rcu_tortures pool.
141 165 */
142 166 static struct rcu_torture *
143 167  
... ... @@ -199,11 +223,12 @@
199 223 static void
200 224 rcu_stutter_wait(void)
201 225 {
202   - while (stutter_pause_test || !rcutorture_runnable)
  226 + while ((stutter_pause_test || !rcutorture_runnable) && !fullstop) {
203 227 if (rcutorture_runnable)
204 228 schedule_timeout_interruptible(1);
205 229 else
206 230 schedule_timeout_interruptible(round_jiffies_relative(HZ));
  231 + }
207 232 }
208 233  
209 234 /*
... ... @@ -599,7 +624,7 @@
599 624 rcu_stutter_wait();
600 625 } while (!kthread_should_stop() && !fullstop);
601 626 VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping");
602   - while (!kthread_should_stop())
  627 + while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
603 628 schedule_timeout_uninterruptible(1);
604 629 return 0;
605 630 }
... ... @@ -624,7 +649,7 @@
624 649 } while (!kthread_should_stop() && !fullstop);
625 650  
626 651 VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
627   - while (!kthread_should_stop())
  652 + while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
628 653 schedule_timeout_uninterruptible(1);
629 654 return 0;
630 655 }
... ... @@ -734,7 +759,7 @@
734 759 VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping");
735 760 if (irqreader && cur_ops->irqcapable)
736 761 del_timer_sync(&t);
737   - while (!kthread_should_stop())
  762 + while (!kthread_should_stop() && fullstop != FULLSTOP_SIGNALED)
738 763 schedule_timeout_uninterruptible(1);
739 764 return 0;
740 765 }
... ... @@ -831,7 +856,7 @@
831 856 do {
832 857 schedule_timeout_interruptible(stat_interval * HZ);
833 858 rcu_torture_stats_print();
834   - } while (!kthread_should_stop());
  859 + } while (!kthread_should_stop() && !fullstop);
835 860 VERBOSE_PRINTK_STRING("rcu_torture_stats task stopping");
836 861 return 0;
837 862 }
... ... @@ -899,7 +924,7 @@
899 924 do {
900 925 schedule_timeout_interruptible(shuffle_interval * HZ);
901 926 rcu_torture_shuffle_tasks();
902   - } while (!kthread_should_stop());
  927 + } while (!kthread_should_stop() && !fullstop);
903 928 VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
904 929 return 0;
905 930 }
906 931  
... ... @@ -914,10 +939,10 @@
914 939 do {
915 940 schedule_timeout_interruptible(stutter * HZ);
916 941 stutter_pause_test = 1;
917   - if (!kthread_should_stop())
  942 + if (!kthread_should_stop() && !fullstop)
918 943 schedule_timeout_interruptible(stutter * HZ);
919 944 stutter_pause_test = 0;
920   - } while (!kthread_should_stop());
  945 + } while (!kthread_should_stop() && !fullstop);
921 946 VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping");
922 947 return 0;
923 948 }
924 949  
... ... @@ -934,12 +959,27 @@
934 959 stutter, irqreader);
935 960 }
936 961  
  962 +static struct notifier_block rcutorture_nb = {
  963 + .notifier_call = rcutorture_shutdown_notify,
  964 +};
  965 +
937 966 static void
938 967 rcu_torture_cleanup(void)
939 968 {
940 969 int i;
941 970  
942   - fullstop = 1;
  971 + mutex_lock(&fullstop_mutex);
  972 + if (!fullstop) {
  973 + /* If being signaled, let it happen, then exit. */
  974 + mutex_unlock(&fullstop_mutex);
  975 + schedule_timeout_interruptible(10 * HZ);
  976 + if (cur_ops->cb_barrier != NULL)
  977 + cur_ops->cb_barrier();
  978 + return;
  979 + }
  980 + fullstop = FULLSTOP_CLEANUP;
  981 + mutex_unlock(&fullstop_mutex);
  982 + unregister_reboot_notifier(&rcutorture_nb);
943 983 if (stutter_task) {
944 984 VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task");
945 985 kthread_stop(stutter_task);
... ... @@ -1015,6 +1055,8 @@
1015 1055 { &rcu_ops, &rcu_sync_ops, &rcu_bh_ops, &rcu_bh_sync_ops,
1016 1056 &srcu_ops, &sched_ops, &sched_ops_sync, };
1017 1057  
  1058 + mutex_lock(&fullstop_mutex);
  1059 +
1018 1060 /* Process args and tell the world that the torturer is on the job. */
1019 1061 for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
1020 1062 cur_ops = torture_ops[i];
... ... @@ -1024,6 +1066,7 @@
1024 1066 if (i == ARRAY_SIZE(torture_ops)) {
1025 1067 printk(KERN_ALERT "rcutorture: invalid torture type: \"%s\"\n",
1026 1068 torture_type);
  1069 + mutex_unlock(&fullstop_mutex);
1027 1070 return (-EINVAL);
1028 1071 }
1029 1072 if (cur_ops->init)
1030 1073  
... ... @@ -1146,9 +1189,12 @@
1146 1189 goto unwind;
1147 1190 }
1148 1191 }
  1192 + register_reboot_notifier(&rcutorture_nb);
  1193 + mutex_unlock(&fullstop_mutex);
1149 1194 return 0;
1150 1195  
1151 1196 unwind:
  1197 + mutex_unlock(&fullstop_mutex);
1152 1198 rcu_torture_cleanup();
1153 1199 return firsterr;
1154 1200 }