linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/7] vfs: mountinfo (v4)
@ 2008-03-27 12:06 Miklos Szeredi
  2008-03-27 12:06 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
                   ` (6 more replies)
  0 siblings, 7 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

Another update that fixes Al's latest comments:

 - the per-sb options are merged into the fs-specific options
 - mount source is shown as a separate field (because commas are not
   escaped within it)
 - group id checking before allocation/freeing: this one doesn't
   actually make a difference for the moment (I hope) but Al's variant
   is cleaner
 - simplify ID allocation and freeing
 - dominator renaming
 - function header comment updating

Updated the git tree:

  git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git mountinfo

I suspect it doesn't work for -mm, because it's not based on -linus
directly, but on the mountinfo-base branch in the vfs-2.6.git tree.

Andrew, I'm happy that you applied the patches, but if it's the
slightest inconvenience to deal with them, just leave it.  It'll get
there through the vfs-2.6 tree anyway.

Thanks,
Miklos

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 1/7] vfs: mountinfo: add dentry_path()
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 12:06 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_dentry_path.patch --]
[-- Type: text/plain, Size: 7878 bytes --]

From: Ram Pai <linuxram@us.ibm.com>

[mszeredi@suse.cz] split big patch into managable chunks

Add the following functions:

  dentry_path()
  seq_dentry()

These are similar to d_path() and seq_path().  But instead of
calculating the path within a mount namespace, they calculate the path
from the root of the filesystem to a given dentry, ignoring mounts
completely.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/dcache.c              |   88 ++++++++++++++++++++++++++++++++++-------------
 fs/seq_file.c            |   65 ++++++++++++++++++++++++++--------
 include/linux/dcache.h   |    1 
 include/linux/seq_file.h |    2 +
 4 files changed, 117 insertions(+), 39 deletions(-)

Index: vfs-2.6/fs/dcache.c
===================================================================
--- vfs-2.6.orig/fs/dcache.c	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/dcache.c	2008-03-27 12:06:04.000000000 +0100
@@ -1746,6 +1746,17 @@ shouldnt_be_hashed:
 	goto shouldnt_be_hashed;
 }
 
+static int prepend(char **buffer, int *buflen, const char *str,
+			  int namelen)
+{
+	*buflen -= namelen;
+	if (*buflen < 0)
+		return -ENAMETOOLONG;
+	*buffer -= namelen;
+	memcpy(*buffer, str, namelen);
+	return 0;
+}
+
 /**
  * d_path - return the path of a dentry
  * @dentry: dentry to report
@@ -1767,17 +1778,11 @@ static char *__d_path(struct dentry *den
 {
 	char * end = buffer+buflen;
 	char * retval;
-	int namelen;
 
-	*--end = '\0';
-	buflen--;
-	if (!IS_ROOT(dentry) && d_unhashed(dentry)) {
-		buflen -= 10;
-		end -= 10;
-		if (buflen < 0)
+	prepend(&end, &buflen, "\0", 1);
+	if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
+		(prepend(&end, &buflen, " (deleted)", 10) != 0))
 			goto Elong;
-		memcpy(end, " (deleted)", 10);
-	}
 
 	if (buflen < 1)
 		goto Elong;
@@ -1804,13 +1809,10 @@ static char *__d_path(struct dentry *den
 		}
 		parent = dentry->d_parent;
 		prefetch(parent);
-		namelen = dentry->d_name.len;
-		buflen -= namelen + 1;
-		if (buflen < 0)
+		if ((prepend(&end, &buflen, dentry->d_name.name,
+				dentry->d_name.len) != 0) ||
+		    (prepend(&end, &buflen, "/", 1) != 0))
 			goto Elong;
-		end -= namelen;
-		memcpy(end, dentry->d_name.name, namelen);
-		*--end = '/';
 		retval = end;
 		dentry = parent;
 	}
@@ -1818,12 +1820,10 @@ static char *__d_path(struct dentry *den
 	return retval;
 
 global_root:
-	namelen = dentry->d_name.len;
-	buflen -= namelen;
-	if (buflen < 0)
+	retval += 1;	/* hit the slash */
+	if (prepend(&retval, &buflen, dentry->d_name.name,
+		    dentry->d_name.len) != 0)
 		goto Elong;
-	retval -= namelen-1;	/* hit the slash */
-	memcpy(retval, dentry->d_name.name, namelen);
 	return retval;
 Elong:
 	return ERR_PTR(-ENAMETOOLONG);
@@ -1859,7 +1859,7 @@ char *d_path(struct path *path, char *bu
 
 	read_lock(&current->fs->lock);
 	root = current->fs->root;
-	path_get(&current->fs->root);
+	path_get(&root);
 	read_unlock(&current->fs->lock);
 	spin_lock(&dcache_lock);
 	res = __d_path(path->dentry, path->mnt, &root, buf, buflen);
@@ -1890,6 +1890,48 @@ char *dynamic_dname(struct dentry *dentr
 }
 
 /*
+ * Write full pathname from the root of the filesystem into the buffer.
+ */
+char *dentry_path(struct dentry *dentry, char *buf, int buflen)
+{
+	char *end = buf + buflen;
+	char *retval;
+
+	spin_lock(&dcache_lock);
+	prepend(&end, &buflen, "\0", 1);
+	if (!IS_ROOT(dentry) && d_unhashed(dentry) &&
+		(prepend(&end, &buflen, "//deleted", 9) != 0))
+			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) != 0) ||
+		    (prepend(&end, &buflen, "/", 1) != 0))
+			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
  * returns the length of the buffer filled (which
@@ -1918,9 +1960,9 @@ asmlinkage long sys_getcwd(char __user *
 
 	read_lock(&current->fs->lock);
 	pwd = current->fs->pwd;
-	path_get(&current->fs->pwd);
+	path_get(&pwd);
 	root = current->fs->root;
-	path_get(&current->fs->root);
+	path_get(&root);
 	read_unlock(&current->fs->lock);
 
 	error = -ENOENT;
Index: vfs-2.6/fs/seq_file.c
===================================================================
--- vfs-2.6.orig/fs/seq_file.c	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/seq_file.c	2008-03-27 12:06:04.000000000 +0100
@@ -342,28 +342,40 @@ int seq_printf(struct seq_file *m, const
 }
 EXPORT_SYMBOL(seq_printf);
 
+static char *mangle_path(char *s, char *p, 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) {
 		char *s = m->buf + m->count;
 		char *p = d_path(path, s, m->size - m->count);
 		if (!IS_ERR(p)) {
-			while (s <= p) {
-				char c = *p++;
-				if (!c) {
-					p = m->buf + m->count;
-					m->count = s - m->buf;
-					return s - p;
-				} 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);
-				}
+			s = mangle_path(s, p, esc);
+			if (s) {
+				p = m->buf + m->count;
+				m->count = s - m->buf;
+				return s - p;
 			}
 		}
 	}
@@ -372,6 +384,27 @@ 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)
+{
+	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;
+}
+
 static void *single_start(struct seq_file *p, loff_t *pos)
 {
 	return NULL + (*pos == 0);
Index: vfs-2.6/include/linux/dcache.h
===================================================================
--- vfs-2.6.orig/include/linux/dcache.h	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/include/linux/dcache.h	2008-03-27 12:06:04.000000000 +0100
@@ -302,6 +302,7 @@ extern int d_validate(struct dentry *, s
 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 
 extern char *d_path(struct path *, char *, int);
+extern char *dentry_path(struct dentry *, char *, int);
 
 /* Allocation counts.. */
 
Index: vfs-2.6/include/linux/seq_file.h
===================================================================
--- vfs-2.6.orig/include/linux/seq_file.h	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/include/linux/seq_file.h	2008-03-27 12:06:04.000000000 +0100
@@ -10,6 +10,7 @@ struct seq_operations;
 struct file;
 struct path;
 struct inode;
+struct dentry;
 
 struct seq_file {
 	char *buf;
@@ -42,6 +43,7 @@ int seq_printf(struct seq_file *, const 
 	__attribute__ ((format (printf,2,3)));
 
 int seq_path(struct seq_file *, struct path *, char *);
+int seq_dentry(struct seq_file *, struct dentry *, char *);
 
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_release(struct inode *, struct file *);

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 2/7] vfs: mountinfo: add seq_file_root()
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
  2008-03-27 12:06 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 12:06 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_d_path_root.patch --]
[-- Type: text/plain, Size: 5434 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Add a new function:

  seq_file_root()

This is similar to seq_path(), but calculates the path relative to the
given root, instead of current->fs->root.  If the path was unreachable
from root, then modify the root parameter to reflect this.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/dcache.c              |   24 ++++++++++++++++--------
 fs/seq_file.c            |   30 ++++++++++++++++++++++++++++++
 include/linux/dcache.h   |    1 +
 include/linux/seq_file.h |    2 ++
 4 files changed, 49 insertions(+), 8 deletions(-)

Index: vfs-2.6/fs/dcache.c
===================================================================
--- vfs-2.6.orig/fs/dcache.c	2008-03-27 12:06:04.000000000 +0100
+++ vfs-2.6/fs/dcache.c	2008-03-27 12:06:06.000000000 +0100
@@ -1759,10 +1759,8 @@ static int prepend(char **buffer, int *b
 
 /**
  * d_path - return the path of a dentry
- * @dentry: dentry to report
- * @vfsmnt: vfsmnt to which the dentry belongs
- * @root: root dentry
- * @rootmnt: vfsmnt to which the root dentry belongs
+ * @path: the dentry/vfsmount to report
+ * @root: root vfsmnt/dentry (may be modified by this function)
  * @buffer: buffer to return value in
  * @buflen: buffer length
  *
@@ -1772,10 +1770,15 @@ static int prepend(char **buffer, int *b
  * Returns the buffer or an error code if the path was too long.
  *
  * "buflen" should be positive. Caller holds the dcache_lock.
+ *
+ * If path is not reachable from the supplied root, then the value of
+ * root is changed (without modifying refcounts).
  */
-static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt,
-		       struct path *root, char *buffer, int buflen)
+char *__d_path(const struct path *path, struct path *root,
+	       char *buffer, int buflen)
 {
+	struct dentry *dentry = path->dentry;
+	struct vfsmount *vfsmnt = path->mnt;
 	char * end = buffer+buflen;
 	char * retval;
 
@@ -1824,6 +1827,8 @@ global_root:
 	if (prepend(&retval, &buflen, dentry->d_name.name,
 		    dentry->d_name.len) != 0)
 		goto Elong;
+	root->mnt = vfsmnt;
+	root->dentry = dentry;
 	return retval;
 Elong:
 	return ERR_PTR(-ENAMETOOLONG);
@@ -1846,6 +1851,7 @@ char *d_path(struct path *path, char *bu
 {
 	char *res;
 	struct path root;
+	struct path tmp;
 
 	/*
 	 * We have various synthetic filesystems that never get mounted.  On
@@ -1862,7 +1868,8 @@ char *d_path(struct path *path, char *bu
 	path_get(&root);
 	read_unlock(&current->fs->lock);
 	spin_lock(&dcache_lock);
-	res = __d_path(path->dentry, path->mnt, &root, buf, buflen);
+	tmp = root;
+	res = __d_path(path, &tmp, buf, buflen);
 	spin_unlock(&dcache_lock);
 	path_put(&root);
 	return res;
@@ -1970,9 +1977,10 @@ asmlinkage long sys_getcwd(char __user *
 	spin_lock(&dcache_lock);
 	if (pwd.dentry->d_parent == pwd.dentry || !d_unhashed(pwd.dentry)) {
 		unsigned long len;
+		struct path tmp = root;
 		char * cwd;
 
-		cwd = __d_path(pwd.dentry, pwd.mnt, &root, page, PAGE_SIZE);
+		cwd = __d_path(&pwd, &tmp, page, PAGE_SIZE);
 		spin_unlock(&dcache_lock);
 
 		error = PTR_ERR(cwd);
Index: vfs-2.6/fs/seq_file.c
===================================================================
--- vfs-2.6.orig/fs/seq_file.c	2008-03-27 12:06:04.000000000 +0100
+++ vfs-2.6/fs/seq_file.c	2008-03-27 12:06:06.000000000 +0100
@@ -385,6 +385,36 @@ int seq_path(struct seq_file *m, struct 
 EXPORT_SYMBOL(seq_path);
 
 /*
+ * Same as seq_path, but relative to supplied root.
+ *
+ * root may be changed, see __d_path().
+ */
+int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
+		  char *esc)
+{
+	int err = -ENAMETOOLONG;
+	if (m->count < m->size) {
+		char *s = m->buf + m->count;
+		char *p;
+
+		spin_lock(&dcache_lock);
+		p = __d_path(path, root, s, m->size - m->count);
+		spin_unlock(&dcache_lock);
+		err = PTR_ERR(p);
+		if (!IS_ERR(p)) {
+			s = mangle_path(s, p, esc);
+			if (s) {
+				p = m->buf + m->count;
+				m->count = s - m->buf;
+				return 0;
+			}
+		}
+	}
+	m->count = m->size;
+	return err;
+}
+
+/*
  * returns the path of the 'dentry' from the root of its filesystem.
  */
 int seq_dentry(struct seq_file *m, struct dentry *dentry, char *esc)
Index: vfs-2.6/include/linux/dcache.h
===================================================================
--- vfs-2.6.orig/include/linux/dcache.h	2008-03-27 12:06:04.000000000 +0100
+++ vfs-2.6/include/linux/dcache.h	2008-03-27 12:06:06.000000000 +0100
@@ -301,6 +301,7 @@ extern int d_validate(struct dentry *, s
  */
 extern char *dynamic_dname(struct dentry *, char *, int, const char *, ...);
 
+extern char *__d_path(const struct path *path, struct path *root, char *, int);
 extern char *d_path(struct path *, char *, int);
 extern char *dentry_path(struct dentry *, char *, int);
 
Index: vfs-2.6/include/linux/seq_file.h
===================================================================
--- vfs-2.6.orig/include/linux/seq_file.h	2008-03-27 12:06:04.000000000 +0100
+++ vfs-2.6/include/linux/seq_file.h	2008-03-27 12:06:06.000000000 +0100
@@ -44,6 +44,8 @@ int seq_printf(struct seq_file *, const 
 
 int seq_path(struct seq_file *, struct path *, char *);
 int seq_dentry(struct seq_file *, struct dentry *, char *);
+int seq_path_root(struct seq_file *m, struct path *path, struct path *root,
+		  char *esc);
 
 int single_open(struct file *, int (*)(struct seq_file *, void *), void *);
 int single_release(struct inode *, struct file *);

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 3/7] vfs: mountinfo: add mount ID
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
  2008-03-27 12:06 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
  2008-03-27 12:06 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 22:13   ` Al Viro
  2008-03-27 12:06 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
                   ` (3 subsequent siblings)
  6 siblings, 1 reply; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_mnt_id.patch --]
[-- Type: text/plain, Size: 2507 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Add a unique ID to each vfsmount using the IDR infrastructure.  The
identifiers are reused after the vfsmount is freed.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/namespace.c        |   20 ++++++++++++++++++++
 include/linux/mount.h |    1 +
 2 files changed, 21 insertions(+)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:08.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"
@@ -39,6 +40,7 @@
 __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
 
 static int event;
+static DEFINE_IDA(mnt_id_ida);
 
 static struct list_head *mount_hashtable __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
@@ -58,10 +60,26 @@ static inline unsigned long hash(struct 
 
 #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
 
+static int mnt_alloc_id(struct vfsmount *mnt)
+{
+	if (!ida_pre_get(&mnt_id_ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	return ida_get_new_above(&mnt_id_ida, 1, &mnt->mnt_id);
+}
+
 struct vfsmount *alloc_vfsmnt(const char *name)
 {
 	struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
 	if (mnt) {
+		int err;
+
+		err = mnt_alloc_id(mnt);
+		if (err) {
+			kmem_cache_free(mnt_cache, mnt);
+			return NULL;
+		}
+
 		atomic_set(&mnt->mnt_count, 1);
 		INIT_LIST_HEAD(&mnt->mnt_hash);
 		INIT_LIST_HEAD(&mnt->mnt_child);
@@ -866,6 +884,8 @@ void umount_tree(struct vfsmount *mnt, i
 			p->mnt_mountpoint->d_mounted--;
 		}
 		change_mnt_propagation(p, MS_PRIVATE);
+		ida_remove(&mnt_id_ida, p->mnt_id);
+		p->mnt_id = 0;
 	}
 }
 
Index: vfs-2.6/include/linux/mount.h
===================================================================
--- vfs-2.6.orig/include/linux/mount.h	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/include/linux/mount.h	2008-03-27 12:06:08.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

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 4/7] vfs: mountinfo: add mount peer group ID
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
                   ` (2 preceding siblings ...)
  2008-03-27 12:06 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 12:06 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_mnt_group_id.patch --]
