1 /* Copyright (c) 2007 Coraid, Inc. See COPYING for GPL terms. */
4 * AoE device utility functions; maintains device list.
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>
14 static void dummy_timer(ulong);
15 static void aoedev_freedev(struct aoedev *);
16 static void freetgt(struct aoedev *d, struct aoetgt *t);
17 static void skbpoolfree(struct aoedev *d);
19 static struct aoedev *devlist;
20 static DEFINE_SPINLOCK(devlist_lock);
23 aoedev_by_aoeaddr(int maj, int min)
28 spin_lock_irqsave(&devlist_lock, flags);
30 for (d=devlist; d; d=d->next)
31 if (d->aoemajor == maj && d->aoeminor == min)
34 spin_unlock_irqrestore(&devlist_lock, flags);
43 d = (struct aoedev *)vp;
44 if (d->flags & DEVFL_TKILL)
46 d->timer.expires = jiffies + HZ;
51 aoe_failbuf(struct aoedev *d, struct buf *buf)
57 buf->flags |= BUFFL_FAIL;
58 if (buf->nframesout == 0) {
59 if (buf == d->inprocess) /* ensure we only process this once */
62 mempool_free(buf, d->bufpool);
68 aoedev_downdev(struct aoedev *d)
70 struct aoetgt *t, **tt, **te;
72 struct list_head *head, *pos, *nx;
75 /* clean out active buffers on all targets */
78 for (; tt < te && (t = *tt); tt++) {
79 for (i = 0; i < NFACTIVE; i++) {
80 head = &t->factive[i];
81 list_for_each_safe(pos, nx, head) {
83 f = list_entry(pos, struct frame, head);
86 aoe_failbuf(d, f->buf);
91 t->maxout = t->nframes;
95 /* clean out the in-process buffer (if any) */
96 aoe_failbuf(d, d->inprocess);
100 /* clean out all pending I/O */
101 while (!list_empty(&d->bufq)) {
102 struct buf *buf = container_of(d->bufq.next, struct buf, bufs);
103 list_del(d->bufq.next);
108 set_capacity(d->gd, 0);
110 d->flags &= ~DEVFL_UP;
114 aoedev_freedev(struct aoedev *d)
116 struct aoetgt **t, **e;
118 cancel_work_sync(&d->work);
126 for (; t < e && *t; t++)
129 mempool_destroy(d->bufpool);
131 blk_cleanup_queue(d->blkq);
136 aoedev_flush(const char __user *str, size_t cnt)
139 struct aoedev *d, **dd;
140 struct aoedev *rmd = NULL;
145 if (cnt > sizeof buf)
147 if (copy_from_user(buf, str, cnt))
149 all = !strncmp(buf, "all", 3);
152 spin_lock_irqsave(&devlist_lock, flags);
156 if ((!all && (d->flags & DEVFL_UP))
157 || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
159 spin_unlock(&d->lock);
165 d->flags |= DEVFL_TKILL;
166 spin_unlock(&d->lock);
170 spin_unlock_irqrestore(&devlist_lock, flags);
173 del_timer_sync(&d->timer);
174 aoedev_freedev(d); /* must be able to sleep */
179 /* I'm not really sure that this is a realistic problem, but if the
180 network driver goes gonzo let's just leak memory after complaining. */
182 skbfree(struct sk_buff *skb)
184 enum { Sms = 100, Tms = 3*1000};
189 while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
193 "aoe: %s holds ref: %s\n",
194 skb->dev ? skb->dev->name : "netif",
195 "cannot free skb -- memory leaked.");
198 skb->truesize -= skb->data_len;
199 skb_shinfo(skb)->nr_frags = skb->data_len = 0;
205 skbpoolfree(struct aoedev *d)
207 struct sk_buff *skb, *tmp;
209 skb_queue_walk_safe(&d->skbpool, skb, tmp)
212 __skb_queue_head_init(&d->skbpool);
215 /* find it or malloc it */
217 aoedev_by_sysminor_m(ulong sysminor)
222 spin_lock_irqsave(&devlist_lock, flags);
224 for (d=devlist; d; d=d->next)
225 if (d->sysminor == sysminor)
229 d = kcalloc(1, sizeof *d, GFP_ATOMIC);
232 INIT_WORK(&d->work, aoecmd_sleepwork);
233 spin_lock_init(&d->lock);
234 skb_queue_head_init(&d->sendq);
235 skb_queue_head_init(&d->skbpool);
236 init_timer(&d->timer);
237 d->timer.data = (ulong) d;
238 d->timer.function = dummy_timer;
239 d->timer.expires = jiffies + HZ;
240 add_timer(&d->timer);
241 d->bufpool = NULL; /* defer to aoeblk_gdalloc */
243 INIT_LIST_HEAD(&d->bufq);
244 d->sysminor = sysminor;
245 d->aoemajor = AOEMAJOR(sysminor);
246 d->aoeminor = AOEMINOR(sysminor);
247 d->mintimer = MINTIMER;
251 spin_unlock_irqrestore(&devlist_lock, flags);
256 freetgt(struct aoedev *d, struct aoetgt *t)
259 struct list_head *pos, *nx, *head;
262 list_for_each_safe(pos, nx, head) {
264 f = list_entry(pos, struct frame, head);
277 while ((d = devlist)) {
280 spin_lock_irqsave(&d->lock, flags);
282 d->flags |= DEVFL_TKILL;
283 spin_unlock_irqrestore(&d->lock, flags);
285 del_timer_sync(&d->timer);