Commit 0b3016b7 authored by Martin Schwidefsky's avatar Martin Schwidefsky

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent 750887de
...@@ -467,6 +467,7 @@ static struct timer_list etr_timer; ...@@ -467,6 +467,7 @@ static struct timer_list etr_timer;
static void etr_timeout(unsigned long dummy); static void etr_timeout(unsigned long dummy);
static void etr_work_fn(struct work_struct *work); static void etr_work_fn(struct work_struct *work);
static DEFINE_MUTEX(etr_work_mutex);
static DECLARE_WORK(etr_work, etr_work_fn); static DECLARE_WORK(etr_work, etr_work_fn);
/* /*
...@@ -976,6 +977,9 @@ static void etr_work_fn(struct work_struct *work) ...@@ -976,6 +977,9 @@ static void etr_work_fn(struct work_struct *work)
struct etr_aib aib; struct etr_aib aib;
int sync_port; int sync_port;
/* prevent multiple execution. */
mutex_lock(&etr_work_mutex);
/* Create working copy of etr_eacr. */ /* Create working copy of etr_eacr. */
eacr = etr_eacr; eacr = etr_eacr;
...@@ -991,7 +995,7 @@ static void etr_work_fn(struct work_struct *work) ...@@ -991,7 +995,7 @@ static void etr_work_fn(struct work_struct *work)
del_timer_sync(&etr_timer); del_timer_sync(&etr_timer);
etr_update_eacr(eacr); etr_update_eacr(eacr);
clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags);
return; goto out_unlock;
} }
/* Store aib to get the current ETR status word. */ /* Store aib to get the current ETR status word. */
...@@ -1078,7 +1082,7 @@ static void etr_work_fn(struct work_struct *work) ...@@ -1078,7 +1082,7 @@ static void etr_work_fn(struct work_struct *work)
eacr.es || sync_port < 0) { eacr.es || sync_port < 0) {
etr_update_eacr(eacr); etr_update_eacr(eacr);
etr_set_tolec_timeout(now); etr_set_tolec_timeout(now);
return; goto out_unlock;
} }
/* /*
...@@ -1106,6 +1110,8 @@ static void etr_work_fn(struct work_struct *work) ...@@ -1106,6 +1110,8 @@ static void etr_work_fn(struct work_struct *work)
etr_set_sync_timeout(); etr_set_sync_timeout();
} else } else
etr_set_tolec_timeout(now); etr_set_tolec_timeout(now);
out_unlock:
mutex_unlock(&etr_work_mutex);
} }
/* /*
...@@ -1394,6 +1400,7 @@ static struct stp_sstpi stp_info; ...@@ -1394,6 +1400,7 @@ static struct stp_sstpi stp_info;
static void *stp_page; static void *stp_page;
static void stp_work_fn(struct work_struct *work); static void stp_work_fn(struct work_struct *work);
static DEFINE_MUTEX(stp_work_mutex);
static DECLARE_WORK(stp_work, stp_work_fn); static DECLARE_WORK(stp_work, stp_work_fn);
static int __init early_parse_stp(char *p) static int __init early_parse_stp(char *p)
...@@ -1542,24 +1549,30 @@ static void stp_work_fn(struct work_struct *work) ...@@ -1542,24 +1549,30 @@ static void stp_work_fn(struct work_struct *work)
struct clock_sync_data stp_sync; struct clock_sync_data stp_sync;
int rc; int rc;
/* prevent multiple execution. */
mutex_lock(&stp_work_mutex);
if (!stp_online) { if (!stp_online) {
chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000);
return; goto out_unlock;
} }
rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0);
if (rc) if (rc)
return; goto out_unlock;
rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi));
if (rc || stp_info.c == 0) if (rc || stp_info.c == 0)
return; goto out_unlock;
memset(&stp_sync, 0, sizeof(stp_sync)); memset(&stp_sync, 0, sizeof(stp_sync));
get_online_cpus(); get_online_cpus();
atomic_set(&stp_sync.cpus, num_online_cpus() - 1); atomic_set(&stp_sync.cpus, num_online_cpus() - 1);
stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map);
put_online_cpus(); put_online_cpus();
out_unlock:
mutex_unlock(&stp_work_mutex);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment