• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/block/aoe/
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
14static void dummy_timer(ulong);
15static void aoedev_freedev(struct aoedev *);
16static void freetgt(struct aoedev *d, struct aoetgt *t);
17static void skbpoolfree(struct aoedev *d);
18
19static struct aoedev *devlist;
20static DEFINE_SPINLOCK(devlist_lock);
21
22struct aoedev *
23aoedev_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
38static void
39dummy_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
50void
51aoedev_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
100static void
101aoedev_freedev(struct aoedev *d)
102{
103	struct aoetgt **t, **e;
104
105	if (d->gd) {
106		aoedisk_rm_sysfs(d);
107		del_gendisk(d->gd);
108		put_disk(d->gd);
109	}
110	t = d->targets;
111	e = t + NTARGETS;
112	for (; t < e && *t; t++)
113		freetgt(d, *t);
114	if (d->bufpool)
115		mempool_destroy(d->bufpool);
116	skbpoolfree(d);
117	blk_cleanup_queue(d->blkq);
118	kfree(d);
119}
120
121int
122aoedev_flush(const char __user *str, size_t cnt)
123{
124	ulong flags;
125	struct aoedev *d, **dd;
126	struct aoedev *rmd = NULL;
127	char buf[16];
128	int all = 0;
129
130	if (cnt >= 3) {
131		if (cnt > sizeof buf)
132			cnt = sizeof buf;
133		if (copy_from_user(buf, str, cnt))
134			return -EFAULT;
135		all = !strncmp(buf, "all", 3);
136	}
137
138	flush_scheduled_work();
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
167network driver goes gonzo let's just leak memory after complaining. */
168static void
169skbfree(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
190static void
191skbpoolfree(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 */
202struct aoedev *
203aoedev_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
241static void
242freetgt(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
254void
255aoedev_exit(void)
256{
257	struct aoedev *d;
258	ulong flags;
259
260	flush_scheduled_work();
261
262	while ((d = devlist)) {
263		devlist = d->next;
264
265		spin_lock_irqsave(&d->lock, flags);
266		aoedev_downdev(d);
267		d->flags |= DEVFL_TKILL;
268		spin_unlock_irqrestore(&d->lock, flags);
269
270		del_timer_sync(&d->timer);
271		aoedev_freedev(d);
272	}
273}
274
275int __init
276aoedev_init(void)
277{
278	return 0;
279}
280