diff options
Diffstat (limited to 'drivers/block/aoe')
-rw-r--r-- | drivers/block/aoe/aoe.h | 1 | ||||
-rw-r--r-- | drivers/block/aoe/aoechr.c | 5 | ||||
-rw-r--r-- | drivers/block/aoe/aoedev.c | 87 |
3 files changed, 74 insertions, 19 deletions
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 <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) { |