lkml.org 
[lkml]   [2001]   [Oct]   [15]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[CFT][PATCH] large /proc/mounts and friends
	Folks, patch below adds a new way to handle large files on procfs.
I've done that for /proc/mounts and /proc/ksyms, but the same trick can
be pulled for anything else. The basic idea: if file consists of records
generated by some sequence of objects, we can just describe an iterator and
use precanned functions to turn it into a file. That (and helpers for
formatting) is done in fs/seq_file.c and include/linux/seq_file.h.

Two slightly different examples of use are in fs/namespace.c and
in kernel/module.c - for /proc/mounts and /proc/ksyms resp.

Notice that helpers take care of all logics re overflows, split
entries, etc. - code that actually generates the contents becomes simpler
and cleaner.

See comments in fs/seq_file.c for description of interface - I
hope they are clear enough.

Patch works here, but it obviously needs more testing. Please,
help with that. Code review and comments on interface are also more than
welcome. It's against vanilla 2.4.13-pre3 - there is a couple of unrelated
fixes in fs/namespace.c and mm/filemap.c (already sent to Linus). Patch
follows:

diff -urN S13-pre3/fs/Makefile S13-pre3-seq/fs/Makefile
--- S13-pre3/fs/Makefile Tue Oct 9 21:47:26 2001
+++ S13-pre3-seq/fs/Makefile Mon Oct 15 20:24:18 2001
@@ -14,7 +14,7 @@
super.o block_dev.o char_dev.o stat.o exec.o pipe.o namei.o \
fcntl.o ioctl.o readdir.o select.o fifo.o locks.o \
dcache.o inode.o attr.o bad_inode.o file.o iobuf.o dnotify.o \
- filesystems.o namespace.o
+ filesystems.o namespace.o seq_file.o

ifeq ($(CONFIG_QUOTA),y)
obj-y += dquot.o
diff -urN S13-pre3/fs/namespace.c S13-pre3-seq/fs/namespace.c
--- S13-pre3/fs/namespace.c Thu Oct 11 19:24:34 2001
+++ S13-pre3-seq/fs/namespace.c Mon Oct 15 20:24:18 2001
@@ -22,6 +22,7 @@
#include <linux/nfs_fs.h>
#include <linux/nfs_fs_sb.h>
#include <linux/nfs_mount.h>
+#include <linux/seq_file.h>

struct vfsmount *do_kern_mount(char *type, int flags, char *name, void *data);
int do_remount_sb(struct super_block *sb, int flags, void * data);
@@ -153,6 +154,8 @@
atomic_inc(&sb->s_active);
mnt->mnt_sb = sb;
mnt->mnt_root = dget(root);
+ mnt->mnt_mountpoint = mnt->mnt_root;
+ mnt->mnt_parent = mnt;
}
return mnt;
}
@@ -165,160 +168,127 @@
kill_super(sb);
}

-/* Use octal escapes, like mount does, for embedded spaces etc. */
-static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' };
+/* iterator */
+static void *m_start(struct seq_file *m)
+{
+ down(&mount_sem);
+ if (list_empty(&vfsmntlist))
+ return NULL;
+ return list_entry(vfsmntlist.next, struct vfsmount, mnt_list);
+}

-static int
-mangle(const unsigned char *s, char *buf, int len) {
- char *sp;
- int n;
-
- sp = buf;
- while(*s && sp-buf < len-3) {
- for (n = 0; n < sizeof(need_escaping); n++) {
- if (*s == need_escaping[n]) {
- *sp++ = '\\';
- *sp++ = '0' + ((*s & 0300) >> 6);
- *sp++ = '0' + ((*s & 070) >> 3);
- *sp++ = '0' + (*s & 07);
- goto next;
- }
- }
- *sp++ = *s;
- next:
- s++;
- }
- return sp - buf; /* no trailing NUL */
-}
-
-static struct proc_fs_info {
- int flag;
- char *str;
-} fs_info[] = {
- { MS_SYNCHRONOUS, ",sync" },
- { MS_MANDLOCK, ",mand" },
- { MS_NOATIME, ",noatime" },
- { MS_NODIRATIME, ",nodiratime" },
- { 0, NULL }
-};
+static void *m_next(struct seq_file *m, void *v)
+{
+ struct list_head *p = ((struct vfsmount *)v)->mnt_list.next;
+ return p==&vfsmntlist ? NULL : list_entry(p, struct vfsmount, mnt_list);
+}

