aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block
diff options
context:
space:
mode:
authorEd L. Cashin <ecashin@coraid.com>2008-02-08 07:20:03 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2008-02-08 12:22:31 -0500
commit262bf54144ebcb78cd0d057d2705dc5fb7bba7ac (patch)
tree6a995fead6fa9638e02fc6e3928fe0a8612f073a /drivers/block
parentcf446f0dbafb5428a551da1c0df8f56316831df8 (diff)
aoe: user can ask driver to forget previously detected devices
When an AoE device is detected, the kernel is informed, and a new block device is created. If the device is unused, the block device corresponding to remote device that is no longer available may be removed from the system by telling the aoe driver to "flush" its list of devices. Without this patch, software like GPFS and LVM may attempt to read from AoE devices that were discovered earlier but are no longer present, blocking until the I/O attempt times out. Signed-off-by: Ed L. Cashin <ecashin@coraid.com> Cc: Greg KH <greg@kroah.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/block')
-rw-r--r--drivers/block/aoe/aoe.h1
-rw-r--r--drivers/block/aoe/aoechr.c5
-rw-r--r--drivers/block/aoe/aoedev.c87
3 files changed, 74 insertions, 19 deletions
diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h
index aecaac3f2e58..2248ab226576 100644
--- a/drivers/block/aoe/aoe.h
+++ b/drivers/block/aoe/aoe.h
@@ -191,6 +191,7 @@ struct aoedev *aoedev_by_aoeaddr(int maj, int min);
191struct aoedev *aoedev_by_sysminor_m(ulong sysminor); 191struct aoedev *aoedev_by_sysminor_m(ulong sysminor);
192void aoedev_downdev(struct aoedev *d); 192void aoedev_downdev(struct aoedev *d);
193int aoedev_isbusy(struct aoedev *d); 193int aoedev_isbusy(struct aoedev *d);
194int aoedev_flush(const char __user *str, size_t size);
194 195
195int aoenet_init(void); 196int aoenet_init(void);
196void aoenet_exit(void); 197void aoenet_exit(void);
diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c
index f1124664c5c9..1bc85aa2271f 100644
--- a/drivers/block/aoe/aoechr.c
+++ b/drivers/block/aoe/aoechr.c
@@ -15,6 +15,7 @@ enum {
15 MINOR_DISCOVER, 15 MINOR_DISCOVER,
16 MINOR_INTERFACES, 16 MINOR_INTERFACES,
17 MINOR_REVALIDATE, 17 MINOR_REVALIDATE,
18 MINOR_FLUSH,
18 MSGSZ = 2048, 19 MSGSZ = 2048,
19 NMSG = 100, /* message backlog to retain */ 20 NMSG = 100, /* message backlog to retain */
20}; 21};
@@ -43,6 +44,7 @@ static struct aoe_chardev chardevs[] = {
43 { MINOR_DISCOVER, "discover" }, 44 { MINOR_DISCOVER, "discover" },
44 { MINOR_INTERFACES, "interfaces" }, 45 { MINOR_INTERFACES, "interfaces" },
45 { MINOR_REVALIDATE, "revalidate" }, 46 { MINOR_REVALIDATE, "revalidate" },
47 { MINOR_FLUSH, "flush" },
46}; 48};
47 49
48static int 50static int
@@ -158,6 +160,9 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
158 break; 160 break;
159 case MINOR_REVALIDATE: 161 case MINOR_REVALIDATE:
160 ret = revalidate(buf, cnt); 162 ret = revalidate(buf, cnt);
163 break;
164 case MINOR_FLUSH:
165 ret = aoedev_flush(buf, cnt);
161 } 166 }
162 if (ret == 0) 167 if (ret == 0)
163 ret = cnt; 168 ret = cnt;
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c
index a4d625aefeaa..e26f6f4a28a2 100644
--- a/drivers/block/aoe/aoedev.c
+++ b/drivers/block/aoe/aoedev.c
@@ -9,6 +9,10 @@
9#include <linux/netdevice.h> 9#include <linux/netdevice.h>
10#include "aoe.h" 10#include "aoe.h"
11 11
12static void dummy_timer(ulong);
13static void aoedev_freedev(struct aoedev *);
14static void freetgt(struct aoetgt *t);
15
12static struct aoedev *devlist; 16static struct aoedev *devlist;
13static spinlock_t devlist_lock; 17static spinlock_t devlist_lock;
14 18
@@ -108,6 +112,70 @@ aoedev_downdev(struct aoedev *d)
108 d->flags &= ~DEVFL_UP; 112 d->flags &= ~DEVFL_UP;
109} 113}
110 114
115static void
116aoedev_freedev(struct aoedev *d)
117{
118 struct aoetgt **t, **e;
119
120 if (d->gd) {
121 aoedisk_rm_sysfs(d);
122 del_gendisk(d->gd);
123 put_disk(d->gd);
124 }
125 t = d->targets;
126 e = t + NTARGETS;
127 for (; t < e && *t; t++)
128 freetgt(*t);
129 if (d->bufpool)
130 mempool_destroy(d->bufpool);
131 kfree(d);
132}
133
134int
135aoedev_flush(const char __user *str, size_t cnt)
136{
137 ulong flags;
138 struct aoedev *d, **dd;
139 struct aoedev *rmd = NULL;
140 char buf[16];
141 int all = 0;
142
143 if (cnt >= 3) {
144 if (cnt > sizeof buf)
145 cnt = sizeof buf;
146 if (copy_from_user(buf, str, cnt))
147 return -EFAULT;
148 all = !strncmp(buf, "all", 3);
149 }
150
151 flush_scheduled_work();
152 spin_lock_irqsave(&devlist_lock, flags);
153 dd = &devlist;
154 while ((d = *dd)) {
155 spin_lock(&d->lock);
156 if ((!all && (d->flags & DEVFL_UP))
157 || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
158 || d->nopen) {
159 spin_unlock(&d->lock);
160 dd = &d->next;
161 continue;
162 }
163 *dd = d->next;
164 aoedev_downdev(d);
165 d->flags |= DEVFL_TKILL;
166 spin_unlock(&d->lock);
167 d->next = rmd;
168 rmd = d;
169 }
170 spin_unlock_irqrestore(&devlist_lock, flags);
171 while ((d = rmd)) {
172 rmd = d->next;
173 del_timer_sync(&d->timer);
174 aoedev_freedev(d); /* must be able to sleep */
175 }
176 return 0;
177}
178
111/* find it or malloc it */ 179/* find it or malloc it */
112struct aoedev * 180struct aoedev *
113aoedev_by_sysminor_m(ulong sysminor) 181aoedev_by_sysminor_m(ulong sysminor)
@@ -161,25 +229,6 @@ freetgt(struct aoetgt *t)
161 kfree(t); 229 kfree(t);
162} 230}
163 231
164static void
165aoedev_freedev(struct aoedev *d)
166{
167 struct aoetgt **t, **e;
168
169 if (d->gd) {
170 aoedisk_rm_sysfs(d);
171 del_gendisk(d->gd);
172 put_disk(d->gd);
173 }
174 t = d->targets;
175 e = t + NTARGETS;
176 for (; t < e && *t; t++)
177 freetgt(*t);
178 if (d->bufpool)
179 mempool_destroy(d->bufpool);
180 kfree(d);
181}
182
183void 232void
184aoedev_exit(void) 233aoedev_exit(void)
185{ 234{