[-- Type: text/plain, Size: 7119 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Add a unique ID to each peer group using the IDR infrastructure.  The
identifiers are reused after the peer group dissolves.

The IDR structures are protected by holding namepspace_sem for write
while allocating or deallocating ID's.

ID's are allocated when a previously unshared vfsmount becomes the
first member of a peer group.  When a new member is added to an
existing group, the ID is copied from one of the old members.

ID's are freed when the last member of a peer group is unshared.

Setting the MNT_SHARED flag on members of a subtree is done as a
separate step, after all the ID's have been allocated.  This way an
allocation failure can be cleaned up easilty, without affecting the
propagation state.

Based on design sketch by Al Viro.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/namespace.c        |   93 ++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/pnode.c            |    5 ++
 fs/pnode.h            |    1 
 include/linux/mount.h |    1 
 4 files changed, 96 insertions(+), 4 deletions(-)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:06:08.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:10.000000000 +0100
@@ -41,6 +41,7 @@ __cacheline_aligned_in_smp DEFINE_SPINLO
 
 static int event;
 static DEFINE_IDA(mnt_id_ida);
+static DEFINE_IDA(mnt_group_ida);
 
 static struct list_head *mount_hashtable __read_mostly;
 static struct kmem_cache *mnt_cache __read_mostly;
@@ -68,6 +69,28 @@ static int mnt_alloc_id(struct vfsmount 
 	return ida_get_new_above(&mnt_id_ida, 1, &mnt->mnt_id);
 }
 
+/*
+ * Allocate a new peer group ID
+ *
+ * mnt_group_ida is protected by namespace_sem
+ */
+static int mnt_alloc_group_id(struct vfsmount *mnt)
+{
+	if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
+		return -ENOMEM;
+
+	return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
+}
+
+/*
+ * Release a peer group ID
+ */
+void mnt_release_group_id(struct vfsmount *mnt)
+{
+	ida_remove(&mnt_group_ida, mnt->mnt_group_id);
+	mnt->mnt_group_id = 0;
+}
+
 struct vfsmount *alloc_vfsmnt(const char *name)
 {
 	struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
@@ -517,6 +540,17 @@ static struct vfsmount *clone_mnt(struct
 	struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
 
 	if (mnt) {
+		if (flag & (CL_SLAVE | CL_PRIVATE))
+			mnt->mnt_group_id = 0; /* not a peer of original */
+		else
+			mnt->mnt_group_id = old->mnt_group_id;
+
+		if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
+			int err = mnt_alloc_group_id(mnt);
+			if (err)
+				goto out_free;
+		}
+
 		mnt->mnt_flags = old->mnt_flags;
 		atomic_inc(&sb->s_active);
 		mnt->mnt_sb = sb;
@@ -546,6 +580,10 @@ static struct vfsmount *clone_mnt(struct
 		}
 	}
 	return mnt;
+
+ out_free:
+	free_vfsmnt(mnt);
+	return NULL;
 }
 
 static inline void __mntput(struct vfsmount *mnt)
@@ -1128,6 +1166,33 @@ void drop_collected_mounts(struct vfsmou
 	release_mounts(&umount_list);
 }
 
+static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
+{
+	struct vfsmount *p;
+
+	for (p = mnt; p != end; p = next_mnt(p, mnt)) {
+		if (p->mnt_group_id && !IS_MNT_SHARED(p))
+			mnt_release_group_id(p);
+	}
+}
+
+static int invent_group_ids(struct vfsmount *mnt, bool recurse)
+{
+	struct vfsmount *p;
+
+	for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
+		if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
+			int err = mnt_alloc_group_id(p);
+			if (err) {
+				cleanup_group_ids(mnt, p);
+				return err;
+			}
+		}
+	}
+
+	return 0;
+}
+
 /*
  *  @source_mnt : mount tree to be attached
  *  @nd         : place the mount tree @source_mnt is attached
@@ -1198,9 +1263,16 @@ static int attach_recursive_mnt(struct v
 	struct vfsmount *dest_mnt = path->mnt;
 	struct dentry *dest_dentry = path->dentry;
 	struct vfsmount *child, *p;
+	int err;
 
-	if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list))
-		return -EINVAL;
+	if (IS_MNT_SHARED(dest_mnt)) {
+		err = invent_group_ids(source_mnt, true);
+		if (err)
+			goto out;
+	}
+	err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
+	if (err)
+		goto out_cleanup_ids;
 
 	if (IS_MNT_SHARED(dest_mnt)) {
 		for (p = source_mnt; p; p = next_mnt(p, source_mnt))
@@ -1223,6 +1295,12 @@ static int attach_recursive_mnt(struct v
 	}
 	spin_unlock(&vfsmount_lock);
 	return 0;
+
+ out_cleanup_ids:
+	if (IS_MNT_SHARED(dest_mnt))
+		cleanup_group_ids(source_mnt, NULL);
+ out:
+	return err;
 }
 
 static int graft_tree(struct vfsmount *mnt, struct path *path)
@@ -1263,6 +1341,7 @@ static noinline int do_change_type(struc
 	struct vfsmount *m, *mnt = nd->path.mnt;
 	int recurse = flag & MS_REC;
 	int type = flag & ~MS_REC;
+	int err = 0;
 
 	if (!capable(CAP_SYS_ADMIN))
 		return -EPERM;
@@ -1271,12 +1350,20 @@ static noinline int do_change_type(struc
 		return -EINVAL;
 
 	down_write(&namespace_sem);
+	if (type == MS_SHARED) {
+		err = invent_group_ids(mnt, recurse);
+		if (err)
+			goto out_unlock;
+	}
+
 	spin_lock(&vfsmount_lock);
 	for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
 		change_mnt_propagation(m, type);
 	spin_unlock(&vfsmount_lock);
+
+ out_unlock:
 	up_write(&namespace_sem);
-	return 0;
+	return err;
 }
 
 /*
Index: vfs-2.6/fs/pnode.c
===================================================================
--- vfs-2.6.orig/fs/pnode.c	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/pnode.c	2008-03-27 12:06:10.000000000 +0100
@@ -46,7 +46,11 @@ static int do_make_slave(struct vfsmount
 		if (peer_mnt == mnt)
 			peer_mnt = NULL;
 	}
+	if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share))
+		mnt_release_group_id(mnt);
+
 	list_del_init(&mnt->mnt_share);
+	mnt->mnt_group_id = 0;
 
 	if (peer_mnt)
 		master = peer_mnt;
@@ -68,7 +72,6 @@ static int do_make_slave(struct vfsmount
 	}
 	mnt->mnt_master = master;
 	CLEAR_MNT_SHARED(mnt);
-	INIT_LIST_HEAD(&mnt->mnt_slave_list);
 	return 0;
 }
 
Index: vfs-2.6/fs/pnode.h
===================================================================
--- vfs-2.6.orig/fs/pnode.h	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/pnode.h	2008-03-27 12:06:10.000000000 +0100
@@ -35,4 +35,5 @@ int propagate_mnt(struct vfsmount *, str
 		struct list_head *);
 int propagate_umount(struct list_head *);
 int propagate_mount_busy(struct vfsmount *, int);
+void mnt_release_group_id(struct vfsmount *);
 #endif /* _LINUX_PNODE_H */
