This patch introduces a new proc interface that exposes all the propagation trees within the namespace. It walks through each off the mounts in the namespace, and prints the following information. mount-id: a unique mount identifier dev-id : the unique device used to identify the device containing the filesystem path-from-root: mount point of the mount from / path-from-root-of-its-sb: path from its own root dentry. propagation-flag: SHARED, SLAVE, UNBINDABLE, PRIVATE peer-mount-id: the mount-id of its peer mount (if this mount is shared) master-mount-id: the mount-id of its master mount (if this mount is slave) Using the above information one could easily write a script that can draw all the propagation trees in the namespace. Example: Here is a sample output of cat /proc/$$/mounts_propagation 0xa917800 0x1 / / PRIVATE 0xa917200 0x6200 / / PRIVATE 0xa917180 0x3 /proc / PRIVATE 0xa917f80 0xa /dev/pts / PRIVATE 0xa917100 0x6210 /mnt / SHARED peer:0xa917100 0xa917f00 0x6210 /tmp /1 SLAVE master:0xa917100 0xa917900 0x6220 /mnt/2 / SHARED peer:0xa917900 line 5 indicates that the mount with id 0xa917100 is mounted at /mnt is shared and it is the only mount in its peer group. line 6 indicates that the mount with id 0xa917f00 is mounted at /tmp, its root is the dentry 1 present under its root directory. This mount is a slave mount and its master is the mount with id 0xa917100. line 7 indicates that the mount with id 0xa917900 is mounted at /mnt/2, its root is the dentry / of its filesystem. This mount is a shared and it is the only mount in its peer group. one could write a script which runs through these lines and draws 4 individual satellite mounts and two propagation trees, the first propagation tree has a shared mount and a slave mount. and the second propagation tree has just one shared mount. Signed-off-by: Ram Pai --- fs/namespace.c | 42 ++++++++++++++++++++++++++++++++++++++++++ fs/pnode.c | 6 ------ fs/pnode.h | 6 ++++++ fs/proc/base.c | 22 +++++++++++++++++++++- 4 files changed, 69 insertions(+), 7 deletions(-) Index: linux-2.6.17.10/fs/namespace.c =================================================================== --- linux-2.6.17.10.orig/fs/namespace.c +++ linux-2.6.17.10/fs/namespace.c @@ -410,6 +410,41 @@ static int show_vfsmnt_new(struct seq_fi return show_options(m, v); } +static int show_vfsmnt_propagation(struct seq_file *m, void *v) +{ + struct vfsmount *mnt = v; + seq_printf(m, "0x%x", (int)mnt); + seq_putc(m, ' '); + seq_printf(m, "0x%x", new_encode_dev(mnt->mnt_sb->s_dev)); + seq_putc(m, ' '); + seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); + seq_putc(m, ' '); + seq_dentry(m, mnt->mnt_root, " \t\n\\"); + seq_putc(m, ' '); + + if (IS_MNT_SHARED(mnt)) { + seq_printf(m, "%s ", "SHARED"); + if (IS_MNT_SLAVE(mnt)) { + seq_printf(m, "%s ", "SLAVE"); + } + } else if (IS_MNT_SLAVE(mnt)) { + seq_printf(m, "%s ", "SLAVE"); + } else if (IS_MNT_UNBINDABLE(mnt)) { + seq_printf(m, "%s ", "UNBINDABLE"); + } else { + seq_printf(m, "%s ", "PRIVATE"); + } + + if (IS_MNT_SHARED(mnt)) { + seq_printf(m, "peer:0x%x ", (int)next_peer(mnt)); + } + if (IS_MNT_SLAVE(mnt)) { + seq_printf(m, "master:0x%x ", (int)mnt->mnt_master); + } + seq_puts(m, "\n"); + return 0; +} + struct seq_operations mounts_op = { .start = m_start, .next = m_next, @@ -424,6 +459,13 @@ struct seq_operations mounts_new_op = { .show = show_vfsmnt_new }; +struct seq_operations mounts_propagation_op = { + .start = m_start, + .next = m_next, + .stop = m_stop, + .show = show_vfsmnt_propagation +}; + static int show_vfsstat(struct seq_file *m, void *v) { struct vfsmount *mnt = v; Index: linux-2.6.17.10/fs/proc/base.c =================================================================== --- linux-2.6.17.10.orig/fs/proc/base.c +++ linux-2.6.17.10/fs/proc/base.c @@ -105,6 +105,7 @@ enum pid_directory_inos { PROC_TGID_NUMA_MAPS, PROC_TGID_MOUNTS, PROC_TGID_MOUNTS_NEW, + PROC_TGID_MOUNTS_PROPAGATION, PROC_TGID_MOUNTSTATS, PROC_TGID_WCHAN, #ifdef CONFIG_MMU @@ -146,6 +147,7 @@ enum pid_directory_inos { PROC_TID_MAPS, PROC_TID_NUMA_MAPS, PROC_TID_MOUNTS, + PROC_TID_MOUNTS_PROPAGATION, PROC_TID_MOUNTS_NEW, PROC_TID_MOUNTSTATS, PROC_TID_WCHAN, @@ -206,6 +208,7 @@ static struct pid_entry tgid_base_stuff[ E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), E(PROC_TGID_MOUNTS_NEW,"mounts_new", S_IFREG|S_IRUGO), + E(PROC_TGID_MOUNTS_PROPAGATION,"mounts_propagation", S_IFREG|S_IRUGO), E(PROC_TGID_MOUNTSTATS, "mountstats", S_IFREG|S_IRUSR), #ifdef CONFIG_MMU E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), @@ -250,6 +253,7 @@ static struct pid_entry tid_base_stuff[] E(PROC_TID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_TID_MOUNTS, "mounts", S_IFREG|S_IRUGO), E(PROC_TID_MOUNTS_NEW, "mounts_new", S_IFREG|S_IRUGO), + E(PROC_TID_MOUNTS_PROPAGATION,"mounts_propagation", S_IFREG|S_IRUGO), #ifdef CONFIG_MMU E(PROC_TID_SMAPS, "smaps", S_IFREG|S_IRUGO), #endif @@ -733,7 +737,7 @@ static int __mounts_open(struct inode *i return ret; } -extern struct seq_operations mounts_op, mounts_new_op; +extern struct seq_operations mounts_op, mounts_new_op, mounts_propagation_op; static int mounts_open(struct inode *inode, struct file *file) { return (__mounts_open(inode, file, &mounts_op)); @@ -742,6 +746,10 @@ static int mounts_new_open(struct inode { return __mounts_open(inode, file, &mounts_new_op); } +static int mounts_propagation_open(struct inode *inode, struct file *file) +{ + return __mounts_open(inode, file, &mounts_propagation_op); +} static int mounts_release(struct inode *inode, struct file *file) { @@ -785,6 +793,14 @@ static struct file_operations proc_mount .poll = mounts_poll, }; +static struct file_operations proc_propagation_operations = { + .open = mounts_propagation_open, + .read = seq_read, + .llseek = seq_lseek, + .release = mounts_release, + .poll = mounts_poll, +}; + extern struct seq_operations mountstats_op; static int mountstats_open(struct inode *inode, struct file *file) { @@ -1825,6 +1841,10 @@ static struct dentry *proc_pident_lookup case PROC_TGID_MOUNTS_NEW: inode->i_fop = &proc_mounts_new_operations; break; + case PROC_TID_MOUNTS_PROPAGATION: + case PROC_TGID_MOUNTS_PROPAGATION: + inode->i_fop = &proc_propagation_operations; + break; #ifdef CONFIG_MMU case PROC_TID_SMAPS: case PROC_TGID_SMAPS: Index: linux-2.6.17.10/fs/pnode.c =================================================================== --- linux-2.6.17.10.orig/fs/pnode.c +++ linux-2.6.17.10/fs/pnode.c @@ -11,12 +11,6 @@ #include #include "pnode.h" -/* return the next shared peer mount of @p */ -static inline struct vfsmount *next_peer(struct vfsmount *p) -{ - return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); -} - static inline struct vfsmount *first_slave(struct vfsmount *p) { return list_entry(p->mnt_slave_list.next, struct vfsmount, mnt_slave); Index: linux-2.6.17.10/fs/pnode.h =================================================================== --- linux-2.6.17.10.orig/fs/pnode.h +++ linux-2.6.17.10/fs/pnode.h @@ -29,6 +29,12 @@ static inline void set_mnt_shared(struct mnt->mnt_flags |= MNT_SHARED; } +/* return the next shared peer mount of @p */ +static inline struct vfsmount *next_peer(struct vfsmount *p) +{ + return list_entry(p->mnt_share.next, struct vfsmount, mnt_share); +} + void change_mnt_propagation(struct vfsmount *, int); int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, struct list_head *);