diff options
-rw-r--r-- | Documentation/filesystems/proc.txt | 6 | ||||
-rw-r--r-- | fs/namespace.c | 9 | ||||
-rw-r--r-- | fs/pnode.c | 51 | ||||
-rw-r--r-- | fs/pnode.h | 1 |
4 files changed, 65 insertions, 2 deletions
diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt index 2cd920f92e5e..2a99116edc47 100644 --- a/Documentation/filesystems/proc.txt +++ b/Documentation/filesystems/proc.txt | |||
@@ -2374,8 +2374,14 @@ possible optional fields are: | |||
2374 | 2374 | ||
2375 | shared:X mount is shared in peer group X | 2375 | shared:X mount is shared in peer group X |
2376 | master:X mount is slave to peer group X | 2376 | master:X mount is slave to peer group X |
2377 | propagate_from:X mount is slave and receives propagation from peer group X (*) | ||
2377 | unbindable mount is unbindable | 2378 | unbindable mount is unbindable |
2378 | 2379 | ||
2380 | (*) X is the closest dominant peer group under the process's root. If | ||
2381 | X is the immediate master of the mount, or if there's no dominant peer | ||
2382 | group under the same root, then only the "master:X" field is present | ||
2383 | and not the "propagate_from:X" field. | ||
2384 | |||
2379 | For more information on mount propagation see: | 2385 | For more information on mount propagation see: |
2380 | 2386 | ||
2381 | Documentation/filesystems/sharedsubtree.txt | 2387 | Documentation/filesystems/sharedsubtree.txt |
diff --git a/fs/namespace.c b/fs/namespace.c index c807b8d5f891..0505fb61aa74 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
@@ -850,8 +850,13 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
850 | /* Tagged fields ("foo:X" or "bar") */ | 850 | /* Tagged fields ("foo:X" or "bar") */ |
851 | if (IS_MNT_SHARED(mnt)) | 851 | if (IS_MNT_SHARED(mnt)) |
852 | seq_printf(m, " shared:%i", mnt->mnt_group_id); | 852 | seq_printf(m, " shared:%i", mnt->mnt_group_id); |
853 | if (IS_MNT_SLAVE(mnt)) | 853 | if (IS_MNT_SLAVE(mnt)) { |
854 | seq_printf(m, " master:%i", mnt->mnt_master->mnt_group_id); | 854 | int master = mnt->mnt_master->mnt_group_id; |
855 | int dom = get_dominating_id(mnt, &p->root); | ||
856 | seq_printf(m, " master:%i", master); | ||
857 | if (dom && dom != master) | ||
858 | seq_printf(m, " propagate_from:%i", dom); | ||
859 | } | ||
855 | if (IS_MNT_UNBINDABLE(mnt)) | 860 | if (IS_MNT_UNBINDABLE(mnt)) |
856 | seq_puts(m, " unbindable"); | 861 | seq_puts(m, " unbindable"); |
857 | 862 | ||
diff --git a/fs/pnode.c b/fs/pnode.c index d18d66491a01..8d5f392ec3d3 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -28,6 +28,57 @@ static inline struct vfsmount *next_slave(struct vfsmount *p) | |||
28 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); | 28 | return list_entry(p->mnt_slave.next, struct vfsmount, mnt_slave); |
29 | } | 29 | } |
30 | 30 | ||
31 | /* | ||
32 | * Return true if path is reachable from root | ||
33 | * | ||
34 | * namespace_sem is held, and mnt is attached | ||
35 | */ | ||
36 | static bool is_path_reachable(struct vfsmount *mnt, struct dentry *dentry, | ||
37 | const struct path *root) | ||
38 | { | ||
39 | while (mnt != root->mnt && mnt->mnt_parent != mnt) { | ||
40 | dentry = mnt->mnt_mountpoint; | ||
41 | mnt = mnt->mnt_parent; | ||
42 | } | ||
43 | return mnt == root->mnt && is_subdir(dentry, root->dentry); | ||
44 | } | ||
45 | |||
46 | static struct vfsmount *get_peer_under_root(struct vfsmount *mnt, | ||
47 | struct mnt_namespace *ns, | ||
48 | const struct path *root) | ||
49 | { | ||
50 | struct vfsmount *m = mnt; | ||
51 | |||
52 | do { | ||
53 | /* Check the namespace first for optimization */ | ||
54 | if (m->mnt_ns == ns && is_path_reachable(m, m->mnt_root, root)) | ||
55 | return m; | ||
56 | |||
57 | m = next_peer(m); | ||
58 | } while (m != mnt); | ||
59 | |||
60 | return NULL; | ||
61 | } | ||
62 | |||
63 | /* | ||
64 | * Get ID of closest dominating peer group having a representative | ||
65 | * under the given root. | ||
66 | * | ||
67 | * Caller must hold namespace_sem | ||
68 | */ | ||
69 | int get_dominating_id(struct vfsmount *mnt, const struct path *root) | ||
70 | { | ||
71 | struct vfsmount *m; | ||
72 | |||
73 | for (m = mnt->mnt_master; m != NULL; m = m->mnt_master) { | ||
74 | struct vfsmount *d = get_peer_under_root(m, mnt->mnt_ns, root); | ||
75 | if (d) | ||
76 | return d->mnt_group_id; | ||
77 | } | ||
78 | |||
79 | return 0; | ||
80 | } | ||
81 | |||
31 | static int do_make_slave(struct vfsmount *mnt) | 82 | static int do_make_slave(struct vfsmount *mnt) |
32 | { | 83 | { |
33 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; | 84 | struct vfsmount *peer_mnt = mnt, *master = mnt->mnt_master; |
diff --git a/fs/pnode.h b/fs/pnode.h index 973c3f825e7d..958665d662af 100644 --- a/fs/pnode.h +++ b/fs/pnode.h | |||
@@ -36,4 +36,5 @@ int propagate_mnt(struct vfsmount *, struct dentry *, struct vfsmount *, | |||
36 | int propagate_umount(struct list_head *); | 36 | int propagate_umount(struct list_head *); |
37 | int propagate_mount_busy(struct vfsmount *, int); | 37 | int propagate_mount_busy(struct vfsmount *, int); |
38 | void mnt_release_group_id(struct vfsmount *); | 38 | void mnt_release_group_id(struct vfsmount *); |
39 | int get_dominating_id(struct vfsmount *mnt, const struct path *root); | ||
39 | #endif /* _LINUX_PNODE_H */ | 40 | #endif /* _LINUX_PNODE_H */ |