linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/7] vfs: mountinfo (v3)
@ 2008-03-26 21:11 Miklos Szeredi
  2008-03-26 21:11 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
                   ` (7 more replies)
  0 siblings, 8 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

Here's an updated mountinfo patch with the following changes relative
to the last submission (the one currently in -mm):

 - in __d_path() don't add extra parameter for checking unreachable path
 - reduce proliferation of #ifdef CONFIG_PROC_FS into dcache.c and seq_file.c
 - make peer group ID allocation a separate pass from setting mount shared
 - change order and format of fields in /proc/<pid>/mountinfo
 - remove dubious cleanups
 - consolidate locking: don't use vfsmount_lock where namespace_sem suffices
 - patch history was getting tangled up, merge and resplit into logical chunks

This series is also available here:

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

I guess the simplest for all involved parties would be if this went
into Al's tree (if it looks OK) and then Andrew can suck that tree (*)
containing all sort of goodies into -mm.

(*) git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git vfs-2.6.25

Thanks,
Miklos

--

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

* [patch 1/7] vfs: mountinfo: add dentry_path()
  2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 21:11 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
                   ` (6 subsequent siblings)
  7 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_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-26 21:37:06.000000000 +0100
+++ vfs-2.6/fs/dcache.c	2008-03-26 21:37:35.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-26 21:37:06.000000000 +0100
+++ vfs-2.6/fs/seq_file.c	2008-03-26 21:37:35.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-26 21:37:06.000000000 +0100
+++ vfs-2.6/include/linux/dcache.h	2008-03-26 21:37:35.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-26 21:37:06.000000000 +0100
+++ vfs-2.6/include/linux/seq_file.h	2008-03-26 21:37:35.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-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
  2008-03-26 21:11 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 21:11 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
                   ` (5 subsequent siblings)
  7 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_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-26 21:37:35.000000000 +0100
+++ vfs-2.6/fs/dcache.c	2008-03-26 21:37:38.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-26 21:37:35.000000000 +0100
+++ vfs-2.6/fs/seq_file.c	2008-03-26 21:37:38.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-26 21:37:35.000000000 +0100
+++ vfs-2.6/include/linux/dcache.h	2008-03-26 21:37:38.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-26 21:37:35.000000000 +0100
+++ vfs-2.6/include/linux/seq_file.h	2008-03-26 21:37:38.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-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
  2008-03-26 21:11 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
  2008-03-26 21:11 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 22:25   ` Al Viro
  2008-03-26 21:11 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
                   ` (4 subsequent siblings)
  7 siblings, 1 reply; 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_mnt_id.patch --]
[-- Type: text/plain, Size: 2774 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        |   34 ++++++++++++++++++++++++++++++++++
 include/linux/mount.h |    1 +
 2 files changed, 35 insertions(+)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-26 21:37:06.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-26 21:37:40.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,41 @@ static inline unsigned long hash(struct 
 
 #define MNT_WRITER_UNDERFLOW_LIMIT -(1<<16)
 
+static int mnt_alloc_id(struct vfsmount *mnt)
+{
+	int res;
+
+ retry:
+	spin_lock(&vfsmount_lock);
+	res = ida_get_new(&mnt_id_ida, &mnt->mnt_id);
+	spin_unlock(&vfsmount_lock);
+	if (res == -EAGAIN) {
+		if (ida_pre_get(&mnt_id_ida, GFP_KERNEL))
+			goto retry;
+		res = -ENOMEM;
+	}
+	return res;
+}
+
+static void mnt_free_id(struct vfsmount *mnt)
+{
+	spin_lock(&vfsmount_lock);
+	ida_remove(&mnt_id_ida, mnt->mnt_id);
+	spin_unlock(&vfsmount_lock);
+}
+
 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);
@@ -353,6 +386,7 @@ EXPORT_SYMBOL(simple_set_mnt);
 void free_vfsmnt(struct vfsmount *mnt)
 {
 	kfree(mnt->mnt_devname);
+	mnt_free_id(mnt);
 	kmem_cache_free(mnt_cache, mnt);
 }
 
Index: vfs-2.6/include/linux/mount.h
===================================================================
--- vfs-2.6.orig/include/linux/mount.h	2008-03-26 21:37:06.000000000 +0100
+++ vfs-2.6/include/linux/mount.h	2008-03-26 21:37:40.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-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
                   ` (2 preceding siblings ...)
  2008-03-26 21:11 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 22:39   ` Al Viro
  2008-03-26 21:11 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
                   ` (3 subsequent siblings)
  7 siblings, 1 reply; 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_mnt_group_id.patch --]