Index: vfs-2.6/include/linux/mount.h
===================================================================
--- vfs-2.6.orig/include/linux/mount.h	2008-03-27 12:06:08.000000000 +0100
+++ vfs-2.6/include/linux/mount.h	2008-03-27 12:06:10.000000000 +0100
@@ -57,6 +57,7 @@ struct vfsmount {
 	struct vfsmount *mnt_master;	/* slave is on master->mnt_slave_list */
 	struct mnt_namespace *mnt_ns;	/* containing namespace */
 	int mnt_id;			/* mount identifier */
+	int mnt_group_id;		/* peer group 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

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 5/7] vfs: mountinfo: allow using process root
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
                   ` (3 preceding siblings ...)
  2008-03-27 12:06 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-28  2:08   ` Al Viro
  2008-03-27 12:06 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
  2008-03-27 12:06 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
  6 siblings, 1 reply; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_proc_mounts.patch --]
[-- Type: text/plain, Size: 6963 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Allow /proc/<pid>/mountinfo to use the root of <pid> to calculate
mountpoints.

 - move definition of 'struct proc_mounts' to <linux/mnt_namespace.h>
 - add the process's namespace and root to this structure
 - pass a pointer to 'struct proc_mounts' into seq_operations

In addition the following cleanups are made:

 - use a common open function for /proc/<pid>/{mounts,mountstat}
 - surround namespace.c part of these proc files with #ifdef CONFIG_PROC_FS
 - make the seq_operations structures const

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/namespace.c                |   14 +++--
 fs/proc/base.c                |  108 +++++++++++++++++++-----------------------
 include/linux/mnt_namespace.h |   11 ++++
 3 files changed, 70 insertions(+), 63 deletions(-)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:06:10.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:13.000000000 +0100
@@ -708,20 +708,21 @@ void save_mount_options(struct super_blo
 }
 EXPORT_SYMBOL(save_mount_options);
 
+#ifdef CONFIG_PROC_FS
 /* iterator */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct mnt_namespace *n = m->private;
+	struct proc_mounts *p = m->private;
 
 	down_read(&namespace_sem);
-	return seq_list_start(&n->list, *pos);
+	return seq_list_start(&p->ns->list, *pos);
 }
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	struct mnt_namespace *n = m->private;
+	struct proc_mounts *p = m->private;
 
