]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - drivers/block/aoe/aoedev.c
40bae1a1ff1e23ea1f3e13ad708c9e34c54c8faa
[karo-tx-linux.git] / drivers / block / aoe / aoedev.c
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
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);
18
19 static struct aoedev *devlist;
20 static DEFINE_SPINLOCK(devlist_lock);
21
22 struct aoedev *
23 aoedev_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
38 static void
39 dummy_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
50 void
51 aoe_failbuf(struct aoedev *d, struct buf *buf)
52 {
53         struct bio *bio;
54
55         if (buf == NULL)
56                 return;
57         buf->flags |= BUFFL_FAIL;
58         if (buf->nframesout == 0) {
59                 if (buf == d->inprocess) /* ensure we only process this once */
60                         d->inprocess = NULL;
61                 bio = buf->bio;
62                 mempool_free(buf, d->bufpool);
63                 bio_endio(bio, -EIO);
64         }
65 }
66
67 void
68 aoedev_downdev(struct aoedev *d)
69 {
70         struct aoetgt *t, **tt, **te;
71         struct frame *f;
72         struct list_head *head, *pos, *nx;
73         int i;
74
75         /* clean out active buffers on all targets */
76         tt = d->targets;
77         te = tt + NTARGETS;
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) {
82                                 list_del(pos);
83                                 f = list_entry(pos, struct frame, head);
84                                 if (f->buf) {
85                                         f->buf->nframesout--;
86                                         aoe_failbuf(d, f->buf);
87                                 }
88                                 aoe_freetframe(f);
89                         }
90                 }
91                 t->maxout = t->nframes;
92                 t->nout = 0;
93         }
94
95         /* clean out the in-process buffer (if any) */
96         aoe_failbuf(d, d->inprocess);
97         d->inprocess = NULL;
98         d->htgt = NULL;
99
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);
104                 aoe_failbuf(d, buf);
105         }
106
107         if (d->gd)
108                 set_capacity(d->gd, 0);
109
110         d->flags &= ~DEVFL_UP;
111 }
112
113 static void
114 aoedev_freedev(struct aoedev *d)
115 {
116         struct aoetgt **t, **e;
117
118         cancel_work_sync(&d->work);
119         if (d->gd) {
120                 aoedisk_rm_sysfs(d);
121                 del_gendisk(d->gd);
122                 put_disk(d->gd);
123         }
124         t = d->targets;
125         e = t + NTARGETS;
126         for (; t < e && *t; t++)
127                 freetgt(d, *t);
128         if (d->bufpool)
129                 mempool_destroy(d->bufpool);
130         skbpoolfree(d);
131         blk_cleanup_queue(d->blkq);
132         kfree(d);
133 }
134
135 int
136 aoedev_flush(const char __user *str, size_t cnt)
137 {
138         ulong flags;
139         struct aoedev *d, **dd;
140         struct aoedev *rmd = NULL;
141         char buf[16];
142         int all = 0;
143
144         if (cnt >= 3) {
145                 if (cnt > sizeof buf)
146                         cnt = sizeof buf;
147                 if (copy_from_user(buf, str, cnt))
148                         return -EFAULT;
149                 all = !strncmp(buf, "all", 3);
150         }
151
152         spin_lock_irqsave(&devlist_lock, flags);
153         dd = &devlist;
154         while ((d = *dd)) {
155                 spin_lock(&d->lock);
156                 if ((!all && (d->flags & DEVFL_UP))
157                 || (d->flags & (DEVFL_GDALLOC|DEVFL_NEWSIZE))
158                 || d->nopen) {
159                         spin_unlock(&d->lock);
160                         dd = &d->next;
161                         continue;
162                 }
163                 *dd = d->next;
164                 aoedev_downdev(d);
165                 d->flags |= DEVFL_TKILL;
166                 spin_unlock(&d->lock);
167                 d->next = rmd;
168                 rmd = d;
169         }
170         spin_unlock_irqrestore(&devlist_lock, flags);
171         while ((d = rmd)) {
172                 rmd = d->next;
173                 del_timer_sync(&d->timer);
174                 aoedev_freedev(d);      /* must be able to sleep */
175         }
176         return 0;
177 }
178
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. */
181 static void
182 skbfree(struct sk_buff *skb)
183 {
184         enum { Sms = 100, Tms = 3*1000};
185         int i = Tms / Sms;
186
187         if (skb == NULL)
188                 return;
189         while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
190                 msleep(Sms);
191         if (i < 0) {
192                 printk(KERN_ERR
193                         "aoe: %s holds ref: %s\n",
194                         skb->dev ? skb->dev->name : "netif",
195                         "cannot free skb -- memory leaked.");
196                 return;
197         }
198         skb->truesize -= skb->data_len;
199         skb_shinfo(skb)->nr_frags = skb->data_len = 0;
200         skb_trim(skb, 0);
201         dev_kfree_skb(skb);
202 }
203
204 static void
205 skbpoolfree(struct aoedev *d)
206 {
207         struct sk_buff *skb, *tmp;
208
209         skb_queue_walk_safe(&d->skbpool, skb, tmp)
210                 skbfree(skb);
211
212         __skb_queue_head_init(&d->skbpool);
213 }
214
215 /* find it or malloc it */
216 struct aoedev *
217 aoedev_by_sysminor_m(ulong sysminor)
218 {
219         struct aoedev *d;
220         ulong flags;
221
222         spin_lock_irqsave(&devlist_lock, flags);
223
224         for (d=devlist; d; d=d->next)
225                 if (d->sysminor == sysminor)
226                         break;
227         if (d)
228                 goto out;
229         d = kcalloc(1, sizeof *d, GFP_ATOMIC);
230         if (!d)
231                 goto out;
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 */
242         d->tgt = d->targets;
243         INIT_LIST_HEAD(&d->bufq);
244         d->sysminor = sysminor;
245         d->aoemajor = AOEMAJOR(sysminor);
246         d->aoeminor = AOEMINOR(sysminor);
247         d->mintimer = MINTIMER;
248         d->next = devlist;
249         devlist = d;
250  out:
251         spin_unlock_irqrestore(&devlist_lock, flags);
252         return d;
253 }
254
255 static void
256 freetgt(struct aoedev *d, struct aoetgt *t)
257 {
258         struct frame *f;
259         struct list_head *pos, *nx, *head;
260
261         head = &t->ffree;
262         list_for_each_safe(pos, nx, head) {
263                 list_del(pos);
264                 f = list_entry(pos, struct frame, head);
265                 skbfree(f->skb);
266                 kfree(f);
267         }
268         kfree(t);
269 }
270
271 void
272 aoedev_exit(void)
273 {
274         struct aoedev *d;
275         ulong flags;
276
277         while ((d = devlist)) {
278                 devlist = d->next;
279
280                 spin_lock_irqsave(&d->lock, flags);
281                 aoedev_downdev(d);
282                 d->flags |= DEVFL_TKILL;
283                 spin_unlock_irqrestore(&d->lock, flags);
284
285                 del_timer_sync(&d->timer);
286                 aoedev_freedev(d);
287         }
288 }
289
290 int __init
291 aoedev_init(void)
292 {
293         return 0;
294 }