aoe  87
About: AoE (ATA over Ethernet) Protocol Driver (Linux kernel 4.8.x and greater are not supported).
  Fossies Dox: aoe-87.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

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