提交 e37c4913 编写于 作者: J Jeff Mahoney 提交者: James Bottomley

[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: NJeff Mahoney <jeffm@suse.com>
Signed-off-by: NJames Bottomley <James.Bottomley@suse.de>
上级 9c324b8b
...@@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf, ...@@ -386,13 +386,59 @@ static ssize_t proc_scsi_write(struct file *file, const char __user *buf,
* @s: output goes here * @s: output goes here
* @p: not used * @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"); return 1;
bus_for_each_dev(&scsi_bus_type, NULL, s, proc_print_scsidevice); }
return 0;
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 * proc_scsi_open - glue function
* @inode: not used * @inode: not used
...@@ -406,7 +452,7 @@ static int proc_scsi_open(struct inode *inode, struct file *file) ...@@ -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 * We don't really need this for the write case but it doesn't
* harm either. * 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 = { static const struct file_operations proc_scsi_operations = {
...@@ -415,7 +461,7 @@ static const struct file_operations proc_scsi_operations = { ...@@ -415,7 +461,7 @@ static const struct file_operations proc_scsi_operations = {
.read = seq_read, .read = seq_read,
.write = proc_scsi_write, .write = proc_scsi_write,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = single_release, .release = seq_release,
}; };
/** /**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册