[-- Type: text/plain, Size: 7794 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        |  100 ++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/pnode.c            |   11 +++--
 fs/pnode.h            |    1 
 include/linux/mount.h |    1 
 4 files changed, 106 insertions(+), 7 deletions(-)

Index: vfs-2.6/fs/namespace.c
===================================================================
--- vfs-2.6.orig/fs/namespace.c	2008-03-26 21:39:47.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-26 21:46:35.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;
@@ -83,6 +84,35 @@ static void mnt_free_id(struct vfsmount 
 	spin_unlock(&vfsmount_lock);
 }
 
+/*
+ * Allocate a new peer group ID
+ *
+ * mnt_group_ida is protected by namespace_sem
+ */
+static int mnt_alloc_group_id(struct vfsmount *mnt)
+{
+	int res;
+
+	WARN_ON(mnt->mnt_group_id != 0);
+ retry:
+	res = ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
+	if (res == -EAGAIN) {
+		if (ida_pre_get(&mnt_group_ida, GFP_KERNEL))
+			goto retry;
+		res = -ENOMEM;
+	}
+	return res;
+}
+
+/*
+ * 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);
@@ -533,6 +563,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;
@@ -562,6 +603,10 @@ static struct vfsmount *clone_mnt(struct
 		}
 	}
 	return mnt;
+
+ out_free:
+	free_vfsmnt(mnt);
+	return NULL;
 }
 
 static inline void __mntput(struct vfsmount *mnt)
@@ -1142,6 +1187,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 (list_empty(&p->mnt_share) && !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 (list_empty(&p->mnt_share) && !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
@@ -1212,9 +1284,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))
@@ -1237,6 +1316,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)
@@ -1277,6 +1362,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;
@@ -1285,12 +1371,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-26 21:37:53.000000000 +0100
+++ vfs-2.6/fs/pnode.c	2008-03-26 21:46:35.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;
@@ -58,9 +62,9 @@ static int do_make_slave(struct vfsmount
 		list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
 		INIT_LIST_HEAD(&mnt->mnt_slave_list);
 	} else {
-		struct list_head *p = &mnt->mnt_slave_list;
-		while (!list_empty(p)) {
-                        slave_mnt = list_first_entry(p,
+		struct list_head *slaves = &mnt->mnt_slave_list;
+		while (!list_empty(slaves)) {
+                        slave_mnt = list_first_entry(slaves,
 					struct vfsmount, mnt_slave);
 			list_del_init(&slave_mnt->mnt_slave);
 			slave_mnt->mnt_master = NULL;
@@ -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-26 21:37:52.000000000 +0100
+++ vfs-2.6/fs/pnode.h	2008-03-26 21:46:35.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-26 21:39:47.000000000 +0100
+++ vfs-2.6/include/linux/mount.h	2008-03-26 21:39:49.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-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
                   ` (3 preceding siblings ...)
  2008-03-26 21:11 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 21:11 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
                   ` (2 subsequent siblings)
  7 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

* [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo
  2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
                   ` (4 preceding siblings ...)
  2008-03-26 21:11 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 22:44   ` Al Viro
  2008-03-26 21:11 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
  2008-03-26 22:06 ` [patch 0/7] vfs: mountinfo (v3) Andrew Morton
  7 siblings, 1 reply; 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_mountinfo.patch --]
[-- Type: text/plain, Size: 10324 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 |   33 ++++++++++
 fs/namespace.c                     |  121 +++++++++++++++++++++++++++++--------
 fs/proc/base.c                     |   15 ++++
 include/linux/mnt_namespace.h      |    1 
 4 files changed, 147 insertions(+), 23 deletions(-)

Index: vfs-2.6/Documentation/filesystems/proc.txt
===================================================================
--- vfs-2.6.orig/Documentation/filesystems/proc.txt	2008-03-26 21:37:52.000000000 +0100
+++ vfs-2.6/Documentation/filesystems/proc.txt	2008-03-26 21:43:05.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,36 @@ 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 rw master:1 - ext3 /dev/root,errors=continue
+(1)(2)(3)   (4)   (5)      (6)    (7)  (8)   (9) (10)   (11)      (12)
+
+(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) super options:  filesystem type independent, per super block options
+(8) optional fields:  zero or more fields of the form "tag[:value]"
+(9) separator:  marks the end of the optional fields
+(10) filesystem type:  name of filesystem of the form "type[.subtype]"
+(11) mount source:  filesystem specific information or "none"
+(12) filesystem options:  filesystem type dependent 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-26 21:43:03.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-26 21:43:05.000000000 +0100
@@ -753,20 +753,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" },
@@ -775,27 +785,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");
@@ -809,6 +829,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);
+	seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw");
+	show_sb_opts(m, sb);
+
+	/* 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");
+	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);
@@ -829,7 +904,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-26 21:43:03.000000000 +0100
+++ vfs-2.6/fs/proc/base.c	2008-03-26 21:43:05.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-26 21:43:03.000000000 +0100
+++ vfs-2.6/include/linux/mnt_namespace.h	2008-03-26 21:43:05.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-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
                   ` (5 preceding siblings ...)
  2008-03-26 21:11 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
@ 2008-03-26 21:11 ` Miklos Szeredi
  2008-03-26 22:51   ` Al Viro
  2008-03-26 22:06 ` [patch 0/7] vfs: mountinfo (v3) Andrew Morton
  7 siblings, 1 reply; 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_dominator.patch --]
[-- Type: text/plain, Size: 4252 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                         |   45 +++++++++++++++++++++++++++++++++++++
 fs/pnode.h                         |    1 
 4 files changed, 59 insertions(+), 2 deletions(-)

Index: vfs-2.6/Documentation/filesystems/proc.txt
===================================================================
--- vfs-2.6.orig/Documentation/filesystems/proc.txt	2008-03-26 21:43:05.000000000 +0100
+++ vfs-2.6/Documentation/filesystems/proc.txt	2008-03-26 21:43:07.000000000 +0100
@@ -2375,8 +2375,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-26 21:43:05.000000000 +0100
+++ vfs-2.6/fs/namespace.c	2008-03-26 21:43:07.000000000 +0100
@@ -861,8 +861,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 dominator = get_dominator_id_same_root(mnt, &p->root);
+		seq_printf(m, " master:%i", master);
+		if (dominator && dominator != master)
+			seq_printf(m, " propagate_from:%i", dominator);
+	}
 	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-26 21:41:12.000000000 +0100
+++ vfs-2.6/fs/pnode.c	2008-03-26 21:43:07.000000000 +0100
@@ -28,6 +28,51 @@ 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
+ *
+ * Caller must hold vfsmount_lock
+ */
+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;
+}
+
+int get_dominator_id_same_root(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-26 21:39:49.000000000 +0100
+++ vfs-2.6/fs/pnode.h	2008-03-26 21:43:07.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_dominator_id_same_root(struct vfsmount *mnt, const struct path *root);
 #endif /* _LINUX_PNODE_H */

--

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

* Re: [patch 0/7] vfs: mountinfo (v3)
  2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
                   ` (6 preceding siblings ...)
  2008-03-26 21:11 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
@ 2008-03-26 22:06 ` Andrew Morton
  7 siblings, 0 replies; 17+ messages in thread
From: Andrew Morton @ 2008-03-26 22:06 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: viro, linuxram, linux-fsdevel, linux-kernel

On Wed, 26 Mar 2008 22:11:31 +0100 Miklos Szeredi <miklos@szeredi.hu> wrote:

> Here's an updated mountinfo patch with the following changes relative
> to the last submission (the one currently in -mm):
> 
>  - in __d_path() don't add extra parameter for checking unreachable path
>  - reduce proliferation of #ifdef CONFIG_PROC_FS into dcache.c and seq_file.c
>  - make peer group ID allocation a separate pass from setting mount shared
>  - change order and format of fields in /proc/<pid>/mountinfo
>  - remove dubious cleanups
>  - consolidate locking: don't use vfsmount_lock where namespace_sem suffices
>  - patch history was getting tangled up, merge and resplit into logical chunks
> 
> This series is also available here:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git mountinfo

I coudn't get that to work, perhaps due to lack of gittiness.

> I guess the simplest for all involved parties would be if this went
> into Al's tree (if it looks OK) and then Andrew can suck that tree (*)
> containing all sort of goodies into -mm.
> 
> (*) git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6.git vfs-2.6.25

I recently added that tree to the -mm lineup as git-vfs.patch, and it's in
linux-next.

This patch series applied happily on top of git-vfs (and 887 other patches ;))


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

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

