linux/drivers/block/aoe/aoedev.c
<<
>>
Prefs
   1/* Copyright (c) 2007 Coraid, Inc.  See COPYING for GPL terms. */
   2/*
   3 * aoedev.c
   4 * AoE device utility functions; maintains device list.
   5 */
   6
   7#include <linux/hdreg.h>
   8#include <linux/blkdev.h>
   9#include <linux/netdevice.h>
  10#include <linux/delay.h>
  11#include <linux/slab.h>
  12#include "aoe.h"
  13
  14static void dummy_timer(ulong);
  15static void aoedev_freedev(struct aoedev *);
  16static void freetgt(struct aoedev *d, struct aoetgt *t);
  17static void skbpoolfree(struct aoedev *d);
  18
  19static struct aoedev *devlist;
  20static DEFINE_SPINLOCK(devlist_lock);
  21
  22struct aoedev *
  23aoedev_by_aoeaddr(int maj, int min)
  24{
  25        struct aoedev *d;
  26        ulong flags;
  27
  28        spin_lock_irqsave(&devlist_lock, flags);
  29
  30        for (d=devlist; d; d=d->next)
  31                if (d->aoemajor == maj && d->aoeminor == min)
  32                        break;
  33
  34        spin_unlock_irqrestore(&devlist_lock, flags);
  35        return d;
  36}
  37
  38static void
  39dummy_timer(ulong vp)
  40{
  41        struct aoedev *d;
  42
  43        d = (struct aoedev *)vp;
  44        if (d->flags & DEVFL_TKILL)
  45                return;
  46        d->timer.expires = jiffies + HZ;
  47        add_timer(&d->timer);
  48}
  49
  50void
  51aoedev_downdev(struct aoedev *d)
  52{
  53        struct aoetgt **t, **te;
  54        struct frame *f, *e;
  55        struct buf *buf;
  56        struct bio *bio;
  57
  58        t = d->targets;
  59        te = t + NTARGETS;
  60        for (; t < te && *t; t++) {
  61                f = (*t)->frames;
  62                e = f + (*t)->nframes;
  63                for (; f < e; f->tag = FREETAG, f->buf = NULL, f++) {
  64                        if (f->tag == FREETAG || f->buf == NULL)
  65                                continue;
  66                        buf = f->buf;
  67                        bio = buf->bio;
  68                        if (--buf->nframesout == 0
  69                        && buf != d->inprocess) {
  70                                mempool_free(buf, d->bufpool);
  71                                bio_endio(bio, -EIO);
  72                        }
  73                }
  74                (*t)->maxout = (*t)->nframes;
  75                (*t)->nout = 0;
  76        }
  77        buf = d->inprocess;
  78        if (buf) {
  79                bio = buf->bio;
  80                mempool_free(buf, d->bufpool);
  81                bio_endio(bio, -EIO);
  82        }
  83        d->inprocess = NULL;
  84        d->htgt = NULL;
  85
  86        while (!list_empty(&d->bufq)) {
  87                buf = container_of(d->bufq.next, struct buf, bufs);
  88                list_del(d->bufq.next);
  89                bio = buf->bio;
  90                mempool_free(buf, d->bufpool);
  91                bio_endio(bio, -EIO);
  92        }
  93
  94        if (d->gd)
  95                set_capacity(d->gd, 0);
  96
  97        d->flags &= ~DEVFL_UP;
  98}
  99
 100static void
 101aoedev_freedev(struct aoedev *d)
 102{
 103        struct aoetgt **t, **e;
 104
 105        cancel_work_sync(&d->work);
 106        if (d->gd) {
 107                aoedisk_rm_sysfs(d);
 108                del_gendisk(d->gd);
 109                put_disk(d->gd);
 110        }
 111        t = d->targets;
 112        e = t + NTARGETS;
 113        for (; t < e && *t; t++)
 114                freetgt(d, *t);
 115        if (d->bufpool)
 116                mempool_destroy(d->bufpool);
 117        skbpoolfree(d);
 118        blk_cleanup_queue(d->blkq);
 119        kfree(d);
 120}
 121
 122int
 123aoedev_flush(const char __user *str, size_t cnt)
 124{
 125        ulong flags;
 126        struct aoedev *d, **dd;
 127        struct aoedev *rmd = NULL;
 128        char buf[16];
 129        int all = 0;
 130
 131        if (cnt >= 3) {
 132                if (cnt > sizeof buf)
 133                        cnt = sizeof buf;
 134                if (copy_from_user(buf, str, cnt))
 135                        return -EFAULT;
 136                all = !strncmp(buf, "all", 3);
 137        }
 138
 139        spin_lock_irqsave(&devlist_lock, flags);
 140        dd = &devlist;
 141        while ((d = *dd)) {
 142                spin_lock(&d->lock);
 143                if ((!all && (d->flags & DEVFL_UP))
 144                || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
 145                || d->nopen) {
 146                        spin_unlock(&d->lock);
 147                        dd = &d->next;
 148                        continue;
 149                }
 150                *dd = d->next;
 151                aoedev_downdev(d);
 152                d->flags |= DEVFL_TKILL;
 153                spin_unlock(&d->lock);
 154                d->next = rmd;
 155                rmd = d;
 156        }
 157        spin_unlock_irqrestore(&devlist_lock, flags);
 158        while ((d = rmd)) {
 159                rmd = d->next;
 160                del_timer_sync(&d->timer);
 161                aoedev_freedev(d);      /* must be able to sleep */
 162        }
 163        return 0;
 164}
 165
 166/* I'm not really sure that this is a realistic problem, but if the
 167network driver goes gonzo let's just leak memory after complaining. */
 168static void
 169skbfree(struct sk_buff *skb)
 170{
 171        enum { Sms = 100, Tms = 3*1000};
 172        int i = Tms / Sms;
 173
 174        if (skb == NULL)
 175                return;
 176        while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
 177                msleep(Sms);
 178        if (i < 0) {
 179                printk(KERN_ERR
 180                        "aoe: %s holds ref: %s\n",
 181                        skb->dev ? skb->dev->name : "netif",
 182                        "cannot free skb -- memory leaked.");
 183                return;
 184        }
 185        skb_shinfo(skb)->nr_frags = skb->data_len = 0;
 186        skb_trim(skb, 0);
 187        dev_kfree_skb(skb);
 188}
 189
 190static void
 191skbpoolfree(struct aoedev *d)
 192{
 193        struct sk_buff *skb, *tmp;
 194
 195        skb_queue_walk_safe(&d->skbpool, skb, tmp)
 196                skbfree(skb);
 197
 198        __skb_queue_head_init(&d->skbpool);
 199}
 200
 201/* find it or malloc it */
 202struct aoedev *
 203aoedev_by_sysminor_m(ulong sysminor)
 204{
 205        struct aoedev *d;
 206        ulong flags;
 207
 208        spin_lock_irqsave(&devlist_lock, flags);
 209
 210        for (d=devlist; d; d=d->next)
 211                if (d->sysminor == sysminor)
 212                        break;
 213        if (d)
 214                goto out;
 215        d = kcalloc(1, sizeof *d, GFP_ATOMIC);
 216        if (!d)
 217                goto out;
 218        INIT_WORK(&d->work, aoecmd_sleepwork);
 219        spin_lock_init(&d->lock);
 220        skb_queue_head_init(&d->sendq);
 221        skb_queue_head_init(&d->skbpool);
 222        init_timer(&d->timer);
 223        d->timer.data = (ulong) d;
 224        d->timer.function = dummy_timer;
 225        d->timer.expires = jiffies + HZ;
 226        add_timer(&d->timer);
 227        d->bufpool = NULL;      /* defer to aoeblk_gdalloc */
 228        d->tgt = d->targets;
 229        INIT_LIST_HEAD(&d->bufq);
 230        d->sysminor = sysminor;
 231        d->aoemajor = AOEMAJOR(sysminor);
 232        d->aoeminor = AOEMINOR(sysminor);
 233        d->mintimer = MINTIMER;
 234        d->next = devlist;
 235        devlist = d;
 236 out:
 237        spin_unlock_irqrestore(&devlist_lock, flags);
 238        return d;
 239}
 240
 241static void
 242freetgt(struct aoedev *d, struct aoetgt *t)
 243{
 244        struct frame *f, *e;
 245
 246        f = t->frames;
 247        e = f + t->nframes;
 248        for (; f < e; f++)
 249                skbfree(f->skb);
 250        kfree(t->frames);
 251        kfree(t);
 252}
 253
 254void
 255aoedev_exit(void)
 256{
 257        struct aoedev *d;
 258        ulong flags;
 259
 260        while ((d = devlist)) {
 261                devlist = d->next;
 262
 263                spin_lock_irqsave(&d->lock, flags);
 264                aoedev_downdev(d);
 265                d->flags |= DEVFL_TKILL;
 266                spin_unlock_irqrestore(&d->lock, flags);
 267
 268                del_timer_sync(&d->timer);
 269                aoedev_freedev(d);
 270        }
 271}
 272
 273int __init
 274aoedev_init(void)
 275{
 276        return 0;
 277}
 278