]>
Commit | Line | Data |
---|---|---|
2cb7cef9 BS |
1 | From: Gerald Schaefer <geraldsc@de.ibm.com> |
2 | Subject: stp/etr: serialize work. | |
3 | References: bnc#450096 | |
4 | ||
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 | |
9 | function. | |
10 | Solution: Serialize the etr and stp work functions with a mutex. | |
11 | ||
12 | Acked-by: John Jolly <jjolly@suse.de> | |
13 | --- | |
14 | arch/s390/kernel/time.c | 23 ++++++++++++++++++----- | |
15 | 1 file changed, 18 insertions(+), 5 deletions(-) | |
16 | ||
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; | |
22 | ||
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); | |
27 | ||
28 | /* | |
29 | @@ -950,6 +951,9 @@ static void etr_work_fn(struct work_stru | |
30 | struct etr_aib aib; | |
31 | int sync_port; | |
32 | ||
33 | + /* prevent multiple execution. */ | |
34 | + mutex_lock(&etr_work_mutex); | |
35 | + | |
36 | /* Create working copy of etr_eacr. */ | |
37 | eacr = etr_eacr; | |
38 | ||
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); | |
43 | - return; | |
44 | + goto out_unlock; | |
45 | } | |
46 | ||
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); | |
52 | - return; | |
53 | + goto out_unlock; | |
54 | } | |
55 | ||
56 | /* | |
57 | @@ -1080,6 +1084,8 @@ static void etr_work_fn(struct work_stru | |
58 | etr_set_sync_timeout(); | |
59 | } else | |
60 | etr_set_tolec_timeout(now); | |
61 | +out_unlock: | |
62 | + mutex_unlock(&etr_work_mutex); | |
63 | } | |
64 | ||
65 | /* | |
66 | @@ -1368,6 +1374,7 @@ static struct stp_sstpi stp_info; | |
67 | static void *stp_page; | |
68 | ||
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); | |
72 | ||
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; | |
76 | int rc; | |
77 | ||
78 | + /* prevent multiple execution. */ | |
79 | + mutex_lock(&stp_work_mutex); | |
80 | + | |
81 | if (!stp_online) { | |
82 | chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); | |
83 | - return; | |
84 | + goto out_unlock; | |
85 | } | |
86 | ||
87 | rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); | |
88 | if (rc) | |
89 | - return; | |
90 | + goto out_unlock; | |
91 | ||
92 | rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); | |
93 | if (rc || stp_info.c == 0) | |
94 | - return; | |
95 | + goto out_unlock; | |
96 | ||
97 | memset(&stp_sync, 0, sizeof(stp_sync)); | |
98 | get_online_cpus(); | |
99 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); | |
100 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); | |
101 | put_online_cpus(); | |
102 | + | |
103 | +out_unlock: | |
104 | + mutex_unlock(&stp_work_mutex); | |
105 | } | |
106 | ||
107 | /* |