diff options
author | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
---|---|---|
committer | Srikant Patnaik | 2015-01-11 12:28:04 +0530 |
commit | 871480933a1c28f8a9fed4c4d34d06c439a7a422 (patch) | |
tree | 8718f573808810c2a1e8cb8fb6ac469093ca2784 /drivers/block/aoe/aoedev.c | |
parent | 9d40ac5867b9aefe0722bc1f110b965ff294d30d (diff) | |
download | FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.gz FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.tar.bz2 FOSSEE-netbook-kernel-source-871480933a1c28f8a9fed4c4d34d06c439a7a422.zip |
Moved, renamed, and deleted files
The original directory structure was scattered and unorganized.
Changes are basically to make it look like kernel structure.
Diffstat (limited to 'drivers/block/aoe/aoedev.c')
-rw-r--r-- | drivers/block/aoe/aoedev.c | 277 |
1 files changed, 277 insertions, 0 deletions
diff --git a/drivers/block/aoe/aoedev.c b/drivers/block/aoe/aoedev.c new file mode 100644 index 00000000..6b5110a4 --- /dev/null +++ b/drivers/block/aoe/aoedev.c @@ -0,0 +1,277 @@ +/* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */ +/* + * aoedev.c + * AoE device utility functions; maintains device list. + */ + +#include <linux/hdreg.h> +#include <linux/blkdev.h> +#include <linux/netdevice.h> +#include <linux/delay.h> +#include <linux/slab.h> +#include "aoe.h" + +static void dummy_timer(ulong); +static void aoedev_freedev(struct aoedev *); +static void freetgt(struct aoedev *d, struct aoetgt *t); +static void skbpoolfree(struct aoedev *d); + +static struct aoedev *devlist; +static DEFINE_SPINLOCK(devlist_lock); + +struct aoedev * +aoedev_by_aoeaddr(int maj, int min) +{ + struct aoedev *d; + ulong flags; + + spin_lock_irqsave(&devlist_lock, flags); + + for (d=devlist; d; d=d->next) + if (d->aoemajor == maj && d->aoeminor == min) + break; + + spin_unlock_irqrestore(&devlist_lock, flags); + return d; +} + +static void +dummy_timer(ulong vp) +{ + struct aoedev *d; + + d = (struct aoedev *)vp; + if (d->flags & DEVFL_TKILL) + return; + d->timer.expires = jiffies + HZ; + add_timer(&d->timer); +} + +void +aoedev_downdev(struct aoedev *d) +{ + struct aoetgt **t, **te; + struct frame *f, *e; + struct buf *buf; + struct bio *bio; + + t = d->targets; + te = t + NTARGETS; + for (; t < te && *t; t++) { + f = (*t)->frames; + e = f + (*t)->nframes; + for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) { + if (f->tag == FREETAG || f->buf == NULL) + continue; + buf = f->buf; + bio = buf->bio; + if (--buf->nframesout == 0 + && buf != d->inprocess) { + mempool_free(buf, d->bufpool); + bio_endio(bio, -EIO); + } + } + (*t)->maxout = (*t)->nframes; + (*t)->nout = 0; + } + buf = d->inprocess; + if (buf) { + bio = buf->bio; + mempool_free(buf, d->bufpool); + bio_endio(bio, -EIO); + } + d->inprocess = NULL; + d->htgt = NULL; + + while (!list_empty(&d->bufq)) { + buf = container_of(d->bufq.next, struct buf, bufs); + list_del(d->bufq.next); + bio = buf->bio; + mempool_free(buf, d->bufpool); + bio_endio(bio, -EIO); + } + + if (d->gd) + set_capacity(d->gd, 0); + + d->flags &= ~DEVFL_UP; +} + +static void +aoedev_freedev(struct aoedev *d) +{ + struct aoetgt **t, **e; + + cancel_work_sync(&d->work); + 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(d, *t); + if (d->bufpool) + mempool_destroy(d->bufpool); + skbpoolfree(d); + blk_cleanup_queue(d->blkq); + 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); + } + + 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; +} + +/* I'm not really sure that this is a realistic problem, but if the +network driver goes gonzo let's just leak memory after complaining. */ +static void +skbfree(struct sk_buff *skb) +{ + enum { Sms = 100, Tms = 3*1000}; + int i = Tms / Sms; + + if (skb == NULL) + return; + while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0) + msleep(Sms); + if (i < 0) { + printk(KERN_ERR + "aoe: %s holds ref: %s\n", + skb->dev ? skb->dev->name : "netif", + "cannot free skb -- memory leaked."); + return; + } + skb_shinfo(skb)->nr_frags = skb->data_len = 0; + skb_trim(skb, 0); + dev_kfree_skb(skb); +} + +static void +skbpoolfree(struct aoedev *d) +{ + struct sk_buff *skb, *tmp; + + skb_queue_walk_safe(&d->skbpool, skb, tmp) + skbfree(skb); + + __skb_queue_head_init(&d->skbpool); +} + +/* find it or malloc it */ +struct aoedev * +aoedev_by_sysminor_m(ulong sysminor) +{ + struct aoedev *d; + ulong flags; + + spin_lock_irqsave(&devlist_lock, flags); + + for (d=devlist; d; d=d->next) + if (d->sysminor == sysminor) + break; + if (d) + goto out; + d = kcalloc(1, sizeof *d, GFP_ATOMIC); + if (!d) + goto out; + INIT_WORK(&d->work, aoecmd_sleepwork); + spin_lock_init(&d->lock); + skb_queue_head_init(&d->sendq); + skb_queue_head_init(&d->skbpool); + init_timer(&d->timer); + d->timer.data = (ulong) d; + d->timer.function = dummy_timer; + d->timer.expires = jiffies + HZ; + add_timer(&d->timer); + d->bufpool = NULL; /* defer to aoeblk_gdalloc */ + d->tgt = d->targets; + INIT_LIST_HEAD(&d->bufq); + d->sysminor = sysminor; + d->aoemajor = AOEMAJOR(sysminor); + d->aoeminor = AOEMINOR(sysminor); + d->mintimer = MINTIMER; + d->next = devlist; + devlist = d; + out: + spin_unlock_irqrestore(&devlist_lock, flags); + return d; +} + +static void +freetgt(struct aoedev *d, struct aoetgt *t) +{ + struct frame *f, *e; + + f = t->frames; + e = f + t->nframes; + for (; f < e; f++) + skbfree(f->skb); + kfree(t->frames); + kfree(t); +} + +void +aoedev_exit(void) +{ + struct aoedev *d; + ulong flags; + + while ((d = devlist)) { + devlist = d->next; + + spin_lock_irqsave(&d->lock, flags); + aoedev_downdev(d); + d->flags |= DEVFL_TKILL; + spin_unlock_irqrestore(&d->lock, flags); + + del_timer_sync(&d->timer); + aoedev_freedev(d); + } +} + +int __init +aoedev_init(void) +{ + return 0; +} |