-	return seq_list_next(v, &n->list, pos);
+	return seq_list_next(v, &p->ns->list, pos);
 }
 
 static void m_stop(struct seq_file *m, void *v)
@@ -778,7 +779,7 @@ static int show_vfsmnt(struct seq_file *
 	return err;
 }
 
-struct seq_operations mounts_op = {
+const struct seq_operations mounts_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
@@ -817,12 +818,13 @@ static int show_vfsstat(struct seq_file 
 	return err;
 }
 
-struct seq_operations mountstats_op = {
+const struct seq_operations mountstats_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
 	.show	= show_vfsstat,
 };
+#endif  /* CONFIG_PROC_FS */
 
 /**
  * may_umount_tree - check if a mount tree is busy
Index: vfs-2.6/fs/proc/base.c
===================================================================
--- vfs-2.6.orig/fs/proc/base.c	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/fs/proc/base.c	2008-03-27 12:06:13.000000000 +0100
@@ -502,17 +502,14 @@ static const struct inode_operations pro
 	.setattr	= proc_setattr,
 };
 
-extern const struct seq_operations mounts_op;
-struct proc_mounts {
-	struct seq_file m;
-	int event;
-};
-
-static int mounts_open(struct inode *inode, struct file *file)
+static int mounts_open_common(struct inode *inode, struct file *file,
+			      const struct seq_operations *op)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct nsproxy *nsp;
 	struct mnt_namespace *ns = NULL;
+	struct fs_struct *fs = NULL;
+	struct path root;
 	struct proc_mounts *p;
 	int ret = -EINVAL;
 
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *ino
 				get_mnt_ns(ns);
 		}
 		rcu_read_unlock();
-
+		if (ns)
+			fs = get_fs_struct(task);
 		put_task_struct(task);
 	}
 
-	if (ns) {
-		ret = -ENOMEM;
-		p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
-		if (p) {
-			file->private_data = &p->m;
-			ret = seq_open(file, &mounts_op);
-			if (!ret) {
-				p->m.private = ns;
-				p->event = ns->event;
-				return 0;
-			}
-			kfree(p);
-		}
-		put_mnt_ns(ns);
-	}
+	if (!ns)
+		goto err;
+	if (!fs)
+		goto err_put_ns;
+
+	read_lock(&fs->lock);
+	root = fs->root;
+	path_get(&root);
+	read_unlock(&fs->lock);
+	put_fs_struct(fs);
+
+	ret = -ENOMEM;
+	p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
+	if (!p)
+		goto err_put_path;
+
+	file->private_data = &p->m;
+	ret = seq_open(file, op);
+	if (ret)
+		goto err_free;
+
+	p->m.private = p;
+	p->ns = ns;
+	p->root = root;
+	p->event = ns->event;
+
+	return 0;
+
+ err_free:
+	kfree(p);
+ err_put_path:
+	path_put(&root);
+ err_put_ns:
+	put_mnt_ns(ns);
+ err:
 	return ret;
 }
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-	struct seq_file *m = file->private_data;
-	struct mnt_namespace *ns = m->private;
-	put_mnt_ns(ns);
+	struct proc_mounts *p = file->private_data;
+	path_put(&p->root);
+	put_mnt_ns(p->ns);
 	return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
 	struct proc_mounts *p = file->private_data;
-	struct mnt_namespace *ns = p->m.private;
+	struct mnt_namespace *ns = p->ns;
 	unsigned res = 0;
 
 	poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file 
 	return res;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+	return mounts_open_common(inode, file, &mounts_op);
+}
+
 static const struct file_operations proc_mounts_operations = {
 	.open		= mounts_open,
 	.read		= seq_read,
@@ -581,38 +604,9 @@ static const struct file_operations proc
 	.poll		= mounts_poll,
 };
 
-extern const struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-	int ret = seq_open(file, &mountstats_op);
-
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		struct nsproxy *nsp;
-		struct mnt_namespace *mnt_ns = NULL;
-		struct task_struct *task = get_proc_task(inode);
-
-		if (task) {
-			rcu_read_lock();
-			nsp = task_nsproxy(task);
-			if (nsp) {
-				mnt_ns = nsp->mnt_ns;
-				if (mnt_ns)
-					get_mnt_ns(mnt_ns);
-			}
-			rcu_read_unlock();
-
-			put_task_struct(task);
-		}
-
-		if (mnt_ns)
-			m->private = mnt_ns;
-		else {
-			seq_release(inode, file);
-			ret = -EINVAL;
-		}
-	}
-	return ret;
+	return mounts_open_common(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {
Index: vfs-2.6/include/linux/mnt_namespace.h
===================================================================
--- vfs-2.6.orig/include/linux/mnt_namespace.h	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/include/linux/mnt_namespace.h	2008-03-27 12:06:13.000000000 +0100
@@ -5,6 +5,7 @@
 #include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/nsproxy.h>
+#include <linux/seq_file.h>
 
 struct mnt_namespace {
 	atomic_t		count;
@@ -14,6 +15,13 @@ struct mnt_namespace {
 	int event;
 };
 
+struct proc_mounts {
+	struct seq_file m; /* must be the first element */
+	struct mnt_namespace *ns;
+	struct path root;
+	int event;
+};
+
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
 		struct fs_struct *);
 extern void __put_mnt_ns(struct mnt_namespace *ns);
@@ -37,5 +45,8 @@ static inline void get_mnt_ns(struct mnt
 	atomic_inc(&ns->count);
 }
 
+extern const struct seq_operations mounts_op;
+extern const struct seq_operations mountstats_op;
+
 #endif
 #endif

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
                   ` (4 preceding siblings ...)
  2008-03-27 12:06 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 22:36   ` Al Viro
  2008-03-27 12:06 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
  6 siblings, 1 reply; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_mountinfo.patch --]
[-- Type: text/plain, Size: 10232 bytes --]

From: Ram Pai <linuxram@us.ibm.com>

[mszeredi@suse.cz] rewrite and split big patch into managable chunks

/proc/mounts in its current form lacks important information:

 - propagation state
 - root of mount for bind mounts
 - the st_dev value used within the filesystem
 - identifier for each mount and it's parent

It also suffers from the following problems:

 - not easily extendable
 - ambiguity of mountpoints within a chrooted environment
 - doesn't distinguish between filesystem dependent and independent options
 - doesn't distinguish between per mount and per super block options

This patch introduces /proc/<pid>/mountinfo which attempts to address
all these deficiencies.

Code shared between /proc/<pid>/mounts and /proc/<pid>/mountinfo is
extracted into separate functions.

Thanks to Al Viro for the help in getting the design right.

Signed-off-by: Ram Pai <linuxram@us.ibm.com>
Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 Documentation/filesystems/proc.txt |   32 +++++++++
 fs/namespace.c                     |  121 +++++++++++++++++++++++++++++--------
 fs/proc/base.c                     |   15 ++++
 include/linux/mnt_namespace.h      |    1 
 4 files changed, 146 insertions(+), 23 deletions(-)

Index: vfs-2.6/Documentation/filesystems/proc.txt
===================================================================
--- vfs-2.6.orig/Documentation/filesystems/proc.txt	2008-03-27 12:05:55.000000000 +0100
+++ vfs-2.6/Documentation/filesystems/proc.txt	2008-03-27 12:06:15.000000000 +0100
@@ -43,6 +43,7 @@ Table of Contents
   2.13	/proc/<pid>/oom_score - Display current oom-killer score
   2.14	/proc/<pid>/io - Display the IO accounting fields
   2.15	/proc/<pid>/coredump_filter - Core dump filtering settings
+  2.16	/proc/<pid>/mountinfo - Information about mounts
 
 ------------------------------------------------------------------------------
 Preface
@@ -2348,4 +2349,35 @@ For example:
   $ echo 0x7 > /proc/self/coredump_filter
   $ ./some_program
 
