rbd: warn on update_snaps failure on notify
[linux-2.6.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 aoedev_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
100 static void
101 aoedev_freedev(struct aoedev *d)
102 {
103         struct aoetgt **t, **e;
104
105         cancel_work_sync(&d->work);
106         if (d->gd) {
107                 aoedisk_rm_sysfs(d);
108                 del_gendisk(d->gd);
109                 put_disk(d->gd);
110         }
111         t = d->targets;
112         e = t + NTARGETS;
113         for (; t < e && *t; t++)
114                 freetgt(d, *t);
115         if (d->bufpool)
116                 mempool_destroy(d->bufpool);
117         skbpoolfree(d);
118         blk_cleanup_queue(d->blkq);
119         kfree(d);
120 }
121
122 int
123 aoedev_flush(const char __user *str, size_t cnt)
124 {
125         ulong flags;
126         struct aoedev *d, **dd;
127         struct aoedev *rmd = NULL;
128         char buf[16];
129         int all = 0;
130
131         if (cnt >= 3) {
132                 if (cnt > sizeof buf)
133                         cnt = sizeof buf;
134                 if (copy_from_user(buf, str, cnt))
135                         return -EFAULT;
136                 all = !strncmp(buf, "all", 3);
137         }
138
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
167 network driver goes gonzo let's just leak memory after complaining. */
168 static void
169 skbfree(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
190 static void
191 skbpoolfree(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 */
202 struct aoedev *
203 aoedev_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
241 static void
242 freetgt(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
254 void
255 aoedev_exit(void)
256 {
257         struct aoedev *d;
258         ulong flags;
259
260         while ((d = devlist)) {
261                 devlist = d->next;
262
263                 spin_lock_irqsave(&d->lock, flags);
264                 aoedev_downdev(d);
265                 d->flags |= DEVFL_TKILL;
266                 spin_unlock_irqrestore(&d->lock, flags);
267
268                 del_timer_sync(&d->timer);
269                 aoedev_freedev(d);
270         }
271 }
272
273 int __init
274 aoedev_init(void)
275 {
276         return 0;
277 }