diff options
author | Jeff Mahoney <jeffm@suse.com> | 2011-04-27 16:22:20 -0400 |
---|---|---|
committer | James Bottomley <James.Bottomley@suse.de> | 2011-05-01 14:04:02 -0400 |
commit | e37c4913c555bd149eba3af953fb5d3a1686dfbd (patch) | |
tree | ba9fbba3ba75f4a1153825c7833f977f8c6d50c6 /drivers/scsi/scsi_proc.c | |
parent | 9c324b8ba8e3ee8772a0c716d557e1582699d481 (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.c | 58 |
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 | */ |
389 | static int proc_scsi_show(struct seq_file *s, void *p) | 389 | static 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 | |
394 | static 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 | ||
402 | static 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 | |||
415 | static 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 | |||
422 | static void scsi_seq_stop(struct seq_file *sfile, void *v) | ||
423 | { | ||
424 | put_device(v); | ||
425 | } | ||
426 | |||
427 | static 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 | |||
435 | static 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 | ||
412 | static const struct file_operations proc_scsi_operations = { | 458 | static 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 | /** |