1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: stp/etr: serialize work.
5 Symptom: Oops when setting stp online.
6 Problem: The stp/etr work function dispatched with schedule_work()
7 can be run twice on different cpus because run_workqueue
8 clears the WORK_STRUCT_PENDING bit before it executes the
10 Solution: Serialize the etr and stp work functions with a mutex.
12 Acked-by: John Jolly <jjolly@suse.de>
14 arch/s390/kernel/time.c | 23 ++++++++++++++++++-----
15 1 file changed, 18 insertions(+), 5 deletions(-)
17 Index: linux-2.6.27/arch/s390/kernel/time.c
18 ===================================================================
19 --- linux-2.6.27.orig/arch/s390/kernel/time.c
20 +++ linux-2.6.27/arch/s390/kernel/time.c
21 @@ -441,6 +441,7 @@ static struct timer_list etr_timer;
23 static void etr_timeout(unsigned long dummy);
24 static void etr_work_fn(struct work_struct *work);
25 +static DEFINE_MUTEX(etr_work_mutex);
26 static DECLARE_WORK(etr_work, etr_work_fn);
29 @@ -950,6 +951,9 @@ static void etr_work_fn(struct work_stru
33 + /* prevent multiple execution. */
34 + mutex_lock(&etr_work_mutex);
36 /* Create working copy of etr_eacr. */
39 @@ -965,7 +969,7 @@ static void etr_work_fn(struct work_stru
40 del_timer_sync(&etr_timer);
41 etr_update_eacr(eacr);
42 clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
47 /* Store aib to get the current ETR status word. */
48 @@ -1052,7 +1056,7 @@ static void etr_work_fn(struct work_stru
49 eacr.es || sync_port < 0) {
50 etr_update_eacr(eacr);
51 etr_set_tolec_timeout(now);
57 @@ -1080,6 +1084,8 @@ static void etr_work_fn(struct work_stru
58 etr_set_sync_timeout();
60 etr_set_tolec_timeout(now);
62 + mutex_unlock(&etr_work_mutex);
66 @@ -1368,6 +1374,7 @@ static struct stp_sstpi stp_info;
67 static void *stp_page;
69 static void stp_work_fn(struct work_struct *work);
70 +static DEFINE_MUTEX(stp_work_mutex);
71 static DECLARE_WORK(stp_work, stp_work_fn);
73 static int __init early_parse_stp(char *p)
74 @@ -1517,24 +1524,30 @@ static void stp_work_fn(struct work_stru
75 struct clock_sync_data stp_sync;
78 + /* prevent multiple execution. */
79 + mutex_lock(&stp_work_mutex);
82 chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
87 rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
92 rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
93 if (rc || stp_info.c == 0)
97 memset(&stp_sync, 0, sizeof(stp_sync));
99 atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
100 stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
104 + mutex_unlock(&stp_work_mutex);