summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
authorAlexander Viro <viro@parcelfarce.linux.theplanet.co.uk>2003-09-24 01:09:48 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-09-24 01:09:48 -0700
commitab4a802e409fcec8983eeb194b6a8145d00b7b17 (patch)
treed8f58cd5ace1da71b046b040326c5ad44a751c89 /kernel
parentabd184cb4bf6fcb965c4aafab88e26ef6a46ccec (diff)
[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.
Diffstat (limited to 'kernel')
-rw-r--r--kernel/resource.c100
1 files changed, 58 insertions, 42 deletions
diff --git a/kernel/resource.c b/kernel/resource.c
index 58fdf2c88b32..f8ce88129fd2 100644
--- a/kernel/resource.c
+++ b/kernel/resource.c
@@ -38,75 +38,91 @@ static rwlock_t resource_lock = RW_LOCK_UNLOCKED;
#ifdef CONFIG_PROC_FS
-#define MAX_IORES_LEVEL 5
+enum { MAX_IORES_LEVEL = 5 };
-/*
- * 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)
+static void *r_next(struct seq_file *m, void *v, loff_t *pos)
{
- while (res) {
- const char *name;
-
- name = res->name ? res->name : "<BAD>";
- if (level > MAX_IORES_LEVEL)
- level = MAX_IORES_LEVEL;
- seq_printf (m, fmt + 2 * MAX_IORES_LEVEL - 2 * level,
- res->start, res->end, name);
-
- if (res->child)
- do_resource_list(m, res->child, fmt, level + 1);
+ struct resource *p = v;
+ (*pos)++;
+ if (p->child)
+ return p->child;
+ while (!p->sibling && p->parent)
+ p = p->parent;
+ return p->sibling;
+}
- 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;
- char *fmt;
- int retval;
+ struct resource *r = v, *p;
+ int width = root->end < 0x10000 ? 4 : 8;
+ int depth;
- fmt = root->end < 0x10000
- ? " %04lx-%04lx : %s\n"
- : " %08lx-%08lx : %s\n";
- read_lock(&resource_lock);
- retval = do_resource_list(m, root->child, fmt, 0);
- read_unlock(&resource_lock);
- return retval;
+ for (depth = 0, p = r; depth < MAX_IORES_LEVEL; depth++, p = p->parent)
+ if (p->parent == root)
+ break;
+ seq_printf(m, "%*s%0*lx-%0*lx : %s\n",
+ depth * 2, "",
+ width, r->start,
+ 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 = {
.open = ioports_open,
.read = seq_read,
.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 = {
.open = iomem_open,
.read = seq_read,
.llseek = seq_lseek,
- .release = single_release,
+ .release = seq_release,
};
static int __init ioresources_init(void)