aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/block/aoe/aoedev.c
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/aoe/aoedev.c
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/aoe/aoedev.c')
-rw-r--r--drivers/block/aoe/aoedev.c87
1 files changed, 68 insertions, 19 deletions
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{