+2.16	/proc/<pid>/mountinfo - Information about mounts
+--------------------------------------------------------
+
+This file contains lines of the form:
+
+36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue
+(1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11)
+
+(1) mount ID:  unique identifier of the mount (may be reused after umount)
+(2) parent ID:  ID of parent (or of self for the top of the mount tree)
+(3) major:minor:  value of st_dev for files on filesystem
+(4) root:  root of the mount within the filesystem
+(5) mount point:  mount point relative to the process's root
+(6) mount options:  per mount options
+(7) optional fields:  zero or more fields of the form "tag[:value]"
+(8) separator:  marks the end of the optional fields
+(9) filesystem type:  name of filesystem of the form "type[.subtype]"
+(10) mount source:  filesystem specific information or "none"
+(11) super options:  per super block options
+
+Parsers should ignore all unrecognised optional fields.  Currently the
+possible optional fields are:
+
+shared:X  mount is shared in peer group X
+master:X  mount is slave to peer group X
+unbindable  mount is unbindable
+
+For more information on mount propagation see:
+
+  Documentation/filesystems/sharedsubtree.txt
+
 ------------------------------------------------------------------------------
Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:06:13.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:15.000000000 +0100
@@ -730,20 +730,30 @@ static void m_stop(struct seq_file *m, v
 	up_read(&namespace_sem);
 }
 
-static int show_vfsmnt(struct seq_file *m, void *v)
+struct proc_fs_info {
+	int flag;
+	const char *str;
+};
+
+static void show_sb_opts(struct seq_file *m, struct super_block *sb)
 {
-	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
-	int err = 0;
-	static struct proc_fs_info {
-		int flag;
-		char *str;
-	} fs_info[] = {
+	static const struct proc_fs_info fs_info[] = {
 		{ MS_SYNCHRONOUS, ",sync" },
 		{ MS_DIRSYNC, ",dirsync" },
 		{ MS_MANDLOCK, ",mand" },
 		{ 0, NULL }
 	};
-	static struct proc_fs_info mnt_info[] = {
+	const struct proc_fs_info *fs_infop;
+
+	for (fs_infop = fs_info; fs_infop->flag; fs_infop++) {
+		if (sb->s_flags & fs_infop->flag)
+			seq_puts(m, fs_infop->str);
+	}
+}
+
+static void show_mnt_opts(struct seq_file *m, struct vfsmount *mnt)
+{
+	static const struct proc_fs_info mnt_info[] = {
 		{ MNT_NOSUID, ",nosuid" },
 		{ MNT_NODEV, ",nodev" },
 		{ MNT_NOEXEC, ",noexec" },
@@ -752,27 +762,37 @@ static int show_vfsmnt(struct seq_file *
 		{ MNT_RELATIME, ",relatime" },
 		{ 0, NULL }
 	};
-	struct proc_fs_info *fs_infop;
+	const struct proc_fs_info *fs_infop;
+
+	for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
+		if (mnt->mnt_flags & fs_infop->flag)
+			seq_puts(m, fs_infop->str);
+	}
+}
+
+static void show_type(struct seq_file *m, struct super_block *sb)
+{
+	mangle(m, sb->s_type->name);
+	if (sb->s_subtype && sb->s_subtype[0]) {
+		seq_putc(m, '.');
+		mangle(m, sb->s_subtype);
+	}
+}
+
+static int show_vfsmnt(struct seq_file *m, void *v)
+{
+	struct vfsmount *mnt = list_entry(v, struct vfsmount, mnt_list);
+	int err = 0;
 	struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt };
 
 	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
 	seq_putc(m, ' ');
 	seq_path(m, &mnt_path, " \t\n\\");
 	seq_putc(m, ' ');
-	mangle(m, mnt->mnt_sb->s_type->name);
-	if (mnt->mnt_sb->s_subtype && mnt->mnt_sb->s_subtype[0]) {
-		seq_putc(m, '.');
-		mangle(m, mnt->mnt_sb->s_subtype);
-	}
+	show_type(m, mnt->mnt_sb);
 	seq_puts(m, __mnt_is_readonly(mnt) ? " 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);
-	}
+	show_sb_opts(m, mnt->mnt_sb);
+	show_mnt_opts(m, mnt);
 	if (mnt->mnt_sb->s_op->show_options)
 		err = mnt->mnt_sb->s_op->show_options(m, mnt);
 	seq_puts(m, " 0 0\n");
@@ -786,6 +806,61 @@ const struct seq_operations mounts_op = 
 	.show	= show_vfsmnt
 };
 
+static int show_mountinfo(struct seq_file *m, void *v)
+{
+	struct proc_mounts *p = m->private;
+	size_t count_save = m->count;
+	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 path root = p->root;
+	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));
+	seq_dentry(m, mnt->mnt_root, " \t\n\\");
+	seq_putc(m, ' ');
+	seq_path_root(m, &mnt_path, &root, " \t\n\\");
+	if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) {
+		/*
+		 * Mountpoint is outside root, rewind seq_file. Ugly,
+		 * but necessary for race-free detection of unreachable
+		 * mountpoints.
+		 */
+		m->count = count_save;
+		return 0;
+	}
+	seq_puts(m, mnt->mnt_flags & MNT_READONLY ? " ro" : " rw");
+	show_mnt_opts(m, mnt);
+
+	/* Tagged fields ("foo:X" or "bar") */
+	if (IS_MNT_SHARED(mnt))
+		seq_printf(m, " shared:%i", mnt->mnt_group_id);
+	if (IS_MNT_SLAVE(mnt))
+		seq_printf(m, " master:%i", mnt->mnt_master->mnt_group_id);
+	if (IS_MNT_UNBINDABLE(mnt))
+		seq_puts(m, " unbindable");
+
+	/* Filesystem specific data */
+	seq_puts(m, " - ");
+	show_type(m, sb);
+	seq_putc(m, ' ');
+	mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none");
+	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
+	show_sb_opts(m, sb);
+	if (sb->s_op->show_options)
+		err = sb->s_op->show_options(m, mnt);
+	seq_putc(m, '\n');
+	return err;
+}
+
+const struct seq_operations mountinfo_op = {
+	.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);
@@ -806,7 +881,7 @@ static int show_vfsstat(struct seq_file 
 
 	/* file system type */
 	seq_puts(m, "with fstype ");
-	mangle(m, mnt->mnt_sb->s_type->name);
+	show_type(m, mnt->mnt_sb);
 
 	/* optional statistics */
 	if (mnt->mnt_sb->s_op->show_stats) {
Index: vfs-2.6/fs/proc/base.c
===================================================================
--- vfs-2.6.orig/fs/proc/base.c	2008-03-27 12:06:13.000000000 +0100
+++ vfs-2.6/fs/proc/base.c	2008-03-27 12:06:15.000000000 +0100
@@ -604,6 +604,19 @@ static const struct file_operations proc
 	.poll		= mounts_poll,
 };
 
+static int mountinfo_open(struct inode *inode, struct file *file)
+{
+	return mounts_open_common(inode, file, &mountinfo_op);
+}
+
+static const struct file_operations proc_mountinfo_operations = {
+	.open		= mountinfo_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= mounts_release,
+	.poll		= mounts_poll,
+};
+
 static int mountstats_open(struct inode *inode, struct file *file)
 {
 	return mounts_open_common(inode, file, &mountstats_op);
@@ -2285,6 +2298,7 @@ static const struct pid_entry tgid_base_
 	LNK("root",       root),
 	LNK("exe",        exe),
 	REG("mounts",     S_IRUGO, mounts),
+	REG("mountinfo",  S_IRUGO, mountinfo),
 	REG("mountstats", S_IRUSR, mountstats),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
@@ -2616,6 +2630,7 @@ static const struct pid_entry tid_base_s
 	LNK("root",      root),
 	LNK("exe",       exe),
 	REG("mounts",    S_IRUGO, mounts),
+	REG("mountinfo",  S_IRUGO, mountinfo),
 #ifdef CONFIG_PROC_PAGE_MONITOR
 	REG("clear_refs", S_IWUSR, clear_refs),
 	REG("smaps",     S_IRUGO, smaps),
Index: vfs-2.6/include/linux/mnt_namespace.h
===================================================================
--- vfs-2.6.orig/include/linux/mnt_namespace.h	2008-03-27 12:06:13.000000000 +0100
+++ vfs-2.6/include/linux/mnt_namespace.h	2008-03-27 12:06:15.000000000 +0100
@@ -46,6 +46,7 @@ static inline void get_mnt_ns(struct mnt
 }
 
 extern const struct seq_operations mounts_op;
+extern const struct seq_operations mountinfo_op;
 extern const struct seq_operations mountstats_op;
 
 #endif

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 7/7] vfs: mountinfo: show dominating group id
  2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
                   ` (5 preceding siblings ...)
  2008-03-27 12:06 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
@ 2008-03-27 12:06 ` Miklos Szeredi
  2008-03-27 22:42   ` Al Viro
  2008-03-30 18:51   ` Ram Pai
  6 siblings, 2 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-27 12:06 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_dominator.patch --]