On Wed, Mar 26, 2008 at 10:11:34PM +0100, Miklos Szeredi wrote:
> +static int mnt_alloc_id(struct vfsmount *mnt)
> +{
> +	int res;
> +
> + retry:
> +	spin_lock(&vfsmount_lock);
> +	res = ida_get_new(&mnt_id_ida, &mnt->mnt_id);
> +	spin_unlock(&vfsmount_lock);
> +	if (res == -EAGAIN) {
> +		if (ida_pre_get(&mnt_id_ida, GFP_KERNEL))
> +			goto retry;
> +		res = -ENOMEM;
> +	}
> +	return res;

*Ugh*

Why bother with vfsmount_lock here?  All allocations are done under
namespace_sem.  Moreover, I'd rather replace that 'goto retry' with
a single call of ida_get_new(), since we are serialized anyway.

> @@ -353,6 +386,7 @@ EXPORT_SYMBOL(simple_set_mnt);
>  void free_vfsmnt(struct vfsmount *mnt)
>  {
>  	kfree(mnt->mnt_devname);
> +	mnt_free_id(mnt);
>  	kmem_cache_free(mnt_cache, mnt);
>  }

... and I'd rather do that earlier, e.g. in umount_tree().  At that point
we (a) have namespace_sem and (b) irrevocably kick the sucker out of
any namespace.

I'd rather minimize banging vfsmount_lock like that...

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

* Re: [patch 4/7] vfs: mountinfo: add mount peer group ID
  2008-03-26 21:11 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
@ 2008-03-26 22:39   ` Al Viro
  0 siblings, 0 replies; 17+ messages in thread
From: Al Viro @ 2008-03-26 22:39 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Wed, Mar 26, 2008 at 10:11:35PM +0100, Miklos Szeredi wrote:
> +static int mnt_alloc_group_id(struct vfsmount *mnt)
> +{
> +	int res;
> +
> +	WARN_ON(mnt->mnt_group_id != 0);
> + retry:
> +	res = ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
> +	if (res == -EAGAIN) {
> +		if (ida_pre_get(&mnt_group_ida, GFP_KERNEL))
> +			goto retry;
> +		res = -ENOMEM;
> +	}
> +	return res;
> +}
> +

Same comment on goto retry

> +/*
> + * 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;
> +}

Erm...  What if that sucker has zero group ID to start with?  You
do call it that way later.

> +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 (list_empty(&p->mnt_share) && !IS_MNT_SHARED(p))
> +			mnt_release_group_id(p);
> +	}
> +}

I'd make that p->mnt_group_id && !IS_MNT_SHARED(p), actually...

> +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 (list_empty(&p->mnt_share) && !IS_MNT_SHARED(p)) {
> +			int err = mnt_alloc_group_id(p);
> +			if (err) {
> +				cleanup_group_ids(mnt, p);
> +				return err;
> +			}
> +		}
> +	}

Same comment

> @@ -58,9 +62,9 @@ static int do_make_slave(struct vfsmount
>  		list_splice(&mnt->mnt_slave_list, master->mnt_slave_list.prev);
>  		INIT_LIST_HEAD(&mnt->mnt_slave_list);
>  	} else {
> -		struct list_head *p = &mnt->mnt_slave_list;
> -		while (!list_empty(p)) {
> -                        slave_mnt = list_first_entry(p,
> +		struct list_head *slaves = &mnt->mnt_slave_list;
> +		while (!list_empty(slaves)) {
> +                        slave_mnt = list_first_entry(slaves,
>  					struct vfsmount, mnt_slave);
>  			list_del_init(&slave_mnt->mnt_slave);
>  			slave_mnt->mnt_master = NULL;

What is that renaming doing here?

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

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

On Wed, Mar 26, 2008 at 10:11:37PM +0100, Miklos Szeredi wrote:

> +This file contains lines of the form:
> +
> +36 35 98:0 /mnt1 /mnt2 rw,noatime rw master:1 - ext3 /dev/root,errors=continue
> +(1)(2)(3)   (4)   (5)      (6)    (7)  (8)   (9) (10)   (11)      (12)
> +
> +(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) super options:  filesystem type independent, per super block options

Move that one past fs type, please.

> +(8) optional fields:  zero or more fields of the form "tag[:value]"
> +(9) separator:  marks the end of the optional fields
> +(10) filesystem type:  name of filesystem of the form "type[.subtype]"
> +(11) mount source:  filesystem specific information or "none"

I'm not even sure that we *want* "none" here, to be honest, but that's
a separate story...

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

* Re: [patch 7/7] vfs: mountinfo: show dominating group id
  2008-03-26 21:11 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
@ 2008-03-26 22:51   ` Al Viro
  2008-03-27  8:34     ` Miklos Szeredi
  0 siblings, 1 reply; 17+ messages in thread
From: Al Viro @ 2008-03-26 22:51 UTC (permalink / raw)
  To: Miklos Szeredi; +Cc: akpm, linuxram, linux-fsdevel, linux-kernel

On Wed, Mar 26, 2008 at 10:11:38PM +0100, Miklos Szeredi wrote:
> +static struct vfsmount *get_peer_under_root(struct vfsmount *mnt,
> +					    struct mnt_namespace *ns,

Isn't it mnt->mnt_ns in all cases?

> +int get_dominator_id_same_root(struct vfsmount *mnt, const struct path *root)

Open season for better name.  Leaving aside .au associations, it's too
long and too uninformative...   Will do for now, but we'd better come up
with something better.

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

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

> > +This file contains lines of the form:
> > +
> > +36 35 98:0 /mnt1 /mnt2 rw,noatime rw master:1 - ext3 /dev/root,errors=continue
> > +(1)(2)(3)   (4)   (5)      (6)    (7)  (8)   (9) (10)   (11)      (12)
> > +
> > +(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) super options:  filesystem type independent, per super block options
> 
> Move that one past fs type, please.

Can you please be a bit more specific?  Because getting this right
iteratively is going to be tiring.

36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 rw /dev/root,errors=continue

or

36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root,rw,errors=continue

or perhaps

36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue

or something else?

Miklos

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

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

> > +static struct vfsmount *get_peer_under_root(struct vfsmount *mnt,
> > +					    struct mnt_namespace *ns,
> 
> Isn't it mnt->mnt_ns in all cases?

Nope.

Miklos

^ 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

* [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 ` Miklos Szeredi
  2008-03-27 22:13   ` Al Viro
  0 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

end of thread, other threads:[~2008-03-27 22:14 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-03-26 21:11 [patch 0/7] vfs: mountinfo (v3) Miklos Szeredi
2008-03-26 21:11 ` [patch 1/7] vfs: mountinfo: add dentry_path() Miklos Szeredi
2008-03-26 21:11 ` [patch 2/7] vfs: mountinfo: add seq_file_root() Miklos Szeredi
2008-03-26 21:11 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
2008-03-26 22:25   ` Al Viro
2008-03-26 21:11 ` [patch 4/7] vfs: mountinfo: add mount peer group ID Miklos Szeredi
2008-03-26 22:39   ` Al Viro
2008-03-26 21:11 ` [patch 5/7] vfs: mountinfo: allow using process root Miklos Szeredi
2008-03-26 21:11 ` [patch 6/7] vfs: mountinfo: add /proc/<pid>/mountinfo Miklos Szeredi
2008-03-26 22:44   ` Al Viro
2008-03-27  8:33     ` Miklos Szeredi
2008-03-26 21:11 ` [patch 7/7] vfs: mountinfo: show dominating group id Miklos Szeredi
2008-03-26 22:51   ` Al Viro
2008-03-27  8:34     ` Miklos Szeredi
2008-03-26 22:06 ` [patch 0/7] vfs: mountinfo (v3) Andrew Morton
2008-03-27 12:06 [patch 0/7] vfs: mountinfo (v4) Miklos Szeredi
2008-03-27 12:06 ` [patch 3/7] vfs: mountinfo: add mount ID Miklos Szeredi
2008-03-27 22:13   ` Al Viro

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).