diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:38:38 -0500 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2008-12-25 07:38:56 -0500 |
commit | 0b3016b781abeabc502042c942cbc611e31250c7 (patch) | |
tree | a4aead52e4ea230a529e2c9d0899f5fe32f41408 /arch/s390/kernel | |
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/s390/kernel')
-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 6e09bc285ba0..496528561248 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -467,6 +467,7 @@ static struct timer_list etr_timer; | |||
467 | 467 | ||
468 | static void etr_timeout(unsigned long dummy); | 468 | static void etr_timeout(unsigned long dummy); |
469 | static void etr_work_fn(struct work_struct *work); | 469 | static void etr_work_fn(struct work_struct *work); |
470 | static DEFINE_MUTEX(etr_work_mutex); | ||
470 | static DECLARE_WORK(etr_work, etr_work_fn); | 471 | static DECLARE_WORK(etr_work, etr_work_fn); |
471 | 472 | ||
472 | /* | 473 | /* |
@@ -976,6 +977,9 @@ static void etr_work_fn(struct work_struct *work) | |||
976 | struct etr_aib aib; | 977 | struct etr_aib aib; |
977 | int sync_port; | 978 | int sync_port; |
978 | 979 | ||
980 | /* prevent multiple execution. */ | ||
981 | mutex_lock(&etr_work_mutex); | ||
982 | |||
979 | /* Create working copy of etr_eacr. */ | 983 | /* Create working copy of etr_eacr. */ |
980 | eacr = etr_eacr; | 984 | eacr = etr_eacr; |
981 | 985 | ||
@@ -991,7 +995,7 @@ static void etr_work_fn(struct work_struct *work) | |||
991 | del_timer_sync(&etr_timer); | 995 | del_timer_sync(&etr_timer); |
992 | etr_update_eacr(eacr); | 996 | etr_update_eacr(eacr); |
993 | clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); | 997 | clear_bit(CLOCK_SYNC_ETR, &clock_sync_flags); |
994 | return; | 998 | goto out_unlock; |
995 | } | 999 | } |
996 | 1000 | ||
997 | /* Store aib to get the current ETR status word. */ | 1001 | /* Store aib to get the current ETR status word. */ |
@@ -1078,7 +1082,7 @@ static void etr_work_fn(struct work_struct *work) | |||
1078 | eacr.es || sync_port < 0) { | 1082 | eacr.es || sync_port < 0) { |
1079 | etr_update_eacr(eacr); | 1083 | etr_update_eacr(eacr); |
1080 | etr_set_tolec_timeout(now); | 1084 | etr_set_tolec_timeout(now); |
1081 | return; | 1085 | goto out_unlock; |
1082 | } | 1086 | } |
1083 | 1087 | ||
1084 | /* | 1088 | /* |
@@ -1106,6 +1110,8 @@ static void etr_work_fn(struct work_struct *work) | |||
1106 | etr_set_sync_timeout(); | 1110 | etr_set_sync_timeout(); |
1107 | } else | 1111 | } else |
1108 | etr_set_tolec_timeout(now); | 1112 | etr_set_tolec_timeout(now); |
1113 | out_unlock: | ||
1114 | mutex_unlock(&etr_work_mutex); | ||
1109 | } | 1115 | } |
1110 | 1116 | ||
1111 | /* | 1117 | /* |
@@ -1394,6 +1400,7 @@ static struct stp_sstpi stp_info; | |||
1394 | static void *stp_page; | 1400 | static void *stp_page; |
1395 | 1401 | ||
1396 | static void stp_work_fn(struct work_struct *work); | 1402 | static void stp_work_fn(struct work_struct *work); |
1403 | static DEFINE_MUTEX(stp_work_mutex); | ||
1397 | static DECLARE_WORK(stp_work, stp_work_fn); | 1404 | static DECLARE_WORK(stp_work, stp_work_fn); |
1398 | 1405 | ||
1399 | static int __init early_parse_stp(char *p) | 1406 | static int __init early_parse_stp(char *p) |
@@ -1542,24 +1549,30 @@ static void stp_work_fn(struct work_struct *work) | |||
1542 | struct clock_sync_data stp_sync; | 1549 | struct clock_sync_data stp_sync; |
1543 | int rc; | 1550 | int rc; |
1544 | 1551 | ||
1552 | /* prevent multiple execution. */ | ||
1553 | mutex_lock(&stp_work_mutex); | ||
1554 | |||
1545 | if (!stp_online) { | 1555 | if (!stp_online) { |
1546 | chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); | 1556 | chsc_sstpc(stp_page, STP_OP_CTRL, 0x0000); |
1547 | return; | 1557 | goto out_unlock; |
1548 | } | 1558 | } |
1549 | 1559 | ||
1550 | rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); | 1560 | rc = chsc_sstpc(stp_page, STP_OP_CTRL, 0xb0e0); |
1551 | if (rc) | 1561 | if (rc) |
1552 | return; | 1562 | goto out_unlock; |
1553 | 1563 | ||
1554 | rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); | 1564 | rc = chsc_sstpi(stp_page, &stp_info, sizeof(struct stp_sstpi)); |
1555 | if (rc || stp_info.c == 0) | 1565 | if (rc || stp_info.c == 0) |
1556 | return; | 1566 | goto out_unlock; |
1557 | 1567 | ||
1558 | memset(&stp_sync, 0, sizeof(stp_sync)); | 1568 | memset(&stp_sync, 0, sizeof(stp_sync)); |
1559 | get_online_cpus(); | 1569 | get_online_cpus(); |
1560 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); | 1570 | atomic_set(&stp_sync.cpus, num_online_cpus() - 1); |
1561 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); | 1571 | stop_machine(stp_sync_clock, &stp_sync, &cpu_online_map); |
1562 | put_online_cpus(); | 1572 | put_online_cpus(); |
1573 | |||
1574 | out_unlock: | ||
1575 | mutex_unlock(&stp_work_mutex); | ||
1563 | } | 1576 | } |
1564 | 1577 | ||
1565 | /* | 1578 | /* |