[-- Type: text/plain, Size: 4354 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Show peer group ID of nearest dominating group that has intersection
with the mount's namespace.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 Documentation/filesystems/proc.txt |    6 ++++
 fs/namespace.c                     |    9 +++++-
 fs/pnode.c                         |   51 +++++++++++++++++++++++++++++++++++++
 fs/pnode.h                         |    1 
 4 files changed, 65 insertions(+), 2 deletions(-)

Index: vfs-2.6/Documentation/filesystems/proc.txt
===================================================================
--- vfs-2.6.orig/Documentation/filesystems/proc.txt	2008-03-27 12:06:15.000000000 +0100
+++ vfs-2.6/Documentation/filesystems/proc.txt	2008-03-27 12:06:17.000000000 +0100
@@ -2374,8 +2374,14 @@ possible optional fields are:
 
 shared:X  mount is shared in peer group X
 master:X  mount is slave to peer group X
+propagate_from:X  mount is slave and receives propagation from peer group X (*)
 unbindable  mount is unbindable
 
+(*) X is the closest dominant peer group under the process's root.  If
+X is the immediate master of the mount, or if there's no dominant peer
+group under the same root, then only the "master:X" field is present
+and not the "propagate_from:X" field.
+
 For more information on mount propagation see:
 
   Documentation/filesystems/sharedsubtree.txt
Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:06:15.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:17.000000000 +0100
@@ -836,8 +836,13 @@ static int show_mountinfo(struct seq_fil
 	/* Tagged fields ("foo:X" or "bar") */
 	if (IS_MNT_SHARED(mnt))
 		seq_printf(m, " shared:%i", mnt->mnt_group_id);
-	if (IS_MNT_SLAVE(mnt))
-		seq_printf(m, " master:%i", mnt->mnt_master->mnt_group_id);
+	if (IS_MNT_SLAVE(mnt)) {
+		int master = mnt->mnt_master->mnt_group_id;
+		int dom = get_dominating_id(mnt, &p->root);
+		seq_printf(m, " master:%i", master);
+		if (dom && dom != master)
+			seq_printf(m, " propagate_from:%i", dom);
+	}
 	if (IS_MNT_UNBINDABLE(mnt))
 		seq_puts(m, " unbindable");
 
Index: vfs-2.6/fs/pnode.c
===================================================================
--- vfs-2.6.orig/fs/pnode.c	2008-03-27 12:06:10.000000000 +0100
+++ vfs-2.6/fs/pnode.c	2008-03-27 12:06:17.000000000 +0100
@@ -28,6 +28,57 @@ static inline struct vfsmount *next_slav
 	return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
 }
 
+/*
+ * Return true if path is reachable from root
+ *
+ * namespace_sem is held, and mnt is attached
+ */
+static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
+			 const struct path *root)
+{
+	while (mnt != root->mnt && mnt->mnt_parent != mnt) {
+		dentry = mnt->mnt_mountpoint;
+		mnt = mnt->mnt_parent;
+	}
+	return mnt == root->mnt && is_subdir(dentry, root->dentry);
+}
+
+static struct vfsmount *get_peer_under_root(struct vfsmount *mnt,
+					    struct mnt_namespace *ns,
+					    const struct path *root)
+{
+	struct vfsmount *m = mnt;
+
+	do {
+		/* Check the namespace first for optimization */
+		if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root))
+			return m;
+
+		m = next_peer(m);
+	} while (m != mnt);
+
+	return NULL;
+}
+
+/*
+ * Get ID of closest dominating peer group having a representative
+ * under the given root.
+ *
+ * Caller must hold namespace_sem
+ */
+int get_dominating_id(struct vfsmount *mnt, const struct path *root)
+{
+	struct vfsmount *m;
+
+	for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) {
+		struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root);
+		if (d)
+			return d->mnt_group_id;
+	}
+
+	return 0;
+}
+
 static int do_make_slave(struct vfsmount *mnt)
 {
 	struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master;
Index: vfs-2.6/fs/pnode.h
===================================================================
--- vfs-2.6.orig/fs/pnode.h	2008-03-27 12:06:10.000000000 +0100
+++ vfs-2.6/fs/pnode.h	2008-03-27 12:06:17.000000000 +0100
@@ -36,4 +36,5 @@ int propagate_mnt(struct vfsmount *, str
 int propagate_umount(struct list_head *);
 int propagate_mount_busy(struct vfsmount *, int);
 void mnt_release_group_id(struct vfsmount *);
+int get_dominating_id(struct vfsmount *mnt, const struct path *root);
 #endif /* _LINUX_PNODE_H */

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 3/7] vfs: mountinfo: add mount ID
  2008-03-27 12:06 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
@ 2008-03-27 22:13   ` Al Viro
  0 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2008-03-27 22:13 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Thu, Mar 27, 2008 at 01:06:22PM +0100, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Add a unique ID to each vfsmount using the IDR infrastructure.  The
> identifiers are reused after the vfsmount is freed.

Er...  That would need shifting allocation to attach_recursive_mnt()
and copy_tree()...

Anyway, nevermind that for now; I'll pick the variant with spinlock
from the previous patchset.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo
  2008-03-27 12:06 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
@ 2008-03-27 22:36   ` Al Viro
  2008-03-28  8:48     ` Miklos Szeredi
  0 siblings, 1 reply; 17+ messages in thread
From: Al Viro @ 2008-03-27 22:36 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Thu, Mar 27, 2008 at 01:06:25PM +0100, Miklos Szeredi wrote:
> +36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue

Works for me...

> -static int show_vfsmnt(struct seq_file *m, void *v)
> +struct proc_fs_info {

struct flag_name would be better; will do on merge.

> +static void show_type(struct seq_file *m, struct super_block *sb)
> +{
> +	mangle(m, sb->s_type->name);

BTW, do we really want to bother with quoting?  Anyway, that can live
for now...

> +static int show_mountinfo(struct seq_file *m, void *v)
> +{
> +	struct proc_mounts *p = m->private;
> +	size_t count_save = m->count;

> +		/*
> +		 * Mountpoint is outside root, rewind seq_file. Ugly,
> +		 * but necessary for race-free detection of unreachable
> +		 * mountpoints.
> +		 */
> +		m->count = count_save;
> +		return 0;
> +	}

You know, _if_ we want to go that way, let's do it right; all callers
of ->show() are in seq_file.c and all of them know the previous value
of m->count.  So let's define SEQ_SKIP as 1 and teach these 3 callers
to handle it.  And make this sucker (and anything else that might want
the same kind of things) return SEQ_SKIP instead of playing with m->count
directly.

Again, will do on merge...

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 7/7] vfs: mountinfo: show dominating group id
  2008-03-27 12:06 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
@ 2008-03-27 22:42   ` Al Viro
  2008-03-28  8:52     ` Miklos Szeredi
  2008-03-30 18:51   ` Ram Pai
  1 sibling, 1 reply; 17+ messages in thread
From: Al Viro @ 2008-03-27 22:42 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Thu, Mar 27, 2008 at 01:06:26PM +0100, Miklos Szeredi wrote:
> +propagate_from:X  mount is slave and receives propagation from peer group X (*)
>  unbindable  mount is unbindable
>  
> +(*) X is the closest dominant peer group under the process's root.  If
> +X is the immediate master of the mount, or if there's no dominant peer
> +group under the same root, then only the "master:X" field is present
> +and not the "propagate_from:X" field.

Humm...  How does one distinguish between these variants?  Searching
in mountinfo for vfsmount with group ID of reported master?  We can
live with that, but it looks like a subtlety that will be cheerfully
forgotten by userland code.

Will do for now, but I think that we'll need that piece of documentation
more noticable and not so easy to overlook.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 5/7] vfs: mountinfo: allow using process root
  2008-03-27 12:06 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
@ 2008-03-28  2:08   ` Al Viro
  2008-03-28  8:59     ` Miklos Szeredi
  0 siblings, 1 reply; 17+ messages in thread
From: Al Viro @ 2008-03-28  2:08 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Thu, Mar 27, 2008 at 01:06:24PM +0100, Miklos Szeredi wrote:
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Allow /proc/<pid>/mountinfo to use the root of <pid> to calculate
> mountpoints.
> 
>  - move definition of 'struct proc_mounts' to <linux/mnt_namespace.h>
>  - add the process's namespace and root to this structure
>  - pass a pointer to 'struct proc_mounts' into seq_operations

