aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/s390/cio/blacklist.c122
1 files changed, 92 insertions, 30 deletions
diff --git a/drivers/s390/cio/blacklist.c b/drivers/s390/cio/blacklist.c
index 25e98483d4e..daea41c6332 100644
--- a/drivers/s390/cio/blacklist.c
+++ b/drivers/s390/cio/blacklist.c
@@ -15,6 +15,7 @@
15#include <linux/vmalloc.h> 15#include <linux/vmalloc.h>
16#include <linux/slab.h> 16#include <linux/slab.h>
17#include <linux/proc_fs.h> 17#include <linux/proc_fs.h>
18#include <linux/seq_file.h>
18#include <linux/ctype.h> 19#include <linux/ctype.h>
19#include <linux/device.h> 20#include <linux/device.h>
20 21
@@ -279,41 +280,82 @@ blacklist_parse_proc_parameters (char *buf)
279 s390_redo_validation (); 280 s390_redo_validation ();
280} 281}
281 282
282/* FIXME: These should be real bus ids and not home-grown ones! */ 283/* Iterator struct for all devices. */
283static int cio_ignore_read (char *page, char **start, off_t off, 284struct ccwdev_iter {
284 int count, int *eof, void *data) 285 int devno;
286 int in_range;
287};
288
289static void *
290cio_ignore_proc_seq_start(struct seq_file *s, loff_t *offset)
285{ 291{
286 const unsigned int entry_size = 18; /* "0.0.ABCD-0.0.EFGH\n" */ 292 struct ccwdev_iter *iter;
287 long devno; 293
288 int len; 294 if (*offset > __MAX_SUBCHANNEL)
289 295 return NULL;
290 len = 0; 296 iter = kmalloc(sizeof(struct ccwdev_iter), GFP_KERNEL);
291 for (devno = off; /* abuse the page variable 297 if (!iter)
292 * as counter, see fs/proc/generic.c */ 298 return ERR_PTR(-ENOMEM);
293 devno < __MAX_SUBCHANNEL && len + entry_size < count; devno++) { 299 memset(iter, 0, sizeof(struct ccwdev_iter));
294 if (!test_bit(devno, bl_dev)) 300 iter->devno = *offset;
295 continue; 301 return iter;
296 len += sprintf(page + len, "0.0.%04lx", devno); 302}
297 if (test_bit(devno + 1, bl_dev)) { /* print range */ 303
298 while (++devno < __MAX_SUBCHANNEL) 304static void
299 if (!test_bit(devno, bl_dev)) 305cio_ignore_proc_seq_stop(struct seq_file *s, void *it)
300 break; 306{
301 len += sprintf(page + len, "-0.0.%04lx", --devno); 307 if (!IS_ERR(it))
302 } 308 kfree(it);
303 len += sprintf(page + len, "\n"); 309}
304 }
305 310
306 if (devno < __MAX_SUBCHANNEL) 311static void *
307 *eof = 1; 312cio_ignore_proc_seq_next(struct seq_file *s, void *it, loff_t *offset)
308 *start = (char *) (devno - off); /* number of checked entries */ 313{
309 return len; 314 struct ccwdev_iter *iter;
315
316 if (*offset > __MAX_SUBCHANNEL)
317 return NULL;
318 iter = (struct ccwdev_iter *)it;
319 iter->devno++;
320 (*offset)++;
321 return iter;
310} 322}
311 323
312static int cio_ignore_write(struct file *file, const char __user *user_buf, 324static int
313 unsigned long user_len, void *data) 325cio_ignore_proc_seq_show(struct seq_file *s, void *it)
326{
327 struct ccwdev_iter *iter;
328
329 iter = (struct ccwdev_iter *)it;
330 if (!is_blacklisted(iter->devno))
331 /* Not blacklisted, nothing to output. */
332 return 0;
333 if (!iter->in_range) {
334 /* First device in range. */
335 if ((iter->devno == __MAX_SUBCHANNEL) ||
336 !is_blacklisted(iter->devno + 1))
337 /* Singular device. */
338 return seq_printf(s, "0.0.%04x\n", iter->devno);
339 iter->in_range = 1;
340 return seq_printf(s, "0.0.%04x-", iter->devno);
341 }
342 if ((iter->devno == __MAX_SUBCHANNEL) ||
343 !is_blacklisted(iter->devno + 1)) {
344 /* Last device in range. */
345 iter->in_range = 0;
346 return seq_printf(s, "0.0.%04x\n", iter->devno);
347 }
348 return 0;
349}
350
351static ssize_t
352cio_ignore_write(struct file *file, const char __user *user_buf,
353 size_t user_len, loff_t *offset)
314{ 354{
315 char *buf; 355 char *buf;
316 356
357 if (*offset)
358 return -EINVAL;
317 if (user_len > 65536) 359 if (user_len > 65536)
318 user_len = 65536; 360 user_len = 65536;
319 buf = vmalloc (user_len + 1); /* maybe better use the stack? */ 361 buf = vmalloc (user_len + 1); /* maybe better use the stack? */
@@ -331,6 +373,27 @@ static int cio_ignore_write(struct file *file, const char __user *user_buf,
331 return user_len; 373 return user_len;
332} 374}
333 375
376static struct seq_operations cio_ignore_proc_seq_ops = {
377 .start = cio_ignore_proc_seq_start,
378 .stop = cio_ignore_proc_seq_stop,
379 .next = cio_ignore_proc_seq_next,
380 .show = cio_ignore_proc_seq_show,
381};
382
383static int
384cio_ignore_proc_open(struct inode *inode, struct file *file)
385{
386 return seq_open(file, &cio_ignore_proc_seq_ops);
387}
388
389static struct file_operations cio_ignore_proc_fops = {
390 .open = cio_ignore_proc_open,
391 .read = seq_read,
392 .llseek = seq_lseek,
393 .release = seq_release,
394 .write = cio_ignore_write,
395};
396
334static int 397static int
335cio_ignore_proc_init (void) 398cio_ignore_proc_init (void)
336{ 399{
@@ -341,8 +404,7 @@ cio_ignore_proc_init (void)
341 if (!entry) 404 if (!entry)
342 return 0; 405 return 0;
343 406
344 entry->read_proc = cio_ignore_read; 407 entry->proc_fops = &cio_ignore_proc_fops;
345 entry->write_proc = cio_ignore_write;
346 408
347 return 1; 409 return 1;
348} 410}