Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/drivers/block/aoe/aoechr.c
26282 views
1
/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
2
/*
3
* aoechr.c
4
* AoE character device driver
5
*/
6
7
#include <linux/hdreg.h>
8
#include <linux/blkdev.h>
9
#include <linux/completion.h>
10
#include <linux/delay.h>
11
#include <linux/slab.h>
12
#include <linux/mutex.h>
13
#include <linux/skbuff.h>
14
#include <linux/export.h>
15
#include "aoe.h"
16
17
enum {
18
//MINOR_STAT = 1, (moved to sysfs)
19
MINOR_ERR = 2,
20
MINOR_DISCOVER,
21
MINOR_INTERFACES,
22
MINOR_REVALIDATE,
23
MINOR_FLUSH,
24
MSGSZ = 2048,
25
NMSG = 100, /* message backlog to retain */
26
};
27
28
struct aoe_chardev {
29
ulong minor;
30
char name[32];
31
};
32
33
enum { EMFL_VALID = 1 };
34
35
struct ErrMsg {
36
short flags;
37
short len;
38
char *msg;
39
};
40
41
static DEFINE_MUTEX(aoechr_mutex);
42
43
/* A ring buffer of error messages, to be read through
44
* "/dev/etherd/err". When no messages are present,
45
* readers will block waiting for messages to appear.
46
*/
47
static struct ErrMsg emsgs[NMSG];
48
static int emsgs_head_idx, emsgs_tail_idx;
49
static struct completion emsgs_comp;
50
static spinlock_t emsgs_lock;
51
static int nblocked_emsgs_readers;
52
53
static struct aoe_chardev chardevs[] = {
54
{ MINOR_ERR, "err" },
55
{ MINOR_DISCOVER, "discover" },
56
{ MINOR_INTERFACES, "interfaces" },
57
{ MINOR_REVALIDATE, "revalidate" },
58
{ MINOR_FLUSH, "flush" },
59
};
60
61
static char *aoe_devnode(const struct device *dev, umode_t *mode)
62
{
63
return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
64
}
65
66
static const struct class aoe_class = {
67
.name = "aoe",
68
.devnode = aoe_devnode,
69
};
70
71
static int
72
discover(void)
73
{
74
aoecmd_cfg(0xffff, 0xff);
75
return 0;
76
}
77
78
static int
79
interfaces(const char __user *str, size_t size)
80
{
81
if (set_aoe_iflist(str, size)) {
82
printk(KERN_ERR
83
"aoe: could not set interface list: too many interfaces\n");
84
return -EINVAL;
85
}
86
return 0;
87
}
88
89
static int
90
revalidate(const char __user *str, size_t size)
91
{
92
int major, minor, n;
93
ulong flags;
94
struct aoedev *d;
95
struct sk_buff *skb;
96
char buf[16];
97
98
if (size >= sizeof buf)
99
return -EINVAL;
100
buf[sizeof buf - 1] = '\0';
101
if (copy_from_user(buf, str, size))
102
return -EFAULT;
103
104
n = sscanf(buf, "e%d.%d", &major, &minor);
105
if (n != 2) {
106
pr_err("aoe: invalid device specification %s\n", buf);
107
return -EINVAL;
108
}
109
d = aoedev_by_aoeaddr(major, minor, 0);
110
if (!d)
111
return -EINVAL;
112
spin_lock_irqsave(&d->lock, flags);
113
aoecmd_cleanslate(d);
114
aoecmd_cfg(major, minor);
115
loop:
116
skb = aoecmd_ata_id(d);
117
spin_unlock_irqrestore(&d->lock, flags);
118
/* try again if we are able to sleep a bit,
119
* otherwise give up this revalidation
120
*/
121
if (!skb && !msleep_interruptible(250)) {
122
spin_lock_irqsave(&d->lock, flags);
123
goto loop;
124
}
125
aoedev_put(d);
126
if (skb) {
127
struct sk_buff_head queue;
128
__skb_queue_head_init(&queue);
129
__skb_queue_tail(&queue, skb);
130
aoenet_xmit(&queue);
131
}
132
return 0;
133
}
134
135
void
136
aoechr_error(char *msg)
137
{
138
struct ErrMsg *em;
139
char *mp;
140
ulong flags, n;
141
142
n = strlen(msg);
143
144
spin_lock_irqsave(&emsgs_lock, flags);
145
146
em = emsgs + emsgs_tail_idx;
147
if ((em->flags & EMFL_VALID)) {
148
bail: spin_unlock_irqrestore(&emsgs_lock, flags);
149
return;
150
}
151
152
mp = kmemdup(msg, n, GFP_ATOMIC);
153
if (!mp)
154
goto bail;
155
156
em->msg = mp;
157
em->flags |= EMFL_VALID;
158
em->len = n;
159
160
emsgs_tail_idx++;
161
emsgs_tail_idx %= ARRAY_SIZE(emsgs);
162
163
spin_unlock_irqrestore(&emsgs_lock, flags);
164
165
if (nblocked_emsgs_readers)
166
complete(&emsgs_comp);
167
}
168
169
static ssize_t
170
aoechr_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offp)
171
{
172
int ret = -EINVAL;
173
174
switch ((unsigned long) filp->private_data) {
175
default:
176
printk(KERN_INFO "aoe: can't write to that file.\n");
177
break;
178
case MINOR_DISCOVER:
179
ret = discover();
180
break;
181
case MINOR_INTERFACES:
182
ret = interfaces(buf, cnt);
183
break;
184
case MINOR_REVALIDATE:
185
ret = revalidate(buf, cnt);
186
break;
187
case MINOR_FLUSH:
188
ret = aoedev_flush(buf, cnt);
189
break;
190
}
191
if (ret == 0)
192
ret = cnt;
193
return ret;
194
}
195
196
static int
197
aoechr_open(struct inode *inode, struct file *filp)
198
{
199
int n, i;
200
201
mutex_lock(&aoechr_mutex);
202
n = iminor(inode);
203
filp->private_data = (void *) (unsigned long) n;
204
205
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
206
if (chardevs[i].minor == n) {
207
mutex_unlock(&aoechr_mutex);
208
return 0;
209
}
210
mutex_unlock(&aoechr_mutex);
211
return -EINVAL;
212
}
213
214
static int
215
aoechr_rel(struct inode *inode, struct file *filp)
216
{
217
return 0;
218
}
219
220
static ssize_t
221
aoechr_read(struct file *filp, char __user *buf, size_t cnt, loff_t *off)
222
{
223
unsigned long n;
224
char *mp;
225
struct ErrMsg *em;
226
ssize_t len;
227
ulong flags;
228
229
n = (unsigned long) filp->private_data;
230
if (n != MINOR_ERR)
231
return -EFAULT;
232
233
spin_lock_irqsave(&emsgs_lock, flags);
234
235
for (;;) {
236
em = emsgs + emsgs_head_idx;
237
if ((em->flags & EMFL_VALID) != 0)
238
break;
239
if (filp->f_flags & O_NDELAY) {
240
spin_unlock_irqrestore(&emsgs_lock, flags);
241
return -EAGAIN;
242
}
243
nblocked_emsgs_readers++;
244
245
spin_unlock_irqrestore(&emsgs_lock, flags);
246
247
n = wait_for_completion_interruptible(&emsgs_comp);
248
249
spin_lock_irqsave(&emsgs_lock, flags);
250
251
nblocked_emsgs_readers--;
252
253
if (n) {
254
spin_unlock_irqrestore(&emsgs_lock, flags);
255
return -ERESTARTSYS;
256
}
257
}
258
if (em->len > cnt) {
259
spin_unlock_irqrestore(&emsgs_lock, flags);
260
return -EAGAIN;
261
}
262
mp = em->msg;
263
len = em->len;
264
em->msg = NULL;
265
em->flags &= ~EMFL_VALID;
266
267
emsgs_head_idx++;
268
emsgs_head_idx %= ARRAY_SIZE(emsgs);
269
270
spin_unlock_irqrestore(&emsgs_lock, flags);
271
272
n = copy_to_user(buf, mp, len);
273
kfree(mp);
274
return n == 0 ? len : -EFAULT;
275
}
276
277
static const struct file_operations aoe_fops = {
278
.write = aoechr_write,
279
.read = aoechr_read,
280
.open = aoechr_open,
281
.release = aoechr_rel,
282
.owner = THIS_MODULE,
283
.llseek = noop_llseek,
284
};
285
286
int __init
287
aoechr_init(void)
288
{
289
int n, i;
290
291
n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
292
if (n < 0) {
293
printk(KERN_ERR "aoe: can't register char device\n");
294
return n;
295
}
296
init_completion(&emsgs_comp);
297
spin_lock_init(&emsgs_lock);
298
n = class_register(&aoe_class);
299
if (n) {
300
unregister_chrdev(AOE_MAJOR, "aoechr");
301
return n;
302
}
303
304
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
305
device_create(&aoe_class, NULL,
306
MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
307
chardevs[i].name);
308
309
return 0;
310
}
311
312
void
313
aoechr_exit(void)
314
{
315
int i;
316
317
for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
318
device_destroy(&aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
319
class_unregister(&aoe_class);
320
unregister_chrdev(AOE_MAJOR, "aoechr");
321
}
322
323
324