-static struct proc_fs_info mnt_info[] = {
- { MNT_NOSUID, ",nosuid" },
- { MNT_NODEV, ",nodev" },
- { MNT_NOEXEC, ",noexec" },
- { 0, NULL }
-};
+static void m_stop(struct seq_file *m, void *v)
+{
+ up(&mount_sem);
+}

-static struct proc_nfs_info {
- int flag;
- char *str;
- char *nostr;
-} nfs_info[] = {
- { NFS_MOUNT_SOFT, ",soft", ",hard" },
- { NFS_MOUNT_INTR, ",intr", "" },
- { NFS_MOUNT_POSIX, ",posix", "" },
- { NFS_MOUNT_TCP, ",tcp", ",udp" },
- { NFS_MOUNT_NOCTO, ",nocto", "" },
- { NFS_MOUNT_NOAC, ",noac", "" },
- { NFS_MOUNT_NONLM, ",nolock", ",lock" },
- { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
- { 0, NULL, NULL }
-};
+static inline void mangle(struct seq_file *m, const char *s)
+{
+ seq_escape(m, s, " \t\n\\");
+}

-int get_filesystem_info( char *buf )
+static void show_nfs_mount(struct seq_file *m, struct vfsmount *mnt)
{
- struct list_head *p;
- struct proc_fs_info *fs_infop;
+ static struct proc_nfs_info {
+ int flag;
+ char *str;
+ char *nostr;
+ } nfs_info[] = {
+ { NFS_MOUNT_SOFT, ",soft", ",hard" },
+ { NFS_MOUNT_INTR, ",intr", "" },
+ { NFS_MOUNT_POSIX, ",posix", "" },
+ { NFS_MOUNT_TCP, ",tcp", ",udp" },
+ { NFS_MOUNT_NOCTO, ",nocto", "" },
+ { NFS_MOUNT_NOAC, ",noac", "" },
+ { NFS_MOUNT_NONLM, ",nolock", ",lock" },
+ { NFS_MOUNT_BROKEN_SUID, ",broken_suid", "" },
+ { 0, NULL, NULL }
+ };
struct proc_nfs_info *nfs_infop;
- struct nfs_server *nfss;
- int len, prevlen;
- char *path, *buffer = (char *) __get_free_page(GFP_KERNEL);
-
- if (!buffer) return 0;
- len = prevlen = 0;
-
-#define FREEROOM ((int)PAGE_SIZE-200-len)
-#define MANGLE(s) len += mangle((s), buf+len, FREEROOM);
-
- for (p = vfsmntlist.next; p != &vfsmntlist; p = p->next) {
- struct vfsmount *tmp = list_entry(p, struct vfsmount, mnt_list);
- path = d_path(tmp->mnt_root, tmp, buffer, PAGE_SIZE);
- if (!path)
- continue;
- MANGLE(tmp->mnt_devname ? tmp->mnt_devname : "none");
- buf[len++] = ' ';
- MANGLE(path);
- buf[len++] = ' ';
- MANGLE(tmp->mnt_sb->s_type->name);
- len += sprintf(buf+len, " %s",
- tmp->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
- for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
- if (tmp->mnt_sb->s_flags & fs_infop->flag)
- MANGLE(fs_infop->str);
- }
- for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
- if (tmp->mnt_flags & fs_infop->flag)
- MANGLE(fs_infop->str);
- }
- if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
- nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
- len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
-
- len += sprintf(buf+len, ",rsize=%d", nfss->rsize);
-
- len += sprintf(buf+len, ",wsize=%d", nfss->wsize);
-#if 0
- if (nfss->timeo != 7*HZ/10) {
- len += sprintf(buf+len, ",timeo=%d",
- nfss->timeo*10/HZ);
- }
- if (nfss->retrans != 3) {
- len += sprintf(buf+len, ",retrans=%d",
- nfss->retrans);
- }
-#endif
- if (nfss->acregmin != 3*HZ) {
- len += sprintf(buf+len, ",acregmin=%d",
- nfss->acregmin/HZ);
- }
- if (nfss->acregmax != 60*HZ) {
- len += sprintf(buf+len, ",acregmax=%d",
- nfss->acregmax/HZ);
- }
- if (nfss->acdirmin != 30*HZ) {
- len += sprintf(buf+len, ",acdirmin=%d",
- nfss->acdirmin/HZ);
- }
- if (nfss->acdirmax != 60*HZ) {
- len += sprintf(buf+len, ",acdirmax=%d",
- nfss->acdirmax/HZ);
- }
- for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
- char *str;
- if (nfss->flags & nfs_infop->flag)
- str = nfs_infop->str;
- else
- str = nfs_infop->nostr;
- MANGLE(str);
- }
- len += sprintf(buf+len, ",addr=");
- MANGLE(nfss->hostname);
- }
- len += sprintf(buf + len, " 0 0\n");
- if (FREEROOM <= 3) {
- len = prevlen;
- len += sprintf(buf+len, "# truncated\n");
- break;
- }
- prevlen = len;
+ struct nfs_server *nfss = &mnt->mnt_sb->u.nfs_sb.s_server;
+
+ seq_printf(m, ",v%d", nfss->rpc_ops->version);
+ seq_printf(m, ",rsize=%d", nfss->rsize);
+ seq_printf(m, ",wsize=%d", nfss->wsize);
+ if (nfss->acregmin != 3*HZ)
+ seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
+ if (nfss->acregmax != 60*HZ)
+ seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
+ if (nfss->acdirmin != 30*HZ)
+ seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
+ if (nfss->acdirmax != 60*HZ)
+ seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
+ for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
+ if (nfss->flags & nfs_infop->flag)
+ seq_puts(m, nfs_infop->str);
+ else
+ seq_puts(m, nfs_infop->nostr);
}
+ seq_puts(m, ",addr=");
+ mangle(m, nfss->hostname);
+}