NB: we might want to collect that stuff in one place.  Sharing details
between proc/base and namespace is not nice and it just got more hairy.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo
  2008-03-27 22:36   ` Al Viro
@ 2008-03-28  8:48     ` Miklos Szeredi
  0 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-28  8:48 UTC (permalink / raw)
  To: viro; +Cc: miklos, akpm, linuxram, linux-fsdevel, linux-kernel

> > +static void show_type(struct seq_file *m, struct super_block *sb)
> > +{
> > +	mangle(m, sb->s_type->name);
> 
> BTW, do we really want to bother with quoting?  Anyway, that can live
> for now...

Right, type name shouldn't need quoting.  We might want to check at fs
registration, that name is alphanumeric+underscore only, so that
somebody doesn't get the idea to put spaces into filesystem names.

> 
> > +static int show_mountinfo(struct seq_file *m, void *v)
> > +{
> > +	struct proc_mounts *p = m->private;
> > +	size_t count_save = m->count;
> 
> > +		/*
> > +		 * Mountpoint is outside root, rewind seq_file. Ugly,
> > +		 * but necessary for race-free detection of unreachable
> > +		 * mountpoints.
> > +		 */
> > +		m->count = count_save;
> > +		return 0;
> > +	}
> 
> You know, _if_ we want to go that way, let's do it right; all callers
> of ->show() are in seq_file.c and all of them know the previous value
> of m->count.  So let's define SEQ_SKIP as 1 and teach these 3 callers
> to handle it.  And make this sucker (and anything else that might want
> the same kind of things) return SEQ_SKIP instead of playing with m->count
> directly.

Sounds good.

> Again, will do on merge...

Thanks,
Miklos

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 7/7] vfs: mountinfo: show dominating group id
  2008-03-27 22:42   ` Al Viro
@ 2008-03-28  8:52     ` Miklos Szeredi
  0 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-28  8:52 UTC (permalink / raw)
  To: viro; +Cc: miklos, akpm, linuxram, linux-fsdevel, linux-kernel

> On Thu, Mar 27, 2008 at 01:06:26PM +0100, Miklos Szeredi wrote:
> > +propagate_from:X  mount is slave and receives propagation from peer group X (*)
> >  unbindable  mount is unbindable
> >  
> > +(*) X is the closest dominant peer group under the process's root.  If
> > +X is the immediate master of the mount, or if there's no dominant peer
> > +group under the same root, then only the "master:X" field is present
> > +and not the "propagate_from:X" field.
> 
> Humm...  How does one distinguish between these variants?  Searching
> in mountinfo for vfsmount with group ID of reported master?

Yeah.  We could show propagate_from: unconditionally, but it would be
redundant most of the time.

Miklos

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 5/7] vfs: mountinfo: allow using process root
  2008-03-28  2:08   ` Al Viro
@ 2008-03-28  8:59     ` Miklos Szeredi
  0 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-28  8:59 UTC (permalink / raw)
  To: viro; +Cc: miklos, akpm, linuxram, linux-fsdevel, linux-kernel

> On Thu, Mar 27, 2008 at 01:06:24PM +0100, Miklos Szeredi wrote:
> > From: Miklos Szeredi <mszeredi@suse.cz>
> > 
> > Allow /proc/<pid>/mountinfo to use the root of <pid> to calculate
> > mountpoints.
> > 
> >  - move definition of 'struct proc_mounts' to <linux/mnt_namespace.h>
> >  - add the process's namespace and root to this structure
> >  - pass a pointer to 'struct proc_mounts' into seq_operations
> 
> NB: we might want to collect that stuff in one place.  Sharing details
> between proc/base and namespace is not nice and it just got more hairy.

OK.  It needs to be in namespace.c because of namespace_sem.

Miklos

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [patch 7/7] vfs: mountinfo: show dominating group id
  2008-03-27 12:06 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
  2008-03-27 22:42   ` Al Viro
@ 2008-03-30 18:51   ` Ram Pai
  1 sibling, 0 replies; 17+ messages in thread
From: Ram Pai @ 2008-03-30 18:51 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: viro, akpm, linux-fsdevel, linux-kernel

On Thu, 2008-03-27 at 13:06 +0100, Miklos Szeredi wrote:
> plain text document attachment (mountinfo_dominator.patch)
> From: Miklos Szeredi <mszeredi@suse.cz>
> 
> Show peer group ID of nearest dominating group that has intersection
> with the mount's namespace.
> 
> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
> ---
>  Documentation/filesystems/proc.txt |    6 ++++
>  fs/namespace.c                     |    9 +++++-
>  fs/pnode.c                         |   51 +++++++++++++++++++++++++++++++++++++
>  fs/pnode.h                         |    1 
>  4 files changed, 65 insertions(+), 2 deletions(-)
> 
> Index: vfs-2.6/Documentation/filesystems/proc.txt
> ===================================================================
> --- vfs-2.6.orig/Documentation/filesystems/proc.txt	2008-03-27 12:06:15.000000000 +0100
> +++ vfs-2.6/Documentation/filesystems/proc.txt	2008-03-27 12:06:17.000000000 +0100
> @@ -2374,8 +2374,14 @@ possible optional fields are:
> 
>  shared:X  mount is shared in peer group X
>  master:X  mount is slave to peer group X
> +propagate_from:X  mount is slave and receives propagation from peer group X (*)
>  unbindable  mount is unbindable
> 
> +(*) X is the closest dominant peer group under the process's root.  If
> +X is the immediate master of the mount, or if there's no dominant peer
> +group under the same root, then only the "master:X" field is present
> +and not the "propagate_from:X" field.
> +
>  For more information on mount propagation see:
> 
>    Documentation/filesystems/sharedsubtree.txt
> Index: vfs-2.6/fs/namespace.c
> ===================================================================
> --- vfs-2.6.orig/fs/namespace.c	2008-03-27 12:06:15.000000000 +0100
> +++ vfs-2.6/fs/namespace.c	2008-03-27 12:06:17.000000000 +0100
> @@ -836,8 +836,13 @@ static int show_mountinfo(struct seq_fil
>  	/* Tagged fields ("foo:X" or "bar") */
>  	if (IS_MNT_SHARED(mnt))
>  		seq_printf(m, " shared:%i", mnt->mnt_group_id);
> -	if (IS_MNT_SLAVE(mnt))
> -		seq_printf(m, " master:%i", mnt->mnt_master->mnt_group_id);
> +	if (IS_MNT_SLAVE(mnt)) {
> +		int master = mnt->mnt_master->mnt_group_id;
> +		int dom = get_dominating_id(mnt, &p->root);
> +		seq_printf(m, " master:%i", master);
> +		if (dom && dom != master)
> +			seq_printf(m, " propagate_from:%i", dom);
> +	}
>  	if (IS_MNT_UNBINDABLE(mnt))
>  		seq_puts(m, " unbindable");
> 
> Index: vfs-2.6/fs/pnode.c
> ===================================================================
> --- vfs-2.6.orig/fs/pnode.c	2008-03-27 12:06:10.000000000 +0100
> +++ vfs-2.6/fs/pnode.c	2008-03-27 12:06:17.000000000 +0100
> @@ -28,6 +28,57 @@ static inline struct vfsmount *next_slav
>  	return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave);
>  }
> 
> +/*
> + * Return true if path is reachable from root
> + *
> + * namespace_sem is held, and mnt is attached
> + */
> +static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry,
> +			 const struct path *root)
> +{
> +	while (mnt != root->mnt && mnt->mnt_parent != mnt) {
> +		dentry = mnt->mnt_mountpoint;
> +		mnt = mnt->mnt_parent;
> +	}
> +	return mnt == root->mnt && is_subdir(dentry, root->dentry);
> +}


This function belongs somewhere else, maybe namespace.c since it has
nothing to do with propagation and is generally provides a useful
service.

RP





^ permalink raw reply	[flat|nested] 17+ messages in thread

* [patch 5/7] vfs: mountinfo: allow using process root
  2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  0 siblings, 0 replies; 17+ messages in thread
From: Miklos Szeredi @ 2008-03-26 21:11 UTC (permalink / raw)
  To: viro; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

