mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 06:31:49 +00:00
[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>
This commit is contained in:
parent
9c324b8ba8
commit
e37c4913c5
@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
|
||||
* @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 const 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 *inode, struct file *file)
|
||||
* 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_scsi_operations = {
|
||||
.read = seq_read,
|
||||
.write = proc_scsi_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
.release = seq_release,
|
||||
};
|
||||
|
||||
/**
|
||||
|
Loading…
Reference in New Issue
Block a user