diff options
Diffstat (limited to 'drivers/block/aoe/aoechr.c')
-rw-r--r-- | drivers/block/aoe/aoechr.c | 93 |
1 files changed, 53 insertions, 40 deletions
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index d5480e34cb22..e8e60e7a2e70 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* Copyright (c) 2006 Coraid, Inc. See COPYING for GPL terms. */ | 1 | /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ |
2 | /* | 2 | /* |
3 | * aoechr.c | 3 | * aoechr.c |
4 | * AoE character device driver | 4 | * AoE character device driver |
@@ -6,6 +6,7 @@ | |||
6 | 6 | ||
7 | #include <linux/hdreg.h> | 7 | #include <linux/hdreg.h> |
8 | #include <linux/blkdev.h> | 8 | #include <linux/blkdev.h> |
9 | #include <linux/delay.h> | ||
9 | #include "aoe.h" | 10 | #include "aoe.h" |
10 | 11 | ||
11 | enum { | 12 | enum { |
@@ -14,6 +15,7 @@ enum { | |||
14 | MINOR_DISCOVER, | 15 | MINOR_DISCOVER, |
15 | MINOR_INTERFACES, | 16 | MINOR_INTERFACES, |
16 | MINOR_REVALIDATE, | 17 | MINOR_REVALIDATE, |
18 | MINOR_FLUSH, | ||
17 | MSGSZ = 2048, | 19 | MSGSZ = 2048, |
18 | NMSG = 100, /* message backlog to retain */ | 20 | NMSG = 100, /* message backlog to retain */ |
19 | }; | 21 | }; |
@@ -42,6 +44,7 @@ static struct aoe_chardev chardevs[] = { | |||
42 | { MINOR_DISCOVER, "discover" }, | 44 | { MINOR_DISCOVER, "discover" }, |
43 | { MINOR_INTERFACES, "interfaces" }, | 45 | { MINOR_INTERFACES, "interfaces" }, |
44 | { MINOR_REVALIDATE, "revalidate" }, | 46 | { MINOR_REVALIDATE, "revalidate" }, |
47 | { MINOR_FLUSH, "flush" }, | ||
45 | }; | 48 | }; |
46 | 49 | ||
47 | static int | 50 | static int |
@@ -68,6 +71,7 @@ revalidate(const char __user *str, size_t size) | |||
68 | int major, minor, n; | 71 | int major, minor, n; |
69 | ulong flags; | 72 | ulong flags; |
70 | struct aoedev *d; | 73 | struct aoedev *d; |
74 | struct sk_buff *skb; | ||
71 | char buf[16]; | 75 | char buf[16]; |
72 | 76 | ||
73 | if (size >= sizeof buf) | 77 | if (size >= sizeof buf) |
@@ -85,13 +89,20 @@ revalidate(const char __user *str, size_t size) | |||
85 | d = aoedev_by_aoeaddr(major, minor); | 89 | d = aoedev_by_aoeaddr(major, minor); |
86 | if (!d) | 90 | if (!d) |
87 | return -EINVAL; | 91 | return -EINVAL; |
88 | |||
89 | spin_lock_irqsave(&d->lock, flags); | 92 | spin_lock_irqsave(&d->lock, flags); |
90 | d->flags &= ~DEVFL_MAXBCNT; | 93 | aoecmd_cleanslate(d); |
91 | d->flags |= DEVFL_PAUSE; | 94 | loop: |
95 | skb = aoecmd_ata_id(d); | ||
92 | spin_unlock_irqrestore(&d->lock, flags); | 96 | spin_unlock_irqrestore(&d->lock, flags); |
97 | /* try again if we are able to sleep a bit, | ||
98 | * otherwise give up this revalidation | ||
99 | */ | ||
100 | if (!skb && !msleep_interruptible(200)) { | ||
101 | spin_lock_irqsave(&d->lock, flags); | ||
102 | goto loop; | ||
103 | } | ||
104 | aoenet_xmit(skb); | ||
93 | aoecmd_cfg(major, minor); | 105 | aoecmd_cfg(major, minor); |
94 | |||
95 | return 0; | 106 | return 0; |
96 | } | 107 | } |
97 | 108 | ||
@@ -149,6 +160,9 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp | |||
149 | break; | 160 | break; |
150 | case MINOR_REVALIDATE: | 161 | case MINOR_REVALIDATE: |
151 | ret = revalidate(buf, cnt); | 162 | ret = revalidate(buf, cnt); |
163 | break; | ||
164 | case MINOR_FLUSH: | ||
165 | ret = aoedev_flush(buf, cnt); | ||
152 | } | 166 | } |
153 | if (ret == 0) | 167 | if (ret == 0) |
154 | ret = cnt; | 168 | ret = cnt; |
@@ -185,52 +199,51 @@ aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off) | |||
185 | ulong flags; | 199 | ulong flags; |
186 | 200 | ||
187 | n = (unsigned long) filp->private_data; | 201 | n = (unsigned long) filp->private_data; |
188 | switch (n) { | 202 | if (n != MINOR_ERR) |
189 | case MINOR_ERR: | 203 | return -EFAULT; |
190 | spin_lock_irqsave(&emsgs_lock, flags); | 204 | |
191 | loop: | 205 | spin_lock_irqsave(&emsgs_lock, flags); |
192 | em = emsgs + emsgs_head_idx; | ||
193 | if ((em->flags & EMFL_VALID) == 0) { | ||
194 | if (filp->f_flags & O_NDELAY) { | ||
195 | spin_unlock_irqrestore(&emsgs_lock, flags); | ||
196 | return -EAGAIN; | ||
197 | } | ||
198 | nblocked_emsgs_readers++; | ||
199 | 206 | ||
207 | for (;;) { | ||
208 | em = emsgs + emsgs_head_idx; | ||
209 | if ((em->flags & EMFL_VALID) != 0) | ||
210 | break; | ||
211 | if (filp->f_flags & O_NDELAY) { | ||
200 | spin_unlock_irqrestore(&emsgs_lock, flags); | 212 | spin_unlock_irqrestore(&emsgs_lock, flags); |
213 | return -EAGAIN; | ||
214 | } | ||
215 | nblocked_emsgs_readers++; | ||
201 | 216 | ||
202 | n = down_interruptible(&emsgs_sema); | 217 | spin_unlock_irqrestore(&emsgs_lock, flags); |
218 | |||
219 | n = down_interruptible(&emsgs_sema); | ||
203 | 220 | ||
204 | spin_lock_irqsave(&emsgs_lock, flags); | 221 | spin_lock_irqsave(&emsgs_lock, flags); |
205 | 222 | ||
206 | nblocked_emsgs_readers--; | 223 | nblocked_emsgs_readers--; |
207 | 224 | ||
208 | if (n) { | 225 | if (n) { |
209 | spin_unlock_irqrestore(&emsgs_lock, flags); | ||
210 | return -ERESTARTSYS; | ||
211 | } | ||
212 | goto loop; | ||
213 | } | ||
214 | if (em->len > cnt) { | ||
215 | spin_unlock_irqrestore(&emsgs_lock, flags); | 226 | spin_unlock_irqrestore(&emsgs_lock, flags); |
216 | return -EAGAIN; | 227 | return -ERESTARTSYS; |
217 | } | 228 | } |
218 | mp = em->msg; | 229 | } |
219 | len = em->len; | 230 | if (em->len > cnt) { |
220 | em->msg = NULL; | 231 | spin_unlock_irqrestore(&emsgs_lock, flags); |
221 | em->flags &= ~EMFL_VALID; | 232 | return -EAGAIN; |
233 | } | ||
234 | mp = em->msg; | ||
235 | len = em->len; | ||
236 | em->msg = NULL; | ||
237 | em->flags &= ~EMFL_VALID; | ||
222 | 238 | ||
223 | emsgs_head_idx++; | 239 | emsgs_head_idx++; |
224 | emsgs_head_idx %= ARRAY_SIZE(emsgs); | 240 | emsgs_head_idx %= ARRAY_SIZE(emsgs); |
225 | 241 | ||
226 | spin_unlock_irqrestore(&emsgs_lock, flags); | 242 | spin_unlock_irqrestore(&emsgs_lock, flags); |
227 | 243 | ||
228 | n = copy_to_user(buf, mp, len); | 244 | n = copy_to_user(buf, mp, len); |
229 | kfree(mp); | 245 | kfree(mp); |
230 | return n == 0 ? len : -EFAULT; | 246 | return n == 0 ? len : -EFAULT; |
231 | default: | ||
232 | return -EFAULT; | ||
233 | } | ||
234 | } | 247 | } |
235 | 248 | ||
236 | static const struct file_operations aoe_fops = { | 249 | static const struct file_operations aoe_fops = { |