summaryrefslogtreecommitdiff
path: root/kernel/module.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:33:15 -0800
committerLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 20:33:15 -0800
commitd40d1af9f0aebf7e108f1dfb66ac5af671bc9719 (patch)
tree7a2518e82986a8eb5b4eb76553df04d8ba6e4642 /kernel/module.c
parenta8a2069f432c5597bdf9c83ab3045b9ef32ab5e3 (diff)
v2.4.14.2 -> v2.4.14.3
- Alan Cox: more driver merging - Al Viro: make ext2 group allocation more readable
Diffstat (limited to 'kernel/module.c')
-rw-r--r--kernel/module.c109
1 files changed, 71 insertions, 38 deletions
diff --git a/kernel/module.c b/kernel/module.c
index e246f49d0818..34bb9edaa2b3 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -9,6 +9,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/kmod.h>
+#include <linux/seq_file.h>
/*
* Originally by Anonymous (as far as I know...)
@@ -1156,52 +1157,84 @@ fini:
* Called by the /proc file system to return a current list of ksyms.
*/
-int
-get_ksyms_list(char *buf, char **start, off_t offset, int length)
-{
+struct mod_sym {
struct module *mod;
- char *p = buf;
- int len = 0; /* code from net/ipv4/proc.c */
- off_t pos = 0;
- off_t begin = 0;
+ int index;
+};
- for (mod = module_list; mod; mod = mod->next) {
- unsigned i;
- struct module_symbol *sym;
+/* iterator */
- if (!MOD_CAN_QUERY(mod))
- continue;
+static void *s_start(struct seq_file *m, loff_t *pos)
+{
+ struct mod_sym *p = kmalloc(sizeof(*p), GFP_KERNEL);
+ struct module *v;
+ loff_t n = *pos;
- for (i = mod->nsyms, sym = mod->syms; i > 0; --i, ++sym) {
- p = buf + len;
- if (*mod->name) {
- len += sprintf(p, "%0*lx %s\t[%s]\n",
- (int)(2*sizeof(void*)),
- sym->value, sym->name,
- mod->name);
- } else {
- len += sprintf(p, "%0*lx %s\n",
- (int)(2*sizeof(void*)),
- sym->value, sym->name);
- }
- pos = begin + len;
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- pos = begin + len;
- if (pos > offset+length)
- goto leave_the_loop;
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+ lock_kernel();
+ for (v = module_list, n = *pos; v; n -= v->nsyms, v = v->next) {
+ if (n < v->nsyms) {
+ p->mod = v;
+ p->index = n;
+ return p;
}
}
-leave_the_loop:
- *start = buf + (offset - begin);
- len -= (offset - begin);
- if (len > length)
- len = length;
- return len;
+ unlock_kernel();
+ kfree(p);
+ return NULL;
}
+static void *s_next(struct seq_file *m, void *p, loff_t *pos)
+{
+ struct mod_sym *v = p;
+ (*pos)++;
+ if (++v->index >= v->mod->nsyms) {
+ do {
+ v->mod = v->mod->next;
+ if (!v->mod) {
+ unlock_kernel();
+ kfree(p);
+ return NULL;
+ }
+ } while (!v->mod->nsyms);
+ v->index = 0;
+ }
+ return p;
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+ if (p && !IS_ERR(p)) {
+ unlock_kernel();
+ kfree(p);
+ }
+}
+
+static int s_show(struct seq_file *m, void *p)
+{
+ struct mod_sym *v = p;
+ struct module_symbol *sym;
+
+ if (!MOD_CAN_QUERY(v->mod))
+ return 0;
+ sym = &v->mod->syms[v->index];
+ if (*v->mod->name)
+ seq_printf(m, "%0*lx %s\t[%s]\n", (int)(2*sizeof(void*)),
+ sym->value, sym->name, v->mod->name);
+ else
+ seq_printf(m, "%0*lx %s\n", (int)(2*sizeof(void*)),
+ sym->value, sym->name);
+ return 0;
+}
+
+struct seq_operations ksyms_op = {
+ start: s_start,
+ next: s_next,
+ stop: s_stop,
+ show: s_show
+};
+
#else /* CONFIG_MODULES */
/* Dummy syscalls for people who don't want modules */