diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 13:38:38 +0100 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 13:38:56 +0100 |
commit | 0b3016b781abeabc502042c942cbc611e31250c7 (patch) | |
tree | a4aead52e4ea230a529e2c9d0899f5fe32f41408 /arch | |
parent | 750887dedc088d28198b170bcae83695247797d1 (diff) |
[S390] serialize stp/etr work
The work function dispatched with schedule_work() can be run twice
on different cpus because run_workqueue clears the WORK_STRUCT_PENDING
bit and then executes the function. Another cpu can call schedule_work()
again and run the work function a second time before the first call
is completed. This patch serialized the etr and stp work function with
a mutex.
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/kernel/time.c | 23 |
1 files changed, 18 insertions, 5 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 6e09bc285ba..49652856124 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c @@ -467,6 +467,7 @@ static struct timer_list etr_timer; static void etr_timeout(unsigned long dummy); static void etr_work_fn(struct work_struct *work); +static DEFINE_MUTEX(etr_work_mutex); static DECLARE_WORK(etr_work, etr_work_fn); /* @@ -976,6 +977,9 @@ static void etr_work_fn(struct work_struct *work) struct etr_aib aib; int sync_port; + /* prevent multiple execution. */ + mutex_lock(&etr_work_mutex); + /* Create working copy of etr_eacr. */ eacr = etr_eacr; @@ -991,7 +995,7 @@ static void etr_work_fn(struct work_struct *work) del_timer_sync(&etr_timer); etr_update_eacr(eacr); clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); - return; + goto out_unlock; } /* Store aib to get the current ETR status word. */ @@ -1078,7 +1082,7 @@ static void etr_work_fn(struct work_struct *work) eacr.es || sync_port < 0) { etr_update_eacr(eacr); etr_set_tolec_timeout(now); - return; + goto out_unlock; } /* @@ -1106,6 +1110,8 @@ static void etr_work_fn(struct work_struct *work) etr_set_sync_timeout(); } else etr_set_tolec_timeout(now); +out_unlock: + mutex_unlock(&etr_work_mutex); } /* @@ -1394,6 +1400,7 @@ static struct stp_sstpi stp_info; static void *stp_page; static void stp_work_fn(struct work_struct *work); +static DEFINE_MUTEX(stp_work_mutex); static DECLARE_WORK(stp_work, stp_work_fn); static int __init early_parse_stp(char *p) @@ -1542,24 +1549,30 @@ static void stp_work_fn(struct work_struct *work) struct clock_sync_data stp_sync; int rc; + /* prevent multiple execution. */ + mutex_lock(&stp_work_mutex); + if (!stp_online) { chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); - return; + goto out_unlock; } rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); if (rc) - return; + goto out_unlock; rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); if (rc || stp_info.c == 0) - return; + goto out_unlock; memset(&stp_sync, 0, sizeof(stp_sync)); get_online_cpus(); atomic_set(&stp_sync.cpus, num_online_cpus() - 1); stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); put_online_cpus(); + +out_unlock: + mutex_unlock(&stp_work_mutex); } /* |