aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/s390/cio/crw.c
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2009-03-26 10:24:09 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2009-03-26 10:24:13 -0400
commit98c1c6825247c71e3d8a9a5439ba21fce7563014 (patch)
tree6e2311aff5eefba2aaad2f09b1c11b7b2b0eceae /drivers/s390/cio/crw.c
parente74fe0cec92439115630b51195444b89b910800a (diff)
[S390] cio/crw: add/fix locking
The crw_unregister_handler uses xchg + synchronize_sched when unregistering a crw_handler. This doesn't protect crw_collect_info to potentially jump to NULL since it has unlocked code like this: if (crw_handlers[i]) crw_handlers[i](NULL, NULL, 1); So add a mutex which protects the crw handler array for changes. Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'drivers/s390/cio/crw.c')
-rw-r--r--drivers/s390/cio/crw.c32
1 files changed, 23 insertions, 9 deletions
diff --git a/drivers/s390/cio/crw.c b/drivers/s390/cio/crw.c
index 508f88f6420c..d157665d0e76 100644
--- a/drivers/s390/cio/crw.c
+++ b/drivers/s390/cio/crw.c
@@ -9,11 +9,13 @@
9 */ 9 */
10 10
11#include <linux/semaphore.h> 11#include <linux/semaphore.h>
12#include <linux/mutex.h>
12#include <linux/kthread.h> 13#include <linux/kthread.h>
13#include <linux/init.h> 14#include <linux/init.h>
14#include <asm/crw.h> 15#include <asm/crw.h>
15 16
16static struct semaphore crw_semaphore; 17static struct semaphore crw_semaphore;
18static DEFINE_MUTEX(crw_handler_mutex);
17static crw_handler_t crw_handlers[NR_RSCS]; 19static crw_handler_t crw_handlers[NR_RSCS];
18 20
19/** 21/**
@@ -25,11 +27,17 @@ static crw_handler_t crw_handlers[NR_RSCS];
25 */ 27 */
26int crw_register_handler(int rsc, crw_handler_t handler) 28int crw_register_handler(int rsc, crw_handler_t handler)
27{ 29{
30 int rc = 0;
31
28 if ((rsc < 0) || (rsc >= NR_RSCS)) 32 if ((rsc < 0) || (rsc >= NR_RSCS))
29 return -EINVAL; 33 return -EINVAL;
30 if (!cmpxchg(&crw_handlers[rsc], NULL, handler)) 34 mutex_lock(&crw_handler_mutex);
31 return 0; 35 if (crw_handlers[rsc])
32 return -EBUSY; 36 rc = -EBUSY;
37 else
38 crw_handlers[rsc] = handler;
39 mutex_unlock(&crw_handler_mutex);
40 return rc;
33} 41}
34 42
35/** 43/**
@@ -40,8 +48,9 @@ void crw_unregister_handler(int rsc)
40{ 48{
41 if ((rsc < 0) || (rsc >= NR_RSCS)) 49 if ((rsc < 0) || (rsc >= NR_RSCS))
42 return; 50 return;
43 xchg(&crw_handlers[rsc], NULL); 51 mutex_lock(&crw_handler_mutex);
44 synchronize_sched(); 52 crw_handlers[rsc] = NULL;
53 mutex_unlock(&crw_handler_mutex);
45} 54}
46 55
47/* 56/*
@@ -58,6 +67,8 @@ repeat:
58 ignore = down_interruptible(&crw_semaphore); 67 ignore = down_interruptible(&crw_semaphore);
59 chain = 0; 68 chain = 0;
60 while (1) { 69 while (1) {
70 crw_handler_t handler;
71
61 if (unlikely(chain > 1)) { 72 if (unlikely(chain > 1)) {
62 struct crw tmp_crw; 73 struct crw tmp_crw;
63 74
@@ -90,10 +101,12 @@ repeat:
90 int i; 101 int i;
91 102
92 pr_debug("%s: crw overflow detected!\n", __func__); 103 pr_debug("%s: crw overflow detected!\n", __func__);
104 mutex_lock(&crw_handler_mutex);
93 for (i = 0; i < NR_RSCS; i++) { 105 for (i = 0; i < NR_RSCS; i++) {
94 if (crw_handlers[i]) 106 if (crw_handlers[i])
95 crw_handlers[i](NULL, NULL, 1); 107 crw_handlers[i](NULL, NULL, 1);
96 } 108 }
109 mutex_unlock(&crw_handler_mutex);
97 chain = 0; 110 chain = 0;
98 continue; 111 continue;
99 } 112 }
@@ -101,10 +114,11 @@ repeat:
101 chain++; 114 chain++;
102 continue; 115 continue;
103 } 116 }
104 if (crw_handlers[crw[chain].rsc]) 117 mutex_lock(&crw_handler_mutex);
105 crw_handlers[crw[chain].rsc](&crw[0], 118 handler = crw_handlers[crw[chain].rsc];
106 chain ? &crw[1] : NULL, 119 if (handler)
107 0); 120 handler(&crw[0], chain ? &crw[1] : NULL, 0);
121 mutex_unlock(&crw_handler_mutex);
108 /* chain is always 0 or 1 here. */ 122 /* chain is always 0 or 1 here. */
109 chain = crw[chain].chn ? chain + 1 : 0; 123 chain = crw[chain].chn ? chain + 1 : 0;
110 } 124 }