- free_page((unsigned long) buffer);
- return len;
-#undef MANGLE
-#undef FREEROOM
+static int show_vfsmnt(struct seq_file *m, void *v)
+{
+ struct vfsmount *mnt = v;
+ static struct proc_fs_info {
+ int flag;
+ char *str;
+ } fs_info[] = {
+ { MS_SYNCHRONOUS, ",sync" },
+ { MS_MANDLOCK, ",mand" },
+ { MS_NOATIME, ",noatime" },
+ { MS_NODIRATIME, ",nodiratime" },
+ { 0, NULL }
+ };
+ static struct proc_fs_info mnt_info[] = {
+ { MNT_NOSUID, ",nosuid" },
+ { MNT_NODEV, ",nodev" },
+ { MNT_NOEXEC, ",noexec" },
+ { 0, NULL }
+ };
+ struct proc_fs_info *fs_infop;
+ char *path_buf, *path;
+
+ path_buf = (char *) __get_free_page(GFP_KERNEL);
+ if (!path_buf)
+ return -ENOMEM;
+ path = d_path(mnt->mnt_root, mnt, path_buf, PAGE_SIZE);
+
+ mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
+ seq_putc(m, ' ');
+ mangle(m, path);
+ free_page((unsigned long) path_buf);
+ seq_putc(m, ' ');
+ mangle(m, mnt->mnt_sb->s_type->name);
+ seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw");
+ for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
+ if (mnt->mnt_sb->s_flags & fs_infop->flag)
+ seq_puts(m, fs_infop->str);
+ }
+ for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
+ if (mnt->mnt_flags & fs_infop->flag)
+ seq_puts(m, fs_infop->str);
+ }
+ if (strcmp("nfs", mnt->mnt_sb->s_type->name) == 0)
+ show_nfs_mount(m, mnt);
+ seq_puts(m, " 0 0\n");
+ return 0;
}

