Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 }
296 
  This page was automatically generated by the LXR engine.