aoe: user can ask driver to forget previously detected devices
authorEd L. Cashin <ecashin@coraid.com>
Fri, 8 Feb 2008 12:20:03 +0000 (04:20 -0800)
committerLinus Torvalds <torvalds@woody.linux-foundation.org>
Fri, 8 Feb 2008 17:22:31 +0000 (09:22 -0800)
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>
Documentation/aoe/mkdevs.sh
Documentation/aoe/udev.txt
drivers/block/aoe/aoe.h
drivers/block/aoe/aoechr.c
drivers/block/aoe/aoedev.c

index 97374aacacb29120b5dfc8f788e4a9516584c8ed..44c0ab7024328d4229ef7609c2ae34aa4e730a1f 100644 (file)
@@ -29,6 +29,8 @@ rm -f $dir/interfaces
 mknod -m 0200 $dir/interfaces c $MAJOR 4
 rm -f $dir/revalidate
 mknod -m 0200 $dir/revalidate c $MAJOR 5
+rm -f $dir/flush
+mknod -m 0200 $dir/flush c $MAJOR 6
 
 export n_partitions
 mkshelf=`echo $0 | sed 's!mkdevs!mkshelf!'`
index 17e76c4f918e0645bb44acc9c3525c861727a780..8686e789542ed0b6f3ccce8f54b1ef794c2f7fe4 100644 (file)
@@ -20,6 +20,7 @@ SUBSYSTEM=="aoe", KERNEL=="discover", NAME="etherd/%k", GROUP="disk", MODE="0220
 SUBSYSTEM=="aoe", KERNEL=="err",       NAME="etherd/%k", GROUP="disk", MODE="0440"
 SUBSYSTEM=="aoe", KERNEL=="interfaces",        NAME="etherd/%k", GROUP="disk", MODE="0220"
 SUBSYSTEM=="aoe", KERNEL=="revalidate",        NAME="etherd/%k", GROUP="disk", MODE="0220"
+SUBSYSTEM=="aoe", KERNEL=="flush",     NAME="etherd/%k", GROUP="disk", MODE="0220"
 
 # aoe block devices     
 KERNEL=="etherd*",       NAME="%k", GROUP="disk"
index aecaac3f2e58aa50f0bf00222fee08c7526b393b..2248ab22657655b414b90f46350a88f08e637505 100644 (file)
@@ -191,6 +191,7 @@ struct aoedev *aoedev_by_aoeaddr(int maj, int min);
 struct aoedev *aoedev_by_sysminor_m(ulong sysminor);
 void aoedev_downdev(struct aoedev *d);
 int aoedev_isbusy(struct aoedev *d);
+int aoedev_flush(const char __user *str, size_t size);
 
 int aoenet_init(void);
 void aoenet_exit(void);
index f1124664c5c907174bad6a0387ff53bb39130251..1bc85aa2271f9ed5294626840ee04a3d9a9b5b01 100644 (file)
@@ -15,6 +15,7 @@ enum {
        MINOR_DISCOVER,
        MINOR_INTERFACES,
        MINOR_REVALIDATE,
+       MINOR_FLUSH,
        MSGSZ = 2048,
        NMSG = 100,             /* message backlog to retain */
 };
@@ -43,6 +44,7 @@ static struct aoe_chardev chardevs[] = {
        { MINOR_DISCOVER, "discover" },
        { MINOR_INTERFACES, "interfaces" },
        { MINOR_REVALIDATE, "revalidate" },
+       { MINOR_FLUSH, "flush" },
 };
 
 static int
@@ -158,6 +160,9 @@ aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp
                break;
        case MINOR_REVALIDATE:
                ret = revalidate(buf, cnt);
+               break;
+       case MINOR_FLUSH:
+               ret = aoedev_flush(buf, cnt);
        }
        if (ret == 0)
                ret = cnt;
index a4d625aefeaaf1baa1d8a72505d29cd1b2a8ca14..e26f6f4a28a2992203508b93ead845dfd26162e7 100644 (file)
@@ -9,6 +9,10 @@
 #include <linux/netdevice.h>
 #include "aoe.h"
 
+static void dummy_timer(ulong);
+static void aoedev_freedev(struct aoedev *);
+static void freetgt(struct aoetgt *t);
+
 static struct aoedev *devlist;
 static spinlock_t devlist_lock;
 
@@ -108,6 +112,70 @@ aoedev_downdev(struct aoedev *d)
        d->flags &= ~DEVFL_UP;
 }
 
+static void
+aoedev_freedev(struct aoedev *d)
+{
+       struct aoetgt **t, **e;
+
+       if (d->gd) {
+               aoedisk_rm_sysfs(d);
+               del_gendisk(d->gd);
+               put_disk(d->gd);
+       }
+       t = d->targets;
+       e = t + NTARGETS;
+       for (; t < e && *t; t++)
+               freetgt(*t);
+       if (d->bufpool)
+               mempool_destroy(d->bufpool);
+       kfree(d);
+}
+
+int
+aoedev_flush(const char __user *str, size_t cnt)
+{
+       ulong flags;
+       struct aoedev *d, **dd;
+       struct aoedev *rmd = NULL;
+       char buf[16];
+       int all = 0;
+
+       if (cnt >= 3) {
+               if (cnt > sizeof buf)
+                       cnt = sizeof buf;
+               if (copy_from_user(buf, str, cnt))
+                       return -EFAULT;
+               all = !strncmp(buf, "all", 3);
+       }
+
+       flush_scheduled_work();
+       spin_lock_irqsave(&devlist_lock, flags);
+       dd = &devlist;
+       while ((d = *dd)) {
+               spin_lock(&d->lock);
+               if ((!all && (d->flags & DEVFL_UP))
+               || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
+               || d->nopen) {
+                       spin_unlock(&d->lock);
+                       dd = &d->next;
+                       continue;
+               }
+               *dd = d->next;
+               aoedev_downdev(d);
+               d->flags |= DEVFL_TKILL;
+               spin_unlock(&d->lock);
+               d->next = rmd;
+               rmd = d;
+       }
+       spin_unlock_irqrestore(&devlist_lock, flags);
+       while ((d = rmd)) {
+               rmd = d->next;
+               del_timer_sync(&d->timer);
+               aoedev_freedev(d);      /* must be able to sleep */
+       }
+       return 0;
+}
+
 /* find it or malloc it */
 struct aoedev *
 aoedev_by_sysminor_m(ulong sysminor)
@@ -161,25 +229,6 @@ freetgt(struct aoetgt *t)
        kfree(t);
 }
 
-static void
-aoedev_freedev(struct aoedev *d)
-{
-       struct aoetgt **t, **e;
-
-       if (d->gd) {
-               aoedisk_rm_sysfs(d);
-               del_gendisk(d->gd);
-               put_disk(d->gd);
-       }
-       t = d->targets;
-       e = t + NTARGETS;
-       for (; t < e && *t; t++)
-               freetgt(*t);
-       if (d->bufpool)
-               mempool_destroy(d->bufpool);
-       kfree(d);
-}
-
 void
 aoedev_exit(void)
 {