diff options
author | Alexey Dobriyan <adobriyan@sw.ru> | 2008-04-29 04:01:55 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-29 11:06:19 -0400 |
commit | 352ced8e594091d74b92da9bcf07aea81d37ac55 (patch) | |
tree | a0e5f67be54a2d1138837787fc126e6807156418 /drivers/scsi | |
parent | 4a5cdb5b8f10998603e1e44adec1e56c234babfe (diff) |
proc: switch /proc/scsi/device_info to seq_file interface
Note 1: 0644 should be used, but root bypasses permissions, so writing
to /proc/scsi/device_info still works.
Note 2: looks like scsi_dev_info_list is unprotected
Note 3: probably make proc whine about "unwriteable but with ->write hook"
entries. Probably.
Signed-off-by: Alexey Dobriyan <adobriyan@sw.ru>
Cc: James Bottomley <James.Bottomley@SteelEye.com>
Cc: Mike Christie <michaelc@cs.wisc.edu>
Cc: Matthew Wilcox <matthew@wil.cx>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/scsi')
-rw-r--r-- | drivers/scsi/scsi_devinfo.c | 77 |
1 files changed, 44 insertions, 33 deletions
diff --git a/drivers/scsi/scsi_devinfo.c b/drivers/scsi/scsi_devinfo.c index b8de041bc0ae..a235802f2981 100644 --- a/drivers/scsi/scsi_devinfo.c +++ b/drivers/scsi/scsi_devinfo.c | |||
@@ -449,37 +449,40 @@ int scsi_get_device_flags(struct scsi_device *sdev, | |||
449 | } | 449 | } |
450 | 450 | ||
451 | #ifdef CONFIG_SCSI_PROC_FS | 451 | #ifdef CONFIG_SCSI_PROC_FS |
452 | /* | 452 | static int devinfo_seq_show(struct seq_file *m, void *v) |
453 | * proc_scsi_dev_info_read: dump the scsi_dev_info_list via | ||
454 | * /proc/scsi/device_info | ||
455 | */ | ||
456 | static int proc_scsi_devinfo_read(char *buffer, char **start, | ||
457 | off_t offset, int length) | ||
458 | { | 453 | { |
459 | struct scsi_dev_info_list *devinfo; | 454 | struct scsi_dev_info_list *devinfo = |
460 | int size, len = 0; | 455 | list_entry(v, struct scsi_dev_info_list, dev_info_list); |
461 | off_t begin = 0; | ||
462 | off_t pos = 0; | ||
463 | 456 | ||
464 | list_for_each_entry(devinfo, &scsi_dev_info_list, dev_info_list) { | 457 | seq_printf(m, "'%.8s' '%.16s' 0x%x\n", |
465 | size = sprintf(buffer + len, "'%.8s' '%.16s' 0x%x\n", | ||
466 | devinfo->vendor, devinfo->model, devinfo->flags); | 458 | devinfo->vendor, devinfo->model, devinfo->flags); |
467 | len += size; | 459 | return 0; |
468 | pos = begin + len; | 460 | } |
469 | if (pos < offset) { | 461 | |
470 | len = 0; | 462 | static void * devinfo_seq_start(struct seq_file *m, loff_t *pos) |
471 | begin = pos; | 463 | { |
472 | } | 464 | return seq_list_start(&scsi_dev_info_list, *pos); |
473 | if (pos > offset + length) | 465 | } |
474 | goto stop_output; | ||
475 | } | ||
476 | 466 | ||
477 | stop_output: | 467 | static void * devinfo_seq_next(struct seq_file *m, void *v, loff_t *pos) |
478 | *start = buffer + (offset - begin); /* Start of wanted data */ | 468 | { |
479 | len -= (offset - begin); /* Start slop */ | 469 | return seq_list_next(v, &scsi_dev_info_list, pos); |
480 | if (len > length) | 470 | } |
481 | len = length; /* Ending slop */ | 471 | |
482 | return (len); | 472 | static void devinfo_seq_stop(struct seq_file *m, void *v) |
473 | { | ||
474 | } | ||
475 | |||
476 | static const struct seq_operations scsi_devinfo_seq_ops = { | ||
477 | .start = devinfo_seq_start, | ||
478 | .next = devinfo_seq_next, | ||
479 | .stop = devinfo_seq_stop, | ||
480 | .show = devinfo_seq_show, | ||
481 | }; | ||
482 | |||
483 | static int proc_scsi_devinfo_open(struct inode *inode, struct file *file) | ||
484 | { | ||
485 | return seq_open(file, &scsi_devinfo_seq_ops); | ||
483 | } | 486 | } |
484 | 487 | ||
485 | /* | 488 | /* |
@@ -489,11 +492,12 @@ stop_output: | |||
489 | * integer value of flag to the scsi device info list. | 492 | * integer value of flag to the scsi device info list. |
490 | * To use, echo "vendor:model:flag" > /proc/scsi/device_info | 493 | * To use, echo "vendor:model:flag" > /proc/scsi/device_info |
491 | */ | 494 | */ |
492 | static int proc_scsi_devinfo_write(struct file *file, const char __user *buf, | 495 | static ssize_t proc_scsi_devinfo_write(struct file *file, |
493 | unsigned long length, void *data) | 496 | const char __user *buf, |
497 | size_t length, loff_t *ppos) | ||
494 | { | 498 | { |
495 | char *buffer; | 499 | char *buffer; |
496 | int err = length; | 500 | ssize_t err = length; |
497 | 501 | ||
498 | if (!buf || length>PAGE_SIZE) | 502 | if (!buf || length>PAGE_SIZE) |
499 | return -EINVAL; | 503 | return -EINVAL; |
@@ -517,6 +521,15 @@ out: | |||
517 | free_page((unsigned long)buffer); | 521 | free_page((unsigned long)buffer); |
518 | return err; | 522 | return err; |
519 | } | 523 | } |
524 | |||
525 | static const struct file_operations scsi_devinfo_proc_fops = { | ||
526 | .owner = THIS_MODULE, | ||
527 | .open = proc_scsi_devinfo_open, | ||
528 | .read = seq_read, | ||
529 | .write = proc_scsi_devinfo_write, | ||
530 | .llseek = seq_lseek, | ||
531 | .release = seq_release, | ||
532 | }; | ||
520 | #endif /* CONFIG_SCSI_PROC_FS */ | 533 | #endif /* CONFIG_SCSI_PROC_FS */ |
521 | 534 | ||
522 | module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); | 535 | module_param_string(dev_flags, scsi_dev_flags, sizeof(scsi_dev_flags), 0); |
@@ -577,15 +590,13 @@ int __init scsi_init_devinfo(void) | |||
577 | } | 590 | } |
578 | 591 | ||
579 | #ifdef CONFIG_SCSI_PROC_FS | 592 | #ifdef CONFIG_SCSI_PROC_FS |
580 | p = create_proc_entry("scsi/device_info", 0, NULL); | 593 | p = proc_create("scsi/device_info", 0, NULL, &scsi_devinfo_proc_fops); |
581 | if (!p) { | 594 | if (!p) { |
582 | error = -ENOMEM; | 595 | error = -ENOMEM; |
583 | goto out; | 596 | goto out; |
584 | } | 597 | } |
585 | 598 | ||
586 | p->owner = THIS_MODULE; | 599 | p->owner = THIS_MODULE; |
587 | p->get_info = proc_scsi_devinfo_read; | ||
588 | p->write_proc = proc_scsi_devinfo_write; | ||
589 | #endif /* CONFIG_SCSI_PROC_FS */ | 600 | #endif /* CONFIG_SCSI_PROC_FS */ |
590 | 601 | ||
591 | out: | 602 | out: |