diff options
author | Maxim Patlasov <mpatlasov@virtuozzo.com> | 2016-02-16 14:45:33 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-02-20 00:15:52 -0500 |
commit | 7ae8fd0351f912b075149a1e03a017be8b903b9a (patch) | |
tree | 27f04af171e1ad217868cbc7b3a433655ed7fe3d /fs/pnode.c | |
parent | 0bacbe528e26422e424d110ebda4ec68ea0fd5eb (diff) |
fs/pnode.c: treat zero mnt_group_id-s as unequal
propagate_one(m) calculates "type" argument for copy_tree() like this:
> if (m->mnt_group_id == last_dest->mnt_group_id) {
> type = CL_MAKE_SHARED;
> } else {
> type = CL_SLAVE;
> if (IS_MNT_SHARED(m))
> type |= CL_MAKE_SHARED;
> }
The "type" argument then governs clone_mnt() behavior with respect to flags
and mnt_master of new mount. When we iterate through a slave group, it is
possible that both current "m" and "last_dest" are not shared (although,
both are slaves, i.e. have non-NULL mnt_master-s). Then the comparison
above erroneously makes new mount shared and sets its mnt_master to
last_source->mnt_master. The patch fixes the problem by handling zero
mnt_group_id-s as though they are unequal.
The similar problem exists in the implementation of "else" clause above
when we have to ascend upward in the master/slave tree by calling:
> last_source = last_source->mnt_master;
> last_dest = last_source->mnt_parent;
proper number of times. The last step is governed by
"n->mnt_group_id != last_dest->mnt_group_id" condition that may lie if
both are zero. The patch fixes this case in the same way as the former one.
[AV: don't open-code an obvious helper...]
Signed-off-by: Maxim Patlasov <mpatlasov@virtuozzo.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/pnode.c')
-rw-r--r-- | fs/pnode.c | 9 |
1 files changed, 7 insertions, 2 deletions
diff --git a/fs/pnode.c b/fs/pnode.c index 6367e1e435c6..c524fdddc7fb 100644 --- a/fs/pnode.c +++ b/fs/pnode.c | |||
@@ -202,6 +202,11 @@ static struct mount *last_dest, *last_source, *dest_master; | |||
202 | static struct mountpoint *mp; | 202 | static struct mountpoint *mp; |
203 | static struct hlist_head *list; | 203 | static struct hlist_head *list; |
204 | 204 | ||
205 | static inline bool peers(struct mount *m1, struct mount *m2) | ||
206 | { | ||
207 | return m1->mnt_group_id == m2->mnt_group_id && m1->mnt_group_id; | ||
208 | } | ||
209 | |||
205 | static int propagate_one(struct mount *m) | 210 | static int propagate_one(struct mount *m) |
206 | { | 211 | { |
207 | struct mount *child; | 212 | struct mount *child; |
@@ -212,7 +217,7 @@ static int propagate_one(struct mount *m) | |||
212 | /* skip if mountpoint isn't covered by it */ | 217 | /* skip if mountpoint isn't covered by it */ |
213 | if (!is_subdir(mp->m_dentry, m->mnt.mnt_root)) | 218 | if (!is_subdir(mp->m_dentry, m->mnt.mnt_root)) |
214 | return 0; | 219 | return 0; |
215 | if (m->mnt_group_id == last_dest->mnt_group_id) { | 220 | if (peers(m, last_dest)) { |
216 | type = CL_MAKE_SHARED; | 221 | type = CL_MAKE_SHARED; |
217 | } else { | 222 | } else { |
218 | struct mount *n, *p; | 223 | struct mount *n, *p; |
@@ -223,7 +228,7 @@ static int propagate_one(struct mount *m) | |||
223 | last_source = last_source->mnt_master; | 228 | last_source = last_source->mnt_master; |
224 | last_dest = last_source->mnt_parent; | 229 | last_dest = last_source->mnt_parent; |
225 | } | 230 | } |
226 | if (n->mnt_group_id != last_dest->mnt_group_id) { | 231 | if (!peers(n, last_dest)) { |
227 | last_source = last_source->mnt_master; | 232 | last_source = last_source->mnt_master; |
228 | last_dest = last_source->mnt_parent; | 233 | last_dest = last_source->mnt_parent; |
229 | } | 234 | } |