diff --git a/Documentation/aoe/mkdevs.sh b/Documentation/aoe/mkdevs.sh index 97374aacacb..44c0ab70243 100644 --- a/Documentation/aoe/mkdevs.sh +++ b/Documentation/aoe/mkdevs.sh @@ -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!'` diff --git a/Documentation/aoe/udev.txt b/Documentation/aoe/udev.txt index 17e76c4f918..8686e789542 100644 --- a/Documentation/aoe/udev.txt +++ b/Documentation/aoe/udev.txt @@ -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" diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index aecaac3f2e5..2248ab22657 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); 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); diff --git a/drivers/block/aoe/aoechr.c b/drivers/block/aoe/aoechr.c index f1124664c5c..1bc85aa2271 100644 --- a/drivers/block/aoe/aoechr.c +++ b/drivers/block/aoe/aoechr.c @@ -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; diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c index a4d625aefea..e26f6f4a28a 100644 --- a/drivers/block/aoe/aoedev.c +++ b/drivers/block/aoe/aoedev.c @@ -9,6 +9,10 @@ #include #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) {