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 if (d->gd) { 106 aoedisk_rm_sysfs(d); 107 del_gendisk(d->gd); 108 put_disk(d->gd); 109 } 110 t = d->targets; 111 e = t + NTARGETS; 112 for (; t < e && *t; t++) 113 freetgt(d, *t); 114 if (d->bufpool) 115 mempool_destroy(d->bufpool); 116 skbpoolfree(d); 117 blk_cleanup_queue(d->blkq); 118 kfree(d); 119} 120 121int 122aoedev_flush(const char __user *str, size_t cnt) 123{ 124 ulong flags; 125 struct aoedev *d, **dd; 126 struct aoedev *rmd = NULL; 127 char buf[16]; 128 int all = 0; 129 130 if (cnt >= 3) { 131 if (cnt > sizeof buf) 132 cnt = sizeof buf; 133 if (copy_from_user(buf, str, cnt)) 134 return -EFAULT; 135 all = !strncmp(buf, "all", 3); 136 } 137 138 flush_scheduled_work(); 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 flush_scheduled_work(); 261 262 while ((d = devlist)) { 263 devlist = d->next; 264 265 spin_lock_irqsave(&d->lock, flags); 266 aoedev_downdev(d); 267 d->flags |= DEVFL_TKILL; 268 spin_unlock_irqrestore(&d->lock, flags); 269 270 del_timer_sync(&d->timer); 271 aoedev_freedev(d); 272 } 273} 274 275int __init 276aoedev_init(void) 277{ 278 return 0; 279} 280