Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
blacklist.c
Go to the documentation of this file.
1 /*
2  * S/390 common I/O routines -- blacklisting of specific devices
3  *
4  * Copyright IBM Corp. 1999, 2002
5  * Author(s): Ingo Adlung ([email protected])
6  * Cornelia Huck ([email protected])
7  * Arnd Bergmann ([email protected])
8  */
9 
10 #define KMSG_COMPONENT "cio"
11 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt
12 
13 #include <linux/init.h>
14 #include <linux/vmalloc.h>
15 #include <linux/proc_fs.h>
16 #include <linux/seq_file.h>
17 #include <linux/ctype.h>
18 #include <linux/device.h>
19 
20 #include <asm/cio.h>
21 #include <asm/uaccess.h>
22 
23 #include "blacklist.h"
24 #include "cio.h"
25 #include "cio_debug.h"
26 #include "css.h"
27 #include "device.h"
28 
29 /*
30  * "Blacklisting" of certain devices:
31  * Device numbers given in the commandline as cio_ignore=... won't be known
32  * to Linux.
33  *
34  * These can be single devices or ranges of devices
35  */
36 
37 /* 65536 bits for each set to indicate if a devno is blacklisted or not */
38 #define __BL_DEV_WORDS ((__MAX_SUBCHANNEL + (8*sizeof(long) - 1)) / \
39  (8*sizeof(long)))
40 static unsigned long bl_dev[__MAX_SSID + 1][__BL_DEV_WORDS];
41 typedef enum {add, free} range_action;
42 
43 /*
44  * Function: blacklist_range
45  * (Un-)blacklist the devices from-to
46  */
47 static int blacklist_range(range_action action, unsigned int from_ssid,
48  unsigned int to_ssid, unsigned int from,
49  unsigned int to, int msgtrigger)
50 {
51  if ((from_ssid > to_ssid) || ((from_ssid == to_ssid) && (from > to))) {
52  if (msgtrigger)
53  pr_warning("0.%x.%04x to 0.%x.%04x is not a valid "
54  "range for cio_ignore\n", from_ssid, from,
55  to_ssid, to);
56 
57  return 1;
58  }
59 
60  while ((from_ssid < to_ssid) || ((from_ssid == to_ssid) &&
61  (from <= to))) {
62  if (action == add)
63  set_bit(from, bl_dev[from_ssid]);
64  else
65  clear_bit(from, bl_dev[from_ssid]);
66  from++;
67  if (from > __MAX_SUBCHANNEL) {
68  from_ssid++;
69  from = 0;
70  }
71  }
72 
73  return 0;
74 }
75 
76 static int pure_hex(char **cp, unsigned int *val, int min_digit,
77  int max_digit, int max_val)
78 {
79  int diff;
80 
81  diff = 0;
82  *val = 0;
83 
84  while (diff <= max_digit) {
85  int value = hex_to_bin(**cp);
86 
87  if (value < 0)
88  break;
89  *val = *val * 16 + value;
90  (*cp)++;
91  diff++;
92  }
93 
94  if ((diff < min_digit) || (diff > max_digit) || (*val > max_val))
95  return 1;
96 
97  return 0;
98 }
99 
100 static int parse_busid(char *str, unsigned int *cssid, unsigned int *ssid,
101  unsigned int *devno, int msgtrigger)
102 {
103  char *str_work;
104  int val, rc, ret;
105 
106  rc = 1;
107 
108  if (*str == '\0')
109  goto out;
110 
111  /* old style */
112  str_work = str;
113  val = simple_strtoul(str, &str_work, 16);
114 
115  if (*str_work == '\0') {
116  if (val <= __MAX_SUBCHANNEL) {
117  *devno = val;
118  *ssid = 0;
119  *cssid = 0;
120  rc = 0;
121  }
122  goto out;
123  }
124 
125  /* new style */
126  str_work = str;
127  ret = pure_hex(&str_work, cssid, 1, 2, __MAX_CSSID);
128  if (ret || (str_work[0] != '.'))
129  goto out;
130  str_work++;
131  ret = pure_hex(&str_work, ssid, 1, 1, __MAX_SSID);
132  if (ret || (str_work[0] != '.'))
133  goto out;
134  str_work++;
135  ret = pure_hex(&str_work, devno, 4, 4, __MAX_SUBCHANNEL);
136  if (ret || (str_work[0] != '\0'))
137  goto out;
138 
139  rc = 0;
140 out:
141  if (rc && msgtrigger)
142  pr_warning("%s is not a valid device for the cio_ignore "
143  "kernel parameter\n", str);
144 
145  return rc;
146 }
147 
148 static int blacklist_parse_parameters(char *str, range_action action,
149  int msgtrigger)
150 {
151  unsigned int from_cssid, to_cssid, from_ssid, to_ssid, from, to;
152  int rc, totalrc;
153  char *parm;
155 
156  totalrc = 0;
157 
158  while ((parm = strsep(&str, ","))) {
159  rc = 0;
160  ra = action;
161  if (*parm == '!') {
162  if (ra == add)
163  ra = free;
164  else
165  ra = add;
166  parm++;
167  }
168  if (strcmp(parm, "all") == 0) {
169  from_cssid = 0;
170  from_ssid = 0;
171  from = 0;
172  to_cssid = __MAX_CSSID;
173  to_ssid = __MAX_SSID;
174  to = __MAX_SUBCHANNEL;
175  } else {
176  rc = parse_busid(strsep(&parm, "-"), &from_cssid,
177  &from_ssid, &from, msgtrigger);
178  if (!rc) {
179  if (parm != NULL)
180  rc = parse_busid(parm, &to_cssid,
181  &to_ssid, &to,
182  msgtrigger);
183  else {
184  to_cssid = from_cssid;
185  to_ssid = from_ssid;
186  to = from;
187  }
188  }
189  }
190  if (!rc) {
191  rc = blacklist_range(ra, from_ssid, to_ssid, from, to,
192  msgtrigger);
193  if (rc)
194  totalrc = -EINVAL;
195  } else
196  totalrc = -EINVAL;
197  }
198 
199  return totalrc;
200 }
201 
202 static int __init
203 blacklist_setup (char *str)
204 {
205  CIO_MSG_EVENT(6, "Reading blacklist parameters\n");
206  if (blacklist_parse_parameters(str, add, 1))
207  return 0;
208  return 1;
209 }
210 
211 __setup ("cio_ignore=", blacklist_setup);
212 
213 /* Checking if devices are blacklisted */
214 
215 /*
216  * Function: is_blacklisted
217  * Returns 1 if the given devicenumber can be found in the blacklist,
218  * otherwise 0.
219  * Used by validate_subchannel()
220  */
221 int
222 is_blacklisted (int ssid, int devno)
223 {
224  return test_bit (devno, bl_dev[ssid]);
225 }
226 
227 #ifdef CONFIG_PROC_FS
228 /*
229  * Function: blacklist_parse_proc_parameters
230  * parse the stuff which is piped to /proc/cio_ignore
231  */
232 static int blacklist_parse_proc_parameters(char *buf)
233 {
234  int rc;
235  char *parm;
236 
237  parm = strsep(&buf, " ");
238 
239  if (strcmp("free", parm) == 0)
240  rc = blacklist_parse_parameters(buf, free, 0);
241  else if (strcmp("add", parm) == 0)
242  rc = blacklist_parse_parameters(buf, add, 0);
243  else if (strcmp("purge", parm) == 0)
244  return ccw_purge_blacklisted();
245  else
246  return -EINVAL;
247 
249 
250  return rc;
251 }
252 
253 /* Iterator struct for all devices. */
254 struct ccwdev_iter {
255  int devno;
256  int ssid;
257  int in_range;
258 };
259 
260 static void *
261 cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
262 {
263  struct ccwdev_iter *iter = s->private;
264 
265  if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
266  return NULL;
267  memset(iter, 0, sizeof(*iter));
268  iter->ssid = *offset / (__MAX_SUBCHANNEL + 1);
269  iter->devno = *offset % (__MAX_SUBCHANNEL + 1);
270  return iter;
271 }
272 
273 static void
274 cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
275 {
276 }
277 
278 static void *
279 cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
280 {
281  struct ccwdev_iter *iter;
282 
283  if (*offset >= (__MAX_SUBCHANNEL + 1) * (__MAX_SSID + 1))
284  return NULL;
285  iter = it;
286  if (iter->devno == __MAX_SUBCHANNEL) {
287  iter->devno = 0;
288  iter->ssid++;
289  if (iter->ssid > __MAX_SSID)
290  return NULL;
291  } else
292  iter->devno++;
293  (*offset)++;
294  return iter;
295 }
296 
297 static int
298 cio_ignore_proc_seq_show(struct seq_file *s, void *it)
299 {
300  struct ccwdev_iter *iter;
301 
302  iter = it;
303  if (!is_blacklisted(iter->ssid, iter->devno))
304  /* Not blacklisted, nothing to output. */
305  return 0;
306  if (!iter->in_range) {
307  /* First device in range. */
308  if ((iter->devno == __MAX_SUBCHANNEL) ||
309  !is_blacklisted(iter->ssid, iter->devno + 1))
310  /* Singular device. */
311  return seq_printf(s, "0.%x.%04x\n",
312  iter->ssid, iter->devno);
313  iter->in_range = 1;
314  return seq_printf(s, "0.%x.%04x-", iter->ssid, iter->devno);
315  }
316  if ((iter->devno == __MAX_SUBCHANNEL) ||
317  !is_blacklisted(iter->ssid, iter->devno + 1)) {
318  /* Last device in range. */
319  iter->in_range = 0;
320  return seq_printf(s, "0.%x.%04x\n", iter->ssid, iter->devno);
321  }
322  return 0;
323 }
324 
325 static ssize_t
326 cio_ignore_write(struct file *file, const char __user *user_buf,
327  size_t user_len, loff_t *offset)
328 {
329  char *buf;
330  ssize_t rc, ret, i;
331 
332  if (*offset)
333  return -EINVAL;
334  if (user_len > 65536)
335  user_len = 65536;
336  buf = vzalloc(user_len + 1); /* maybe better use the stack? */
337  if (buf == NULL)
338  return -ENOMEM;
339 
340  if (strncpy_from_user (buf, user_buf, user_len) < 0) {
341  rc = -EFAULT;
342  goto out_free;
343  }
344 
345  i = user_len - 1;
346  while ((i >= 0) && (isspace(buf[i]) || (buf[i] == 0))) {
347  buf[i] = '\0';
348  i--;
349  }
350  ret = blacklist_parse_proc_parameters(buf);
351  if (ret)
352  rc = ret;
353  else
354  rc = user_len;
355 
356 out_free:
357  vfree (buf);
358  return rc;
359 }
360 
361 static const struct seq_operations cio_ignore_proc_seq_ops = {
362  .start = cio_ignore_proc_seq_start,
363  .stop = cio_ignore_proc_seq_stop,
364  .next = cio_ignore_proc_seq_next,
365  .show = cio_ignore_proc_seq_show,
366 };
367 
368 static int
369 cio_ignore_proc_open(struct inode *inode, struct file *file)
370 {
371  return seq_open_private(file, &cio_ignore_proc_seq_ops,
372  sizeof(struct ccwdev_iter));
373 }
374 
375 static const struct file_operations cio_ignore_proc_fops = {
376  .open = cio_ignore_proc_open,
377  .read = seq_read,
378  .llseek = seq_lseek,
379  .release = seq_release_private,
380  .write = cio_ignore_write,
381 };
382 
383 static int
384 cio_ignore_proc_init (void)
385 {
386  struct proc_dir_entry *entry;
387 
388  entry = proc_create("cio_ignore", S_IFREG | S_IRUGO | S_IWUSR, NULL,
389  &cio_ignore_proc_fops);
390  if (!entry)
391  return -ENOENT;
392  return 0;
393 }
394 
395 __initcall (cio_ignore_proc_init);
396 
397 #endif /* CONFIG_PROC_FS */