aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/scsi_proc.c
diff options
context:
space:
mode:
authorJeff Mahoney <jeffm@suse.com>2011-04-27 16:22:20 -0400
committerJames Bottomley <James.Bottomley@suse.de>2011-05-01 14:04:02 -0400
commite37c4913c555bd149eba3af953fb5d3a1686dfbd (patch)
treeba9fbba3ba75f4a1153825c7833f977f8c6d50c6 /drivers/scsi/scsi_proc.c
parent9c324b8ba8e3ee8772a0c716d557e1582699d481 (diff)
[SCSI] iterate over devices individually for /proc/scsi/scsi
On systems with very large numbers (> 1600 or so) of SCSI devices, cat /proc/scsi/scsi ends up failing with -ENOMEM. This is due to the show routine simply iterating over all of the devices with bus_for_each_dev(), and trying to dump all of them into the buffer at the same time. On my test system (using scsi_debug with 4064 devices), the output ends up being ~ 632k, far more than kmalloc will typically allow. This patch defines its own seq_file opreations to iterate over the scsi devices.The result is that each show() operation only dumps ~ 180 bytes into the buffer at a time so we don't run out of memory. If the "Attached devices" header isn't required, we can dump the sfile->private bit completely. Signed-off-by: Jeff Mahoney <jeffm@suse.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
Diffstat (limited to 'drivers/scsi/scsi_proc.c')
-rw-r--r--drivers/scsi/scsi_proc.c58
1 files changed, 52 insertions, 6 deletions
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index c99da926fdac..f46855cd853d 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
386 * @s: output goes here 386 * @s: output goes here
387 * @p: not used 387 * @p: not used
388 */ 388 */
389static int proc_scsi_show(struct seq_file *s, void *p) 389static int always_match(struct device *dev, void *data)
390{ 390{
391 seq_printf(s, "Attached devices:\n"); 391 return 1;
392 bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); 392}
393 return 0; 393
394static inline struct device *next_scsi_device(struct device *start)
395{
396 struct device *next = bus_find_device(&scsi_bus_type, start, NULL,
397 always_match);
398 put_device(start);
399 return next;
394} 400}
395 401
402static void *scsi_seq_start(struct seq_file *sfile, loff_t *pos)
403{
404 struct device *dev = NULL;
405 loff_t n = *pos;
406
407 while ((dev = next_scsi_device(dev))) {
408 if (!n--)
409 break;
410 sfile->private++;
411 }
412 return dev;
413}
414
415static void *scsi_seq_next(struct seq_file *sfile, void *v, loff_t *pos)
416{
417 (*pos)++;
418 sfile->private++;
419 return next_scsi_device(v);
420}
421
422static void scsi_seq_stop(struct seq_file *sfile, void *v)
423{
424 put_device(v);
425}
426
427static int scsi_seq_show(struct seq_file *sfile, void *dev)
428{
429 if (!sfile->private)
430 seq_puts(sfile, "Attached devices:\n");
431
432 return proc_print_scsidevice(dev, sfile);
433}
434
435static const struct seq_operations scsi_seq_ops = {
436 .start = scsi_seq_start,
437 .next = scsi_seq_next,
438 .stop = scsi_seq_stop,
439 .show = scsi_seq_show
440};
441
396/** 442/**
397 * proc_scsi_open - glue function 443 * proc_scsi_open - glue function
398 * @inode: not used 444 * @inode: not used
@@ -406,7 +452,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file)
406 * We don't really need this for the write case but it doesn't 452 * We don't really need this for the write case but it doesn't
407 * harm either. 453 * harm either.
408 */ 454 */
409 return single_open(file, proc_scsi_show, NULL); 455 return seq_open(file, &scsi_seq_ops);
410} 456}
411 457
412static const struct file_operations proc_scsi_operations = { 458static const struct file_operations proc_scsi_operations = {
@@ -415,7 +461,7 @@ static const struct file_operations proc_scsi_operations = {
415 .read = seq_read, 461 .read = seq_read,
416 .write = proc_scsi_write, 462 .write = proc_scsi_write,
417 .llseek = seq_lseek, 463 .llseek = seq_lseek,
418 .release = single_release, 464 .release = seq_release,
419}; 465};
420 466
421/** 467/**