scsi: iterate over devices individually for /proc/scsi/scsi
PATCH 1/1 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.
---
drivers/scsi/scsi_proc.c | 58 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 52 insertions(+), 6 deletions(-)
drivers/scsi/scsi_proc.c +52 -6
@@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct fi* @s: output goes here * @p: not used */ -static int proc_scsi_show (struct seq_file *s,void *p) +static int always_match (struct device *dev,void *data) { -seq_printf (s,"Attached devices:\n" ); -bus_for_each_dev (&scsi_bus_type,NULL , s, proc_print_scsidevice); -return 0 ; +return 1 ; } +static inline struct device *next_scsi_device (struct device *start) +{ +struct device *next =bus_find_device (&scsi_bus_type, start,NULL , + always_match); +put_device (start); +return next; +} + +static void *scsi_seq_start (struct seq_file *sfile,loff_t *pos) +{ +struct device *dev =NULL ; +loff_t n = *pos; + +while ((dev =next_scsi_device (dev))) { +if (!n--) +break ; + sfile->private++; + } +return dev; +} + +static void *scsi_seq_next (struct seq_file *sfile,void *v,loff_t *pos) +{ + (*pos)++; + sfile->private++; +return next_scsi_device (v); +} + +static void scsi_seq_stop (struct seq_file *sfile,void *v) +{ +put_device (v); +} + +static int scsi_seq_show (struct seq_file *sfile,void *dev) +{ +if (!sfile->private) +seq_puts (sfile,"Attached devices:\n" ); + +return proc_print_scsidevice (dev, sfile); +} + +static struct seq_operations scsi_seq_ops = { + .start = scsi_seq_start, + .next = scsi_seq_next, + .stop = scsi_seq_stop, + .show = scsi_seq_show +}; +/** * proc_scsi_open - glue function * @inode: not used
@@ -406,7 +452,7 @@ static int proc_scsi_open(struct inode ** We don't really need this for the write case but it doesn't * harm either. */ -return single_open (file, proc_scsi_show,NULL ); +return seq_open (file, &scsi_seq_ops); }static const struct file_operations proc_scsi_operations = {
@@ -415,7 +461,7 @@ static const struct file_operations proc .read = seq_read, .write = proc_scsi_write, .llseek = seq_lseek, - .release = single_release, + .release = seq_release, };/**
Signature · 2 lines
Jeff Mahoney SUSE Labs