[-- Attachment #1: mountinfo_proc_mounts.patch --]
[-- Type: text/plain, Size: 6963 bytes --]

From: Miklos Szeredi <mszeredi@suse.cz>

Allow /proc/<pid>/mountinfo to use the root of <pid> to calculate
mountpoints.

 - move definition of 'struct proc_mounts' to <linux/mnt_namespace.h>
 - add the process's namespace and root to this structure
 - pass a pointer to 'struct proc_mounts' into seq_operations

In addition the following cleanups are made:

 - use a common open function for /proc/<pid>/{mounts,mountstat}
 - surround namespace.c part of these proc files with #ifdef CONFIG_PROC_FS
 - make the seq_operations structures const

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
---
 fs/namespace.c                |   14 +++--
 fs/proc/base.c                |  108 +++++++++++++++++++-----------------------
 include/linux/mnt_namespace.h |   11 ++++
 3 files changed, 70 insertions(+), 63 deletions(-)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-26 21:39:49.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-26 21:43:03.000000000 +0100
@@ -731,20 +731,21 @@ void save_mount_options(struct super_blo
 }
 EXPORT_SYMBOL(save_mount_options);
 
+#ifdef CONFIG_PROC_FS
 /* iterator */
 static void *m_start(struct seq_file *m, loff_t *pos)
 {
-	struct mnt_namespace *n = m->private;
+	struct proc_mounts *p = m->private;
 
 	down_read(&namespace_sem);
-	return seq_list_start(&n->list, *pos);
+	return seq_list_start(&p->ns->list, *pos);
 }
 
 static void *m_next(struct seq_file *m, void *v, loff_t *pos)
 {
-	struct mnt_namespace *n = m->private;
+	struct proc_mounts *p = m->private;
 
-	return seq_list_next(v, &n->list, pos);
+	return seq_list_next(v, &p->ns->list, pos);
 }
 
 static void m_stop(struct seq_file *m, void *v)
@@ -801,7 +802,7 @@ static int show_vfsmnt(struct seq_file *
 	return err;
 }
 
-struct seq_operations mounts_op = {
+const struct seq_operations mounts_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
@@ -840,12 +841,13 @@ static int show_vfsstat(struct seq_file 
 	return err;
 }
 
-struct seq_operations mountstats_op = {
+const struct seq_operations mountstats_op = {
 	.start	= m_start,
 	.next	= m_next,
 	.stop	= m_stop,
 	.show	= show_vfsstat,
 };
+#endif  /* CONFIG_PROC_FS */
 
 /**
  * may_umount_tree - check if a mount tree is busy
Index: vfs-2.6/fs/proc/base.c
===================================================================
--- vfs-2.6.orig/fs/proc/base.c	2008-03-26 21:37:52.000000000 +0100
+++ vfs-2.6/fs/proc/base.c	2008-03-26 21:43:03.000000000 +0100
@@ -502,17 +502,14 @@ static const struct inode_operations pro
 	.setattr	= proc_setattr,
 };
 
-extern const struct seq_operations mounts_op;
-struct proc_mounts {
-	struct seq_file m;
-	int event;
-};
-
-static int mounts_open(struct inode *inode, struct file *file)
+static int mounts_open_common(struct inode *inode, struct file *file,
+			      const struct seq_operations *op)
 {
 	struct task_struct *task = get_proc_task(inode);
 	struct nsproxy *nsp;
 	struct mnt_namespace *ns = NULL;
+	struct fs_struct *fs = NULL;
+	struct path root;
 	struct proc_mounts *p;
 	int ret = -EINVAL;
 
@@ -525,40 +522,61 @@ static int mounts_open(struct inode *ino
 				get_mnt_ns(ns);
 		}
 		rcu_read_unlock();
-
+		if (ns)
+			fs = get_fs_struct(task);
 		put_task_struct(task);
 	}
 
-	if (ns) {
-		ret = -ENOMEM;
-		p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
-		if (p) {
-			file->private_data = &p->m;
-			ret = seq_open(file, &mounts_op);
-			if (!ret) {
-				p->m.private = ns;
-				p->event = ns->event;
-				return 0;
-			}
-			kfree(p);
-		}
-		put_mnt_ns(ns);
-	}
+	if (!ns)
+		goto err;
+	if (!fs)
+		goto err_put_ns;
+
+	read_lock(&fs->lock);
+	root = fs->root;
+	path_get(&root);
+	read_unlock(&fs->lock);
+	put_fs_struct(fs);
+
+	ret = -ENOMEM;
+	p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL);
+	if (!p)
+		goto err_put_path;
+
+	file->private_data = &p->m;
+	ret = seq_open(file, op);
+	if (ret)
+		goto err_free;
+
+	p->m.private = p;
+	p->ns = ns;
+	p->root = root;
+	p->event = ns->event;
+
+	return 0;
+
+ err_free:
+	kfree(p);
+ err_put_path:
+	path_put(&root);
+ err_put_ns:
+	put_mnt_ns(ns);
+ err:
 	return ret;
 }
 
 static int mounts_release(struct inode *inode, struct file *file)
 {
-	struct seq_file *m = file->private_data;
-	struct mnt_namespace *ns = m->private;
-	put_mnt_ns(ns);
+	struct proc_mounts *p = file->private_data;
+	path_put(&p->root);
+	put_mnt_ns(p->ns);
 	return seq_release(inode, file);
 }
 
 static unsigned mounts_poll(struct file *file, poll_table *wait)
 {
 	struct proc_mounts *p = file->private_data;
-	struct mnt_namespace *ns = p->m.private;
+	struct mnt_namespace *ns = p->ns;
 	unsigned res = 0;
 
 	poll_wait(file, &ns->poll, wait);
@@ -573,6 +591,11 @@ static unsigned mounts_poll(struct file 
 	return res;
 }
 
+static int mounts_open(struct inode *inode, struct file *file)
+{
+	return mounts_open_common(inode, file, &mounts_op);
+}
+
 static const struct file_operations proc_mounts_operations = {
 	.open		= mounts_open,
 	.read		= seq_read,
@@ -581,38 +604,9 @@ static const struct file_operations proc
 	.poll		= mounts_poll,
 };
 
-extern const struct seq_operations mountstats_op;
 static int mountstats_open(struct inode *inode, struct file *file)
 {
-	int ret = seq_open(file, &mountstats_op);
-
-	if (!ret) {
-		struct seq_file *m = file->private_data;
-		struct nsproxy *nsp;
-		struct mnt_namespace *mnt_ns = NULL;
-		struct task_struct *task = get_proc_task(inode);
-
-		if (task) {
-			rcu_read_lock();
-			nsp = task_nsproxy(task);
-			if (nsp) {
-				mnt_ns = nsp->mnt_ns;
-				if (mnt_ns)
-					get_mnt_ns(mnt_ns);
-			}
-			rcu_read_unlock();
-
-			put_task_struct(task);
-		}
-
-		if (mnt_ns)
-			m->private = mnt_ns;
-		else {
-			seq_release(inode, file);
-			ret = -EINVAL;
-		}
-	}
-	return ret;
+	return mounts_open_common(inode, file, &mountstats_op);
 }
 
 static const struct file_operations proc_mountstats_operations = {
Index: vfs-2.6/include/linux/mnt_namespace.h
===================================================================
--- vfs-2.6.orig/include/linux/mnt_namespace.h	2008-03-26 21:37:52.000000000 +0100
+++ vfs-2.6/include/linux/mnt_namespace.h	2008-03-26 21:43:03.000000000 +0100
@@ -5,6 +5,7 @@
 #include <linux/mount.h>
 #include <linux/sched.h>
 #include <linux/nsproxy.h>
+#include <linux/seq_file.h>
 
 struct mnt_namespace {
 	atomic_t		count;
@@ -14,6 +15,13 @@ struct mnt_namespace {
 	int event;
 };
 
+struct proc_mounts {
+	struct seq_file m; /* must be the first element */
+	struct mnt_namespace *ns;
+	struct path root;
+	int event;
+};
+
 extern struct mnt_namespace *copy_mnt_ns(unsigned long, struct mnt_namespace *,
 		struct fs_struct *);
 extern void __put_mnt_ns(struct mnt_namespace *ns);
@@ -37,5 +45,8 @@ static inline void get_mnt_ns(struct mnt
 	atomic_inc(&ns->count);
 }
 
+extern const struct seq_operations mounts_op;
+extern const struct seq_operations mountstats_op;
+
 #endif
 #endif

--

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2008-03-30 18:52 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
2008-03-27 12:06 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
2008-03-27 12:06 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
2008-03-27 12:06 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
2008-03-27 22:13   ` Al Viro
2008-03-27 12:06 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
2008-03-27 12:06 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
2008-03-28  2:08   ` Al Viro
2008-03-28  8:59     ` Miklos Szeredi
2008-03-27 12:06 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
2008-03-27 22:36   ` Al Viro
2008-03-28  8:48     ` Miklos Szeredi
2008-03-27 12:06 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
2008-03-27 22:42   ` Al Viro
2008-03-28  8:52     ` Miklos Szeredi
2008-03-30 18:51   ` Ram Pai
  -- strict thread matches above, loose matches on Subject: below --
2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
2008-03-26 21:11 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).