Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/drivers/block/aoe/aoedev.c
15112 views
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
}
278
279