+struct seq_operations mounts_op = {
+ start: m_start,
+ next: m_next,
+ stop: m_stop,
+ show: show_vfsmnt
+};
+
/*
* Doesn't take quota and stuff into account. IOW, in some cases it will
* give false negatives. The main reason why it's here is that we need
@@ -1086,7 +1056,7 @@
printk(KERN_NOTICE "Trying to unmount old root ... ");
if (!blivet) {
spin_lock(&dcache_lock);
- list_del(&old_rootmnt->mnt_list);
+ list_del_init(&old_rootmnt->mnt_list);
spin_unlock(&dcache_lock);
mntput(old_rootmnt);
mntput(old_rootmnt);
diff -urN S13-pre3/fs/proc/proc_misc.c S13-pre3-seq/fs/proc/proc_misc.c
--- S13-pre3/fs/proc/proc_misc.c Mon Oct 15 20:12:19 2001
+++ S13-pre3-seq/fs/proc/proc_misc.c Mon Oct 15 20:24:18 2001
@@ -35,6 +35,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/smp_lock.h>
+#include <linux/seq_file.h>

#include <asm/uaccess.h>
#include <asm/pgtable.h>
@@ -57,12 +58,10 @@
#endif
#ifdef CONFIG_MODULES
extern int get_module_list(char *);
-extern int get_ksyms_list(char *, char **, off_t, int);
#endif
extern int get_device_list(char *);
extern int get_partition_list(char *, char **, off_t, int);
extern int get_filesystem_list(char *);
-extern int get_filesystem_info(char *);
extern int get_exec_domain_list(char *);
extern int get_irq_list(char *);
extern int get_dma_list(char *);
@@ -251,13 +250,17 @@
return proc_calc_metrics(page, start, off, count, eof, len);
}

-static int ksyms_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+extern struct seq_operations ksyms_op;
+static int ksyms_open(struct inode *inode, struct file *file)
{
- int len = get_ksyms_list(page, start, off, count);
- if (len < count) *eof = 1;
- return len;
+ return seq_open(file, &ksyms_op);
}
+static struct file_operations proc_ksyms_operations = {
+ open: ksyms_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ release: seq_release,
+};
#endif

static int kstat_read_proc(char *page, char **start, off_t off,
@@ -414,13 +417,6 @@
return len;
}

-static int mounts_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
-{
- int len = get_filesystem_info(page);
- return proc_calc_metrics(page, start, off, count, eof, len);
-}
-
static int execdomains_read_proc(char *page, char **start, off_t off,
int count, int *eof, void *data)
{
@@ -505,6 +501,18 @@
write: write_profile,
};

+extern struct seq_operations mounts_op;
+static int mounts_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &mounts_op);
+}
+static struct file_operations proc_mounts_operations = {
+ open: mounts_open,
+ read: seq_read,
+ llseek: seq_lseek,
+ release: seq_release,
+};
+
struct proc_dir_entry *proc_root_kcore;

void __init proc_misc_init(void)
@@ -530,7 +538,6 @@
#endif
#ifdef CONFIG_MODULES
{"modules", modules_read_proc},
- {"ksyms", ksyms_read_proc},
#endif
{"stat", kstat_read_proc},
{"devices", devices_read_proc},
@@ -546,7 +553,6 @@
{"rtc", ds1286_read_proc},
#endif
{"locks", locks_read_proc},
- {"mounts", mounts_read_proc},
{"swaps", swaps_read_proc},
{"iomem", memory_read_proc},
{"execdomains", execdomains_read_proc},
@@ -559,6 +565,12 @@
entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
if (entry)
entry->proc_fops = &proc_kmsg_operations;
+ entry = create_proc_entry("mounts", 0, NULL);
+ if (entry)
+ entry->proc_fops = &proc_mounts_operations;
+ entry = create_proc_entry("ksyms", 0, NULL);
+ if (entry)
+ entry->proc_fops = &proc_ksyms_operations;
proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
if (proc_root_kcore) {
proc_root_kcore->proc_fops = &proc_kcore_operations;
diff -urN S13-pre3/fs/seq_file.c S13-pre3-seq/fs/seq_file.c
--- S13-pre3/fs/seq_file.c Wed Dec 31 19:00:00 1969
+++ S13-pre3-seq/fs/seq_file.c Mon Oct 15 20:24:18 2001
@@ -0,0 +1,239 @@
+/*
+ * linux/fs/seq_file.c
+ *
+ * helper functions for making syntetic files from sequences of records.
+ * initial implementation -- AV, Oct 2001.
+ */
+
+#include <linux/malloc.h>
+#include <linux/fs.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+/**
+ * seq_open - initialize sequential file
+ * @file: file we initialize
+ * @op: method table describing the sequence
+ *
+ * seq_open() sets @file, associating it with a sequence described
+ * by @op. @op->start() sets the iterator up and returns the first
+ * element of sequence. @op->stop() shuts it down. @op->next()
+ * returns the next element of sequence. @op->show() prints element
+ * into the buffer. In case of error ->start() and ->next() return
+ * ERR_PTR(error). In the end of sequence they return %NULL. ->show()
+ * returns 0 in case of success and negative number in case of error.
+ */
+int seq_open(struct file *file, struct seq_operations *op)
+{
+ struct seq_file *p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return -ENOMEM;
+ memset(p, 0, sizeof(*p));
+ sema_init(&p->sem, 1);
+ p->op = op;
+ file->private_data = p;
+ return 0;
+}
+
+/**
+ * seq_read - ->read() method for sequential files.
+ * @file, @buf, @size, @ppos: see file_operations method
+ *
+ * Ready-made ->f_op->read()
+ */
+ssize_t seq_read(struct file *file, char *buf, size_t size, loff_t *ppos)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ void *p = NULL;
+ size_t copied = 0;
+ unsigned n, eaten = 0;
+ loff_t pos = *ppos;
+ int err = 0;
+
+ down(&m->sem);
+ /* grab buffer if we didn't have one */
+ if (!m->buf) {
+ m->buf = kmalloc(m->size = PAGE_SIZE, GFP_KERNEL);
+ if (!m->buf)
+ goto Enomem;
+ }
+ /* if not empty - flush it first */
+ if (m->count) {
+ n = min(m->count, size);
+ err = copy_to_user(buf, m->buf + m->from, n);
+ if (err)
+ goto Efault;
+ m->count -= n;
+ m->from += n;
+ size -= n;
+ buf += n;
+ copied += n;
+ if (!m->count) {
+ m->from = 0;
+ pos++;
+ }
+ if (!size)
+ goto Done;
+ }
+ /* more, more, I'm still not satisfied... */
+ while (1) {
+ int i;
+ for (p=m->op->start(m), i=0; i<pos; p=m->op->next(m, p), i++) {
+ if (!p || IS_ERR(p))
+ break;
+ }
+ err = PTR_ERR(p);
+ if (!p || IS_ERR(p))
+ break;
+ err = m->op->show(m, p);
+ if (err)
+ break;
+ if (m->count < m->size)
+ goto Fill;
+ m->op->stop(m, p);
+ kfree(m->buf);
+ m->buf = kmalloc(m->size <<= 1, GFP_KERNEL);
+ if (!m->buf)
+ goto Enomem;
+ }
+ m->op->stop(m, p);
+ goto Done;
+Fill:
+ while (m->count < size) {
+ size_t offs = m->count;
+ p = m->op->next(m, p);
+ if (!p || IS_ERR(p)) {
+ err = PTR_ERR(p);
+ break;
+ }
+ err = m->op->show(m, p);
+ if (err || m->count == m->size) {
+ m->count = offs;
+ break;
+ }
+ eaten++;
+ }
+ m->op->stop(m, p);
+ n = min(m->count, size);
+ err = copy_to_user(buf, m->buf, n);
+ if (err)
+ goto Efault;
+ copied += n;
+ m->count -= n;
+ if (m->count) {
+ pos += eaten;
+ m->from += n;
+ } else {
+ pos += eaten + 1;
+ m->from = 0;
+ }
+Done:
+ if (!copied)
+ copied = err;
+ *ppos = pos;
+ up(&m->sem);
+ return copied;
+Enomem:
+ err = -ENOMEM;
+ goto Done;
+Efault:
+ err = -EFAULT;
+ goto Done;
+}
+
+/**
+ * seq_lseek - ->llseek() method for sequential files.
+ * @file, @offset, @origin: see file_operations method
+ *
+ * Ready-made ->f_op->llseek()
+ */
+loff_t seq_lseek(struct file *file, loff_t offset, int origin)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ long long retval = -EINVAL;
+
+ down(&m->sem);
+ switch (origin) {
+ case 1:
+ offset += file->f_pos;
+ case 0:
+ if (offset < 0)
+ break;
+ if (offset != file->f_pos) {
+ file->f_pos = offset;
+ m->count = m->from = 0;
+ }
+ retval = offset;
+ }
+ up(&m->sem);
+ return retval;
+}
+
+/**
+ * seq_release - free the structures associated with sequential file.
+ * @file: file in question
+ * @inode: file->f_dentry->d_inode
+ *
+ * Frees the structures associated with sequential file; can be used
+ * as ->f_op->release() if you don't have private data to destroy.
+ */
+int seq_release(struct inode *inode, struct file *file)
+{
+ struct seq_file *m = (struct seq_file *)file->private_data;
+ kfree(m->buf);
+ kfree(m);
+ return 0;
+}
+
+/**
+ * seq_escape - print string into buffer, escaping some characters
+ * @m: target buffer
+ * @s: string
+ * @esc: set of characters that need escaping
+ *
+ * Puts string into buffer, replacing each occurence of character from
+ * @esc with usual octal escape. Returns 0 in case of success, -1 - in
+ * case of overflow.
+ */
+int seq_escape(struct seq_file *m, const char *s, const char *esc)
+{
+ char *end = m->buf + m->size;
+ char *p;
+ char c;
+
+ for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
+ if (!strchr(esc, c)) {
+ *p++ = c;
+ continue;
+ }
+ if (p + 3 < end) {
+ *p++ = '\\';
+ *p++ = '0' + ((c & 0300) >> 6);
+ *p++ = '0' + ((c & 070) >> 3);
+ *p++ = '0' + (c & 07);
+ continue;
+ }
+ m->count = m->size;
+ return -1;
+ }
+ m->count = p - m->buf;
+ return 0;
+}
+
+int seq_printf(struct seq_file *m, const char *f, ...)
+{
+ va_list args;
+ int len;
+
+ if (m->count < m->size) {
+ va_start(args, f);
+ len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
+ va_end(args);
+ if (m->count + len < m->size) {
+ m->count += len;
+ return 0;
+ }
+ }
+ m->count = m->size;
+ return -1;
+}
diff -urN S13-pre3/include/linux/seq_file.h S13-pre3-seq/include/linux/seq_file.h
--- S13-pre3/include/linux/seq_file.h Wed Dec 31 19:00:00 1969
+++ S13-pre3-seq/include/linux/seq_file.h Mon Oct 15 20:24:21 2001
@@ -0,0 +1,65 @@
+#ifndef _LINUX_SEQ_FILE_H
+#define _LINUX_SEQ_FILE_H
+#ifdef __KERNEL__
+
+struct seq_operations;
+
+struct seq_file {
+ char *buf;
+ size_t size;
+ size_t from;
+ size_t count;
+ struct semaphore sem;
+ struct seq_operations *op;
+};
+
+struct seq_operations {
+ void * (*start) (struct seq_file *m);
+ void (*stop) (struct seq_file *m, void *v);
+ void * (*next) (struct seq_file *m, void *v);
+ int (*show) (struct seq_file *m, void *v);
+};
+
+int seq_open(struct file *, struct seq_operations *);
+ssize_t seq_read(struct file *, char *, size_t, loff_t *);
+loff_t seq_lseek(struct file *, loff_t, int);
+int seq_release(struct inode *, struct file *);
+
+static inline size_t seq_offs(struct seq_file *m)
+{
+ return m->count;
+}
+
+static inline void seq_unroll(struct seq_file *m, size_t offs)
+{
+ m->count = offs;
+}
+
+int seq_escape(struct seq_file *, const char *, const char *);
+
+static inline int seq_putc(struct seq_file *m, char c)
+{
+ if (m->count < m->size) {
+ m->buf[m->count++] = c;
+ return 0;
+ }
+ return -1;
+}
+
+static inline int seq_puts(struct seq_file *m, const char *s)
+{
+ int len = strlen(s);
+ if (m->count + len < m->size) {
+ memcpy(m->buf + m->count, s, len);
+ m->count += len;
+ return 0;
+ }
+ m->count = m->size;
+ return -1;
+}
+
+int seq_printf(struct seq_file *, const char *, ...)
+ __attribute__ ((format (printf,2,3)));
+
+#endif
+#endif
diff -urN S13-pre3/kernel/module.c S13-pre3-seq/kernel/module.c
--- S13-pre3/kernel/module.c Sun Sep 23 16:12:09 2001
+++ S13-pre3-seq/kernel/module.c Mon Oct 15 20:24:21 2001
@@ -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,51 +1157,72 @@
* 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;
-
- for (mod = module_list; mod; mod = mod->next) {
- unsigned i;
- struct module_symbol *sym;
+ int index;
+};

