Commit ab4a802e authored by Alexander Viro's avatar Alexander Viro Committed by Linus Torvalds

[PATCH] Avoid /proc/{ioports,iomem} truncation

The current seq_file code for resource handling will truncate the output
if it overflows the seq_file buffer (one page).  That's because it tries
to traverse the resource tree in one big blob.

So change that to instead traverse the resource tree one entry at a time
and have a real iterator, and clean it up a bit.
parent abd184cb
...@@ -38,75 +38,91 @@ static rwlock_t resource_lock = RW_LOCK_UNLOCKED; ...@@ -38,75 +38,91 @@ static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
#define MAX_IORES_LEVEL 5 enum { MAX_IORES_LEVEL = 5 };
/* static void *r_next(struct seq_file *m, void *v, loff_t *pos)
* do_resource_list():
* for reports of /proc/ioports and /proc/iomem;
* do current entry, then children, then siblings;
*/
static int do_resource_list(struct seq_file *m, struct resource *res, const char *fmt, int level)
{ {
while (res) { struct resource *p = v;
const char *name; (*pos)++;
if (p->child)
name = res->name ? res->name : "<BAD>"; return p->child;
if (level > MAX_IORES_LEVEL) while (!p->sibling && p->parent)
level = MAX_IORES_LEVEL; p = p->parent;
seq_printf (m, fmt + 2 * MAX_IORES_LEVEL - 2 * level, return p->sibling;
res->start, res->end, name); }
if (res->child)
do_resource_list(m, res->child, fmt, level + 1);
res = res->sibling; static void *r_start(struct seq_file *m, loff_t *pos)
} {
struct resource *p = m->private;
loff_t l = 0;
read_lock(&resource_lock);
for (p = p->child; p && l < *pos; p = r_next(m, p, &l))
;
return p;
}
return 0; static void r_stop(struct seq_file *m, void *v)
{
read_unlock(&resource_lock);
} }
static int ioresources_show(struct seq_file *m, void *v) static int r_show(struct seq_file *m, void *v)
{ {
struct resource *root = m->private; struct resource *root = m->private;
char *fmt; struct resource *r = v, *p;
int retval; int width = root->end < 0x10000 ? 4 : 8;
int depth;
fmt = root->end < 0x10000 for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
? " %04lx-%04lx : %s\n" if (p->parent == root)
: " %08lx-%08lx : %s\n"; break;
read_lock(&resource_lock); seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
retval = do_resource_list(m, root->child, fmt, 0); depth * 2, "",
read_unlock(&resource_lock); width, r->start,
return retval; width, r->end,
r->name ? r->name : "<BAD>");
return 0;
} }
static int ioresources_open(struct file *file, struct resource *root) struct seq_operations resource_op = {
.start = r_start,
.next = r_next,
.stop = r_stop,
.show = r_show,
};
static int ioports_open(struct inode *inode, struct file *file)
{ {
return single_open(file, ioresources_show, root); int res = seq_open(file, &resource_op);
if (!res) {
struct seq_file *m = file->private_data;
m->private = &ioport_resource;
}
return res;
} }
static int ioports_open(struct inode *inode, struct file *file) static int iomem_open(struct inode *inode, struct file *file)
{ {
return ioresources_open(file, &ioport_resource); int res = seq_open(file, &resource_op);
if (!res) {
struct seq_file *m = file->private_data;
m->private = &iomem_resource;
}
return res;
} }
static struct file_operations proc_ioports_operations = { static struct file_operations proc_ioports_operations = {
.open = ioports_open, .open = ioports_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = single_release, .release = seq_release,
}; };
static int iomem_open(struct inode *inode, struct file *file)
{
return ioresources_open(file, &iomem_resource);
}
static struct file_operations proc_iomem_operations = { static struct file_operations proc_iomem_operations = {
.open = iomem_open, .open = iomem_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
.release = single_release, .release = seq_release,
}; };
static int __init ioresources_init(void) static int __init ioresources_init(void)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment