[patch 7/7] vfs: mountinfo: show dominating group id
authorMiklos Szeredi <mszeredi@suse.cz>
Thu, 27 Mar 2008 12:06:26 +0000 (13:06 +0100)
committerAl Viro <viro@zeniv.linux.org.uk>
Wed, 23 Apr 2008 04:05:09 +0000 (00:05 -0400)
Show peer group ID of nearest dominating group that has intersection
with the mount's namespace.

Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Documentation/filesystems/proc.txt
fs/namespace.c
fs/pnode.c
fs/pnode.h

index 2cd920f92e5e8f1e39de64b860e3562cc7f5de6e..2a99116edc47335f6ab6f50859de0a8284750cdd 100644 (file)
@@ -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 c807b8d5f89176aba3c927839a89a3fd51fa5b35..0505fb61aa740182cfabe890cc668724378c5791 100644 (file)
@@ -850,8 +850,13 @@ static int show_mountinfo(struct seq_file *m, void *v)
        /* 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 d18d66491a01ab5de2684b056692c424c0159c4f..8d5f392ec3d39fa12a025ec3a6045b7ef8f790a4 100644 (file)
@@ -28,6 +28,57 @@ static inline struct vfsmount *next_slave(struct vfsmount *p)
        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 973c3f825e7dcdb8f7fd6b3158df93f6afb9f7fc..958665d662af24f4e7bea120a959c6220a91b1f5 100644 (file)
@@ -36,4 +36,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *,
 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 */