aoe: support the forgetting (flushing) of a user-specified AoE target

Users sometimes want to cause the aoe driver to forget a particular
previously discovered device when it is no longer online.  The aoetools
provide an "aoe-flush" command that users run to perform this
administrative task.  The changes below provide the support needed in the
driver.

Signed-off-by: Ed Cashin <ecashin@coraid.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
Ed Cashin 2012-12-17 16:03:30 -08:00 committed by Linus Torvalds
parent 1b8a1636ce
commit 4ba9aa7f98
1 changed files with 38 additions and 6 deletions

View File

@ -241,6 +241,30 @@ aoedev_freedev(struct aoedev *d)
kfree(d);
}
/* return whether the user asked for this particular
* device to be flushed
*/
static int
user_req(char *s, size_t slen, struct aoedev *d)
{
char *p;
size_t lim;
if (!d->gd)
return 0;
p = strrchr(d->gd->disk_name, '/');
if (!p)
p = d->gd->disk_name;
else
p += 1;
lim = sizeof(d->gd->disk_name);
lim -= p - d->gd->disk_name;
if (slen < lim)
lim = slen;
return !strncmp(s, p, lim);
}
int
aoedev_flush(const char __user *str, size_t cnt)
{
@ -249,6 +273,7 @@ aoedev_flush(const char __user *str, size_t cnt)
struct aoedev *rmd = NULL;
char buf[16];
int all = 0;
int specified = 0; /* flush a specific device */
if (cnt >= 3) {
if (cnt > sizeof buf)
@ -256,26 +281,33 @@ aoedev_flush(const char __user *str, size_t cnt)
if (copy_from_user(buf, str, cnt))
return -EFAULT;
all = !strncmp(buf, "all", 3);
if (!all)
specified = 1;
}
spin_lock_irqsave(&devlist_lock, flags);
dd = &devlist;
while ((d = *dd)) {
spin_lock(&d->lock);
if ((!all && (d->flags & DEVFL_UP))
if (specified) {
if (!user_req(buf, cnt, d))
goto skip;
} else if ((!all && (d->flags & DEVFL_UP))
|| (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
|| d->nopen
|| d->ref) {
spin_unlock(&d->lock);
dd = &d->next;
continue;
}
|| d->ref)
goto skip;
*dd = d->next;
aoedev_downdev(d);
d->flags |= DEVFL_TKILL;
spin_unlock(&d->lock);
d->next = rmd;
rmd = d;
continue;
skip:
spin_unlock(&d->lock);
dd = &d->next;
}
spin_unlock_irqrestore(&devlist_lock, flags);
while ((d = rmd)) {