- if (!MOD_CAN_QUERY(mod))
- continue;
+/* iterator */

- 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;
+static void *s_start(struct seq_file *m)
+{
+ struct mod_sym *p = kmalloc(sizeof(*p), GFP_KERNEL);
+ if (!p)
+ return ERR_PTR(-ENOMEM);
+ lock_kernel();
+ p->mod = module_list;
+ p->index = 0;
+ return p;
+}
+
+static void *s_next(struct seq_file *m, void *p)
+{
+ struct mod_sym *v = p;
+ if (++v->index < v->mod->nsyms)
+ return p;
+ v->index = 0;
+ do {
+ v->mod = v->mod->next;
+ if (!v->mod) {
+ unlock_kernel();
+ kfree(p);
+ return NULL;
}
+ } while (!v->mod->nsyms);
+ return p;
+}
+
+static void s_stop(struct seq_file *m, void *p)
+{
+ if (p && !IS_ERR(p)) {
+ unlock_kernel();
+ kfree(p);
}
-leave_the_loop:
- *start = buf + (offset - begin);
- len -= (offset - begin);
- if (len > length)
- len = length;
- return len;
}
+
+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 */

diff -urN S13-pre3/mm/filemap.c S13-pre3-seq/mm/filemap.c
--- S13-pre3/mm/filemap.c Mon Oct 15 20:12:20 2001
+++ S13-pre3-seq/mm/filemap.c Mon Oct 15 20:24:45 2001
@@ -2312,7 +2312,7 @@
unsigned long pgoff)
{
unsigned char present = 0;
- struct address_space * as = &vma->vm_file->f_dentry->d_inode->i_mapping;
+ struct address_space * as = vma->vm_file->f_dentry->d_inode->i_mapping;
struct page * page, ** hash = page_hash(as, pgoff);

spin_lock(&pagecache_lock);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2005-03-22 13:08    [W:0.403 / U:0.300 seconds]
©2003-2011 Jasper Spaans. Advertise on this site