aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c11
-rw-r--r--fs/pnode.c198
-rw-r--r--fs/pnode.h3
-rw-r--r--include/linux/mount.h3
4 files changed, 133 insertions, 82 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 2ffc5a2905d4..65233a5f390a 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -885,7 +885,7 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root,
885 goto out_free; 885 goto out_free;
886 } 886 }
887 887
888 mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~MNT_WRITE_HOLD; 888 mnt->mnt.mnt_flags = old->mnt.mnt_flags & ~(MNT_WRITE_HOLD|MNT_MARKED);
889 /* Don't allow unprivileged users to change mount flags */ 889 /* Don't allow unprivileged users to change mount flags */
890 if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY)) 890 if ((flag & CL_UNPRIVILEGED) && (mnt->mnt.mnt_flags & MNT_READONLY))
891 mnt->mnt.mnt_flags |= MNT_LOCK_READONLY; 891 mnt->mnt.mnt_flags |= MNT_LOCK_READONLY;
@@ -1661,9 +1661,9 @@ static int attach_recursive_mnt(struct mount *source_mnt,
1661 if (err) 1661 if (err)
1662 goto out; 1662 goto out;
1663 err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list); 1663 err = propagate_mnt(dest_mnt, dest_mp, source_mnt, &tree_list);
1664 lock_mount_hash();
1664 if (err) 1665 if (err)
1665 goto out_cleanup_ids; 1666 goto out_cleanup_ids;
1666 lock_mount_hash();
1667 for (p = source_mnt; p; p = next_mnt(p, source_mnt)) 1667 for (p = source_mnt; p; p = next_mnt(p, source_mnt))
1668 set_mnt_shared(p); 1668 set_mnt_shared(p);
1669 } else { 1669 } else {
@@ -1690,6 +1690,11 @@ static int attach_recursive_mnt(struct mount *source_mnt,
1690 return 0; 1690 return 0;
1691 1691
1692 out_cleanup_ids: 1692 out_cleanup_ids:
1693 while (!hlist_empty(&tree_list)) {
1694 child = hlist_entry(tree_list.first, struct mount, mnt_hash);
1695 umount_tree(child, 0);
1696 }
1697 unlock_mount_hash();
1693 cleanup_group_ids(source_mnt, NULL); 1698 cleanup_group_ids(source_mnt, NULL);
1694 out: 1699 out:
1695 return err; 1700 return err;
@@ -2044,7 +2049,7 @@ static int do_add_mount(struct mount *newmnt, struct path *path, int mnt_flags)
2044 struct mount *parent; 2049 struct mount *parent;
2045 int err; 2050 int err;
2046 2051
2047 mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | MNT_DOOMED | MNT_SYNC_UMOUNT); 2052 mnt_flags &= ~MNT_INTERNAL_FLAGS;
2048 2053
2049 mp = lock_mount(path); 2054 mp = lock_mount(path);
2050 if (IS_ERR(mp)) 2055 if (IS_ERR(mp))
diff --git a/fs/pnode.c b/fs/pnode.c
index 88396df725b4..302bf22c4a30 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -164,46 +164,94 @@ static struct mount *propagation_next(struct mount *m,
164 } 164 }
165} 165}
166 166
167/* 167static struct mount *next_group(struct mount *m, struct mount *origin)
168 * return the source mount to be used for cloning
169 *
170 * @dest the current destination mount
171 * @last_dest the last seen destination mount
172 * @last_src the last seen source mount
173 * @type return CL_SLAVE if the new mount has to be
174 * cloned as a slave.
175 */
176static struct mount *get_source(struct mount *dest,
177 struct mount *last_dest,
178 struct mount *last_src,
179 int *type)
180{ 168{
181 struct mount *p_last_src = NULL; 169 while (1) {
182 struct mount *p_last_dest = NULL; 170 while (1) {
183 171 struct mount *next;
184 while (last_dest != dest->mnt_master) { 172 if (!IS_MNT_NEW(m) && !list_empty(&m->mnt_slave_list))
185 p_last_dest = last_dest; 173 return first_slave(m);
186 p_last_src = last_src; 174 next = next_peer(m);
187 last_dest = last_dest->mnt_master; 175 if (m->mnt_group_id == origin->mnt_group_id) {
188 last_src = last_src->mnt_master; 176 if (next == origin)
177 return NULL;
178 } else if (m->mnt_slave.next != &next->mnt_slave)
179 break;
180 m = next;
181 }
182 /* m is the last peer */
183 while (1) {
184 struct mount *master = m->mnt_master;
185 if (m->mnt_slave.next != &master->mnt_slave_list)
186 return next_slave(m);
187 m = next_peer(master);
188 if (master->mnt_group_id == origin->mnt_group_id)
189 break;
190 if (master->mnt_slave.next == &m->mnt_slave)
191 break;
192 m = master;
193 }
194 if (m == origin)
195 return NULL;
189 } 196 }
197}
190 198
191 if (p_last_dest) { 199/* all accesses are serialized by namespace_sem */
192 do { 200static struct user_namespace *user_ns;
193 p_last_dest = next_peer(p_last_dest); 201static struct mount *last_dest, *last_source, *dest_master;
194 } while (IS_MNT_NEW(p_last_dest)); 202static struct mountpoint *mp;
195 /* is that a peer of the earlier? */ 203static struct hlist_head *list;
196 if (dest == p_last_dest) { 204
197 *type = CL_MAKE_SHARED; 205static int propagate_one(struct mount *m)
198 return p_last_src; 206{
207 struct mount *child;
208 int type;
209 /* skip ones added by this propagate_mnt() */
210 if (IS_MNT_NEW(m))
211 return 0;
212 /* skip if mountpoint isn't covered by it */
213 if (!is_subdir(mp->m_dentry, m->mnt.mnt_root))
214 return 0;
215 if (m->mnt_group_id == last_dest->mnt_group_id) {
216 type = CL_MAKE_SHARED;
217 } else {
218 struct mount *n, *p;
219 for (n = m; ; n = p) {
220 p = n->mnt_master;
221 if (p == dest_master || IS_MNT_MARKED(p)) {
222 while (last_dest->mnt_master != p) {
223 last_source = last_source->mnt_master;
224 last_dest = last_source->mnt_parent;
225 }
226 if (n->mnt_group_id != last_dest->mnt_group_id) {
227 last_source = last_source->mnt_master;
228 last_dest = last_source->mnt_parent;
229 }
230 break;
231 }
199 } 232 }
233 type = CL_SLAVE;
234 /* beginning of peer group among the slaves? */
235 if (IS_MNT_SHARED(m))
236 type |= CL_MAKE_SHARED;
200 } 237 }
201 /* slave of the earlier, then */ 238
202 *type = CL_SLAVE; 239 /* Notice when we are propagating across user namespaces */
203 /* beginning of peer group among the slaves? */ 240 if (m->mnt_ns->user_ns != user_ns)
204 if (IS_MNT_SHARED(dest)) 241 type |= CL_UNPRIVILEGED;
205 *type |= CL_MAKE_SHARED; 242 child = copy_tree(last_source, last_source->mnt.mnt_root, type);
206 return last_src; 243 if (IS_ERR(child))
244 return PTR_ERR(child);
245 mnt_set_mountpoint(m, mp, child);
246 last_dest = m;
247 last_source = child;
248 if (m->mnt_master != dest_master) {
249 read_seqlock_excl(&mount_lock);
250 SET_MNT_MARK(m->mnt_master);
251 read_sequnlock_excl(&mount_lock);
252 }
253 hlist_add_head(&child->mnt_hash, list);
254 return 0;
207} 255}
208 256
209/* 257/*
@@ -222,56 +270,48 @@ static struct mount *get_source(struct mount *dest,
222int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp, 270int propagate_mnt(struct mount *dest_mnt, struct mountpoint *dest_mp,
223 struct mount *source_mnt, struct hlist_head *tree_list) 271 struct mount *source_mnt, struct hlist_head *tree_list)
224{ 272{
225 struct user_namespace *user_ns = current->nsproxy->mnt_ns->user_ns; 273 struct mount *m, *n;
226 struct mount *m, *child;
227 int ret = 0; 274 int ret = 0;
228 struct mount *prev_dest_mnt = dest_mnt; 275
229 struct mount *prev_src_mnt = source_mnt; 276 /*
230 HLIST_HEAD(tmp_list); 277 * we don't want to bother passing tons of arguments to
231 278 * propagate_one(); everything is serialized by namespace_sem,
232 for (m = propagation_next(dest_mnt, dest_mnt); m; 279 * so globals will do just fine.
233 m = propagation_next(m, dest_mnt)) { 280 */
234 int type; 281 user_ns = current->nsproxy->mnt_ns->user_ns;
235 struct mount *source; 282 last_dest = dest_mnt;
236 283 last_source = source_mnt;
237 if (IS_MNT_NEW(m)) 284 mp = dest_mp;
238 continue; 285 list = tree_list;
239 286 dest_master = dest_mnt->mnt_master;
240 source = get_source(m, prev_dest_mnt, prev_src_mnt, &type); 287
241 288 /* all peers of dest_mnt, except dest_mnt itself */
242 /* Notice when we are propagating across user namespaces */ 289 for (n = next_peer(dest_mnt); n != dest_mnt; n = next_peer(n)) {
243 if (m->mnt_ns->user_ns != user_ns) 290 ret = propagate_one(n);
244 type |= CL_UNPRIVILEGED; 291 if (ret)
245
246 child = copy_tree(source, source->mnt.mnt_root, type);
247 if (IS_ERR(child)) {
248 ret = PTR_ERR(child);
249 tmp_list = *tree_list;
250 tmp_list.first->pprev = &tmp_list.first;
251 INIT_HLIST_HEAD(tree_list);
252 goto out; 292 goto out;
253 } 293 }
254 294
255 if (is_subdir(dest_mp->m_dentry, m->mnt.mnt_root)) { 295 /* all slave groups */
256 mnt_set_mountpoint(m, dest_mp, child); 296 for (m = next_group(dest_mnt, dest_mnt); m;
257 hlist_add_head(&child->mnt_hash, tree_list); 297 m = next_group(m, dest_mnt)) {
258 } else { 298 /* everything in that slave group */
259 /* 299 n = m;
260 * This can happen if the parent mount was bind mounted 300 do {
261 * on some subdirectory of a shared/slave mount. 301 ret = propagate_one(n);
262 */ 302 if (ret)
263 hlist_add_head(&child->mnt_hash, &tmp_list); 303 goto out;
264 } 304 n = next_peer(n);
265 prev_dest_mnt = m; 305 } while (n != m);
266 prev_src_mnt = child;
267 } 306 }
268out: 307out:
269 lock_mount_hash(); 308 read_seqlock_excl(&mount_lock);
270 while (!hlist_empty(&tmp_list)) { 309 hlist_for_each_entry(n, tree_list, mnt_hash) {
271 child = hlist_entry(tmp_list.first, struct mount, mnt_hash); 310 m = n->mnt_parent;
272 umount_tree(child, 0); 311 if (m->mnt_master != dest_mnt->mnt_master)
312 CLEAR_MNT_MARK(m->mnt_master);
273 } 313 }
274 unlock_mount_hash(); 314 read_sequnlock_excl(&mount_lock);
275 return ret; 315 return ret;
276} 316}
277 317
diff --git a/fs/pnode.h b/fs/pnode.h
index fc28a27fa892..4a246358b031 100644
--- a/fs/pnode.h
+++ b/fs/pnode.h
@@ -16,6 +16,9 @@
16#define IS_MNT_NEW(m) (!(m)->mnt_ns) 16#define IS_MNT_NEW(m) (!(m)->mnt_ns)
17#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED) 17#define CLEAR_MNT_SHARED(m) ((m)->mnt.mnt_flags &= ~MNT_SHARED)
18#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE) 18#define IS_MNT_UNBINDABLE(m) ((m)->mnt.mnt_flags & MNT_UNBINDABLE)
19#define IS_MNT_MARKED(m) ((m)->mnt.mnt_flags & MNT_MARKED)
20#define SET_MNT_MARK(m) ((m)->mnt.mnt_flags |= MNT_MARKED)
21#define CLEAR_MNT_MARK(m) ((m)->mnt.mnt_flags &= ~MNT_MARKED)
19 22
20#define CL_EXPIRE 0x01 23#define CL_EXPIRE 0x01
21#define CL_SLAVE 0x02 24#define CL_SLAVE 0x02
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 371d346fa270..839bac270904 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -44,6 +44,8 @@ struct mnt_namespace;
44#define MNT_SHARED_MASK (MNT_UNBINDABLE) 44#define MNT_SHARED_MASK (MNT_UNBINDABLE)
45#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE) 45#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE)
46 46
47#define MNT_INTERNAL_FLAGS (MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL | \
48 MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
47 49
48#define MNT_INTERNAL 0x4000 50#define MNT_INTERNAL 0x4000
49 51
@@ -51,6 +53,7 @@ struct mnt_namespace;
51#define MNT_LOCKED 0x800000 53#define MNT_LOCKED 0x800000
52#define MNT_DOOMED 0x1000000 54#define MNT_DOOMED 0x1000000
53#define MNT_SYNC_UMOUNT 0x2000000 55#define MNT_SYNC_UMOUNT 0x2000000
56#define MNT_MARKED 0x4000000
54 57
55struct vfsmount { 58struct vfsmount {
56 struct dentry *mnt_root; /* root of the mounted tree */ 59 struct dentry *mnt_root; /* root of the mounted tree */