linux/drivers/block/aoe/aoedev.c
<<
>>
Prefs
   1/* Copyright (c) 2004 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 "aoe.h"
  11
  12static struct aoedev *devlist;
  13static spinlock_t devlist_lock;
  14
  15struct aoedev *
  16aoedev_bymac(unsigned char *macaddr)
  17{
  18        struct aoedev *d;
  19        ulong flags;
  20
  21        spin_lock_irqsave(&devlist_lock, flags);
  22
  23        for (d=devlist; d; d=d->next)
  24                if (!memcmp(d->addr, macaddr, 6))
  25                        break;
  26
  27        spin_unlock_irqrestore(&devlist_lock, flags);
  28        return d;
  29}
  30
  31/* called with devlist lock held */
  32static struct aoedev *
  33aoedev_newdev(ulong nframes)
  34{
  35        struct aoedev *d;
  36        struct frame *f, *e;
  37
  38        d = kcalloc(1, sizeof *d, GFP_ATOMIC);
  39        if (d == NULL)
  40                return NULL;
  41        f = kcalloc(nframes, sizeof *f, GFP_ATOMIC);
  42        if (f == NULL) {
  43                kfree(d);
  44                return NULL;
  45        }
  46
  47        d->nframes = nframes;
  48        d->frames = f;
  49        e = f + nframes;
  50        for (; f<e; f++)
  51                f->tag = FREETAG;
  52
  53        spin_lock_init(&d->lock);
  54        init_timer(&d->timer);
  55        d->bufpool = NULL;      /* defer to aoeblk_gdalloc */
  56        INIT_LIST_HEAD(&d->bufq);
  57        d->next = devlist;
  58        devlist = d;
  59
  60        return d;
  61}
  62
  63void
  64aoedev_downdev(struct aoedev *d)
  65{
  66        struct frame *f, *e;
  67        struct buf *buf;
  68        struct bio *bio;
  69
  70        d->flags |= DEVFL_TKILL;
  71        del_timer(&d->timer);
  72
  73        f = d->frames;
  74        e = f + d->nframes;
  75        for (; f<e; f->tag = FREETAG, f->buf = NULL, f++) {
  76                if (f->tag == FREETAG || f->buf == NULL)
  77                        continue;
  78                buf = f->buf;
  79                bio = buf->bio;
  80                if (--buf->nframesout == 0) {
  81                        mempool_free(buf, d->bufpool);
  82                        bio_endio(bio, bio->bi_size, -EIO);
  83                }
  84        }
  85        d->inprocess = NULL;
  86
  87        while (!list_empty(&d->bufq)) {
  88                buf = container_of(d->bufq.next, struct buf, bufs);
  89                list_del(d->bufq.next);
  90                bio = buf->bio;
  91                mempool_free(buf, d->bufpool);
  92                bio_endio(bio, bio->bi_size, -EIO);
  93        }
  94
  95        if (d->nopen)
  96                d->flags |= DEVFL_CLOSEWAIT;
  97        if (d->gd)
  98                d->gd->capacity = 0;
  99
 100        d->flags &= ~DEVFL_UP;
 101}
 102
 103struct aoedev *
 104aoedev_set(ulong sysminor, unsigned char *addr, struct net_device *ifp, ulong bufcnt)
 105{
 106        struct aoedev *d;
 107        ulong flags;
 108
 109        spin_lock_irqsave(&devlist_lock, flags);
 110
 111        for (d=devlist; d; d=d->next)
 112                if (d->sysminor == sysminor
 113                || memcmp(d->addr, addr, sizeof d->addr) == 0)
 114                        break;
 115
 116        if (d == NULL && (d = aoedev_newdev(bufcnt)) == NULL) {
 117                spin_unlock_irqrestore(&devlist_lock, flags);
 118                printk(KERN_INFO "aoe: aoedev_set: aoedev_newdev failure.\n");
 119                return NULL;
 120        }
 121
 122        spin_unlock_irqrestore(&devlist_lock, flags);
 123        spin_lock_irqsave(&d->lock, flags);
 124
 125        d->ifp = ifp;
 126
 127        if (d->sysminor != sysminor
 128        || memcmp(d->addr, addr, sizeof d->addr)
 129        || (d->flags & DEVFL_UP) == 0) {
 130                aoedev_downdev(d); /* flushes outstanding frames */
 131                memcpy(d->addr, addr, sizeof d->addr);
 132                d->sysminor = sysminor;
 133                d->aoemajor = AOEMAJOR(sysminor);
 134                d->aoeminor = AOEMINOR(sysminor);
 135        }
 136
 137        spin_unlock_irqrestore(&d->lock, flags);
 138        return d;
 139}
 140
 141static void
 142aoedev_freedev(struct aoedev *d)
 143{
 144        if (d->gd) {
 145                aoedisk_rm_sysfs(d);
 146                del_gendisk(d->gd);
 147                put_disk(d->gd);
 148        }
 149        kfree(d->frames);
 150        mempool_destroy(d->bufpool);
 151        kfree(d);
 152}
 153
 154void
 155aoedev_exit(void)
 156{
 157        struct aoedev *d;
 158        ulong flags;
 159
 160        flush_scheduled_work();
 161
 162        while ((d = devlist)) {
 163                devlist = d->next;
 164
 165                spin_lock_irqsave(&d->lock, flags);
 166                aoedev_downdev(d);
 167                spin_unlock_irqrestore(&d->lock, flags);
 168
 169                del_timer_sync(&d->timer);
 170                aoedev_freedev(d);
 171        }
 172}
 173
 174int __init
 175aoedev_init(void)
 176{
 177        spin_lock_init(&devlist_lock);
 178        return 0;
 179}
 180
 181
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.