On Jan 19 2008 12:05, Miklos Szeredi wrote: >+ >+/* >+ * Write full pathname from the root of the filesystem into the buffer. >+ */ >+char *dentry_path(struct dentry *dentry, char *buf, int buflen) Hm, this functions looks very much like __d_path(). Is it an unintentional copy? >+{ >+ char *end = buf + buflen; >+ char *retval; >+ >+ spin_lock(&dcache_lock); >+ prepend(&end, &buflen, "\0", 1); >+ if (!IS_ROOT(dentry) && d_unhashed(dentry)) { >+ if (prepend(&end, &buflen, "//deleted", 9)) >+ goto Elong; >+ } >+ if (buflen < 1) >+ goto Elong; >+ /* Get '/' right */ >+ retval = end-1; >+ *retval = '/'; >+ >+ for (;;) { >+ struct dentry *parent; >+ if (IS_ROOT(dentry)) >+ break; >+ >+ parent = dentry->d_parent; >+ prefetch(parent); >+ >+ if (prepend(&end, &buflen, dentry->d_name.name, >+ dentry->d_name.len) || >+ prepend(&end, &buflen, "/", 1)) >+ goto Elong; >+ >+ retval = end; >+ dentry = parent; >+ } >+ spin_unlock(&dcache_lock); >+ return retval; >+Elong: >+ spin_unlock(&dcache_lock); >+ return ERR_PTR(-ENAMETOOLONG); >+} >+ > /* > * NOTE! The user-level library version returns a > * character pointer. The kernel system call just >=================================================================== >--- linux.orig/fs/namespace.c 2008-01-18 19:21:38.000000000 +0100 >+++ linux/fs/namespace.c 2008-01-18 23:39:35.000000000 +0100 >@@ -27,6 +27,7 @@ > #include <linux/mount.h> > #include <linux/ramfs.h> > #include <linux/log2.h> >+#include <linux/idr.h> > #include <asm/uaccess.h> > #include <asm/unistd.h> > #include "pnode.h" (IDR numbers are IMO fine.) >@@ -601,28 +635,29 @@ static inline void mangle(struct seq_fil > seq_escape(m, s, " \t\n\\"); > } > >+static struct proc_fs_info { These do not seem to be static data. Please mark them as const. static const struct proc_fs_info. >+ int flag; >+ char *str; const char *str. >+} fs_info[] = { >+ { MS_SYNCHRONOUS, ",sync" }, >+ { MS_DIRSYNC, ",dirsync" }, >+ { MS_MANDLOCK, ",mand" }, >+ { 0, NULL } >+}; >+static struct proc_fs_info mnt_info[] = { const >+ { MNT_NOSUID, ",nosuid" }, >+ { MNT_NODEV, ",nodev" }, >+ { MNT_NOEXEC, ",noexec" }, >+ { MNT_NOATIME, ",noatime" }, >+ { MNT_NODIRATIME, ",nodiratime" }, >+ { MNT_RELATIME, ",relatime" }, >+ { 0, NULL } >+}; >+ > static int show_vfsmnt(struct seq_file *m, void *v) > { > struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); > int err = 0; >- static struct proc_fs_info { >- int flag; >- char *str; >- } fs_info[] = { >- { MS_SYNCHRONOUS, ",sync" }, >- { MS_DIRSYNC, ",dirsync" }, >- { MS_MANDLOCK, ",mand" }, >- { 0, NULL } >- }; >- static struct proc_fs_info mnt_info[] = { >- { MNT_NOSUID, ",nosuid" }, >- { MNT_NODEV, ",nodev" }, >- { MNT_NOEXEC, ",noexec" }, >- { MNT_NOATIME, ",noatime" }, >- { MNT_NODIRATIME, ",nodiratime" }, >- { MNT_RELATIME, ",relatime" }, >- { 0, NULL } >- }; > struct proc_fs_info *fs_infop; >@@ -657,6 +692,63 @@ struct seq_operations mounts_op = { > .show = show_vfsmnt > }; > >+static int show_mountinfo(struct seq_file *m, void *v) >+{ >+ struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); >+ struct super_block *sb = mnt->mnt_sb; >+ struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; >+ struct proc_fs_info *fs_infop; >+ int err = 0; >+ >+ seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, >+ MAJOR(sb->s_dev), MINOR(sb->s_dev)); >+ mangle(m, sb->s_type->name); >+ if (sb->s_subtype && sb->s_subtype[0]) { >+ seq_putc(m, '.'); >+ mangle(m, sb->s_subtype); >+ } >+ seq_putc(m, ' '); >+ mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); >+ seq_putc(m, ' '); >+ seq_dentry(m, mnt->mnt_root, " \t\n\\"); >+ seq_putc(m, ' '); >+ seq_path(m, &mnt_path, " \t\n\\"); >+ seq_putc(m, ' '); >+ seq_puts(m, mnt->mnt_flags & MNT_READONLY ? "ro" : "rw"); >+ for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { >+ if (mnt->mnt_flags & fs_infop->flag) >+ seq_puts(m, fs_infop->str); >+ } >+ seq_putc(m, ' '); >+ seq_puts(m, sb->s_flags & MS_RDONLY ? "ro" : "rw"); >+ for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { >+ if (sb->s_flags & fs_infop->flag) >+ seq_puts(m, fs_infop->str); >+ } {} could go. >+ if (sb->s_op->show_options) >+ err = sb->s_op->show_options(m, mnt); >+ if (IS_MNT_SHARED(mnt)) { >+ seq_printf(m, " shared:%i", get_peer_group_id(mnt)); >+ if (IS_MNT_SLAVE(mnt)) >+ seq_printf(m, ",slave:%i", get_master_id(mnt)); >+ } else if (IS_MNT_SLAVE(mnt)) { >+ seq_printf(m, " slave:%i", get_master_id(mnt)); >+ } else if (IS_MNT_UNBINDABLE(mnt)) { >+ seq_printf(m, " unbindable"); >+ } else { >+ seq_printf(m, " private"); >+ } >+ seq_putc(m, '\n'); >+ return err; >+} >+ >+struct seq_operations mountinfo_op = { I think this can go const. >+ .start = m_start, >+ .next = m_next, >+ .stop = m_stop, >+ .show = show_mountinfo, >+}; >+ > static int show_vfsstat(struct seq_file *m, void *v) > { > struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list); >Index: linux/fs/seq_file.c >=================================================================== >--- linux.orig/fs/seq_file.c 2008-01-18 19:21:38.000000000 +0100 >+++ linux/fs/seq_file.c 2008-01-18 19:22:27.000000000 +0100 >@@ -349,28 +349,40 @@ int seq_printf(struct seq_file *m, const > } > EXPORT_SYMBOL(seq_printf); > >+static char *mangle_path(char *s, char *p, char *esc) const char *p, const char *esc >+{ >+ while (s <= p) { >+ char c = *p++; >+ if (!c) { >+ return s; >+ } else if (!strchr(esc, c)) { >+ *s++ = c; >+ } else if (s + 4 > p) { >+ break; >+ } else { >+ *s++ = '\\'; >+ *s++ = '0' + ((c & 0300) >> 6); >+ *s++ = '0' + ((c & 070) >> 3); >+ *s++ = '0' + (c & 07); >+ } >+ } >+ return NULL; >+} >+ >+/* >+ * return the absolute path of 'dentry' residing in mount 'mnt'. >+ */ > int seq_path(struct seq_file *m, struct path *path, char *esc) > { > if (m->count < m->size) { >@@ -379,6 +391,28 @@ int seq_path(struct seq_file *m, struct > } > EXPORT_SYMBOL(seq_path); > >+/* >+ * returns the path of the 'dentry' from the root of its filesystem. >+ */ >+int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc) const char *esc >+{ >+ if (m->count < m->size) { >+ char *s = m->buf + m->count; >+ char *p = dentry_path(dentry, s, m->size - m->count); >+ if (!IS_ERR(p)) { >+ s = mangle_path(s, p, esc); >+ if (s) { >+ p = m->buf + m->count; >+ m->count = s - m->buf; >+ return s - p; >+ } >+ } >+ } >+ m->count = m->size; >+ return -1; >+} >+EXPORT_SYMBOL(seq_dentry); >+ > static void *single_start(struct seq_file *p, loff_t *pos) > { > return NULL + (*pos == 0); >=================================================================== >--- linux.orig/include/linux/mount.h 2008-01-18 19:21:38.000000000 +0100 >+++ linux/include/linux/mount.h 2008-01-18 23:39:35.000000000 +0100 >@@ -56,6 +56,7 @@ struct vfsmount { > struct list_head mnt_slave; /* slave list entry */ > struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ > struct mnt_namespace *mnt_ns; /* containing namespace */ >+ int mnt_id; /* mount identifier */ > /* > * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount > * to let these frequently modified fields in a separate cache line Should/could it be unsigned int, or does it need to store -1? - To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html