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