Merge tag 'mm-hotfixes-stable-2024-06-26-17-28' of git://git.kernel.org/pub/scm/linux...
[linux-2.6-block.git] / drivers / block / aoe / aoechr.c
CommitLineData
fea05a26 1/* Copyright (c) 2012 Coraid, Inc. See COPYING for GPL terms. */
1da177e4
LT
2/*
3 * aoechr.c
4 * AoE character device driver
5 */
6
7#include <linux/hdreg.h>
8#include <linux/blkdev.h>
24879a8e 9#include <linux/completion.h>
68e0d42f 10#include <linux/delay.h>
5a0e3ad6 11#include <linux/slab.h>
2a48fc0a 12#include <linux/mutex.h>
e9bb8fb0 13#include <linux/skbuff.h>
d5decd3b 14#include <linux/export.h>
1da177e4
LT
15#include "aoe.h"
16
17enum {
18 //MINOR_STAT = 1, (moved to sysfs)
19 MINOR_ERR = 2,
20 MINOR_DISCOVER,
21 MINOR_INTERFACES,
3ae1c24e 22 MINOR_REVALIDATE,
262bf541 23 MINOR_FLUSH,
1da177e4 24 MSGSZ = 2048,
1da177e4
LT
25 NMSG = 100, /* message backlog to retain */
26};
27
28struct aoe_chardev {
29 ulong minor;
30 char name[32];
31};
32
33enum { EMFL_VALID = 1 };
34
35struct ErrMsg {
36 short flags;
37 short len;
38 char *msg;
39};
40
2a48fc0a 41static DEFINE_MUTEX(aoechr_mutex);
662a8896
EC
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 */
1da177e4
LT
47static struct ErrMsg emsgs[NMSG];
48static int emsgs_head_idx, emsgs_tail_idx;
24879a8e 49static struct completion emsgs_comp;
1da177e4
LT
50static spinlock_t emsgs_lock;
51static int nblocked_emsgs_readers;
65d7a37d 52
1da177e4
LT
53static struct aoe_chardev chardevs[] = {
54 { MINOR_ERR, "err" },
55 { MINOR_DISCOVER, "discover" },
56 { MINOR_INTERFACES, "interfaces" },
3ae1c24e 57 { MINOR_REVALIDATE, "revalidate" },
262bf541 58 { MINOR_FLUSH, "flush" },
1da177e4
LT
59};
60
65d7a37d
IO
61static char *aoe_devnode(const struct device *dev, umode_t *mode)
62{
63 return kasprintf(GFP_KERNEL, "etherd/%s", dev_name(dev));
64}
65
66static const struct class aoe_class = {
67 .name = "aoe",
68 .devnode = aoe_devnode,
69};
70
1da177e4
LT
71static int
72discover(void)
73{
74 aoecmd_cfg(0xffff, 0xff);
75 return 0;
76}
77
78static int
79interfaces(const char __user *str, size_t size)
80{
81 if (set_aoe_iflist(str, size)) {
a12c93f0
EC
82 printk(KERN_ERR
83 "aoe: could not set interface list: too many interfaces\n");
1da177e4
LT
84 return -EINVAL;
85 }
86 return 0;
87}
88
3ae1c24e
EC
89static int
90revalidate(const char __user *str, size_t size)
91{
92 int major, minor, n;
93 ulong flags;
94 struct aoedev *d;
68e0d42f 95 struct sk_buff *skb;
3ae1c24e
EC
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
3ae1c24e
EC
104 n = sscanf(buf, "e%d.%d", &major, &minor);
105 if (n != 2) {
896831f5 106 pr_err("aoe: invalid device specification %s\n", buf);
3ae1c24e
EC
107 return -EINVAL;
108 }
0c966214 109 d = aoedev_by_aoeaddr(major, minor, 0);
3ae1c24e
EC
110 if (!d)
111 return -EINVAL;
3ae1c24e 112 spin_lock_irqsave(&d->lock, flags);
68e0d42f 113 aoecmd_cleanslate(d);
25f4d75e 114 aoecmd_cfg(major, minor);
68e0d42f
EC
115loop:
116 skb = aoecmd_ata_id(d);
3ae1c24e 117 spin_unlock_irqrestore(&d->lock, flags);
68e0d42f
EC
118 /* try again if we are able to sleep a bit,
119 * otherwise give up this revalidation
120 */
25f4d75e 121 if (!skb && !msleep_interruptible(250)) {
68e0d42f
EC
122 spin_lock_irqsave(&d->lock, flags);
123 goto loop;
124 }
69cf2d85 125 aoedev_put(d);
e9bb8fb0
DM
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 }
3ae1c24e
EC
132 return 0;
133}
134
1da177e4
LT
135void
136aoechr_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)) {
148bail: spin_unlock_irqrestore(&emsgs_lock, flags);
149 return;
150 }
151
60abc786 152 mp = kmemdup(msg, n, GFP_ATOMIC);
76cdb09b 153 if (!mp)
1da177e4 154 goto bail;
1da177e4 155
1da177e4
LT
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)
24879a8e 166 complete(&emsgs_comp);
1da177e4
LT
167}
168
169static ssize_t
170aoechr_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:
a12c93f0 176 printk(KERN_INFO "aoe: can't write to that file.\n");
1da177e4
LT
177 break;
178 case MINOR_DISCOVER:
179 ret = discover();
180 break;
181 case MINOR_INTERFACES:
182 ret = interfaces(buf, cnt);
183 break;
3ae1c24e
EC
184 case MINOR_REVALIDATE:
185 ret = revalidate(buf, cnt);
262bf541
EC
186 break;
187 case MINOR_FLUSH:
188 ret = aoedev_flush(buf, cnt);
b21faa25 189 break;
1da177e4
LT
190 }
191 if (ret == 0)
192 ret = cnt;
193 return ret;
194}
195
196static int
197aoechr_open(struct inode *inode, struct file *filp)
198{
199 int n, i;
200
2a48fc0a 201 mutex_lock(&aoechr_mutex);
2017b376 202 n = iminor(inode);
1da177e4
LT
203 filp->private_data = (void *) (unsigned long) n;
204
205 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
579174a5 206 if (chardevs[i].minor == n) {
2a48fc0a 207 mutex_unlock(&aoechr_mutex);
1da177e4 208 return 0;
579174a5 209 }
2a48fc0a 210 mutex_unlock(&aoechr_mutex);
1da177e4
LT
211 return -EINVAL;
212}
213
214static int
215aoechr_rel(struct inode *inode, struct file *filp)
216{
217 return 0;
218}
219
220static ssize_t
221aoechr_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;
cf446f0d
EC
230 if (n != MINOR_ERR)
231 return -EFAULT;
232
233 spin_lock_irqsave(&emsgs_lock, flags);
1da177e4 234
cf446f0d
EC
235 for (;;) {
236 em = emsgs + emsgs_head_idx;
237 if ((em->flags & EMFL_VALID) != 0)
238 break;
239 if (filp->f_flags & O_NDELAY) {
1da177e4 240 spin_unlock_irqrestore(&emsgs_lock, flags);
cf446f0d
EC
241 return -EAGAIN;
242 }
243 nblocked_emsgs_readers++;
244
245 spin_unlock_irqrestore(&emsgs_lock, flags);
1da177e4 246
24879a8e 247 n = wait_for_completion_interruptible(&emsgs_comp);
1da177e4 248
cf446f0d 249 spin_lock_irqsave(&emsgs_lock, flags);
1da177e4 250
cf446f0d 251 nblocked_emsgs_readers--;
1da177e4 252
cf446f0d 253 if (n) {
1da177e4 254 spin_unlock_irqrestore(&emsgs_lock, flags);
cf446f0d 255 return -ERESTARTSYS;
1da177e4 256 }
cf446f0d
EC
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;
1da177e4 266
cf446f0d
EC
267 emsgs_head_idx++;
268 emsgs_head_idx %= ARRAY_SIZE(emsgs);
1da177e4 269
cf446f0d 270 spin_unlock_irqrestore(&emsgs_lock, flags);
1da177e4 271
cf446f0d
EC
272 n = copy_to_user(buf, mp, len);
273 kfree(mp);
274 return n == 0 ? len : -EFAULT;
1da177e4
LT
275}
276
2b8693c0 277static const struct file_operations aoe_fops = {
1da177e4
LT
278 .write = aoechr_write,
279 .read = aoechr_read,
280 .open = aoechr_open,
281 .release = aoechr_rel,
282 .owner = THIS_MODULE,
6038f373 283 .llseek = noop_llseek,
1da177e4
LT
284};
285
286int __init
287aoechr_init(void)
288{
289 int n, i;
290
291 n = register_chrdev(AOE_MAJOR, "aoechr", &aoe_fops);
a04b41cd 292 if (n < 0) {
a12c93f0 293 printk(KERN_ERR "aoe: can't register char device\n");
1da177e4
LT
294 return n;
295 }
24879a8e 296 init_completion(&emsgs_comp);
1da177e4 297 spin_lock_init(&emsgs_lock);
65d7a37d
IO
298 n = class_register(&aoe_class);
299 if (n) {
1da177e4 300 unregister_chrdev(AOE_MAJOR, "aoechr");
65d7a37d 301 return n;
1da177e4 302 }
1ce8a0d3 303
1da177e4 304 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
65d7a37d 305 device_create(&aoe_class, NULL,
1ff9f542
GKH
306 MKDEV(AOE_MAJOR, chardevs[i].minor), NULL,
307 chardevs[i].name);
1da177e4
LT
308
309 return 0;
310}
311
312void
313aoechr_exit(void)
314{
315 int i;
316
317 for (i = 0; i < ARRAY_SIZE(chardevs); ++i)
65d7a37d
IO
318 device_destroy(&aoe_class, MKDEV(AOE_MAJOR, chardevs[i].minor));
319 class_unregister(&aoe_class);
1da177e4
LT
320 unregister_chrdev(AOE_MAJOR, "aoechr");
321}
322