aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/namespace.c93
-rw-r--r--fs/pnode.c5
-rw-r--r--include/linux/mount.h1
3 files changed, 95 insertions, 4 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 8ca6317cb401..cefa1d9939b0 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -41,6 +41,7 @@ __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock);
41 41
42static int event; 42static int event;
43static DEFINE_IDA(mnt_id_ida); 43static DEFINE_IDA(mnt_id_ida);
44static DEFINE_IDA(mnt_group_ida);
44 45
45static struct list_head *mount_hashtable __read_mostly; 46static struct list_head *mount_hashtable __read_mostly;
46static struct kmem_cache *mnt_cache __read_mostly; 47static struct kmem_cache *mnt_cache __read_mostly;
@@ -83,6 +84,28 @@ static void mnt_free_id(struct vfsmount *mnt)
83 spin_unlock(&vfsmount_lock); 84 spin_unlock(&vfsmount_lock);
84} 85}
85 86
87/*
88 * Allocate a new peer group ID
89 *
90 * mnt_group_ida is protected by namespace_sem
91 */
92static int mnt_alloc_group_id(struct vfsmount *mnt)
93{
94 if (!ida_pre_get(&mnt_group_ida, GFP_KERNEL))
95 return -ENOMEM;
96
97 return ida_get_new_above(&mnt_group_ida, 1, &mnt->mnt_group_id);
98}
99
100/*
101 * Release a peer group ID
102 */
103void mnt_release_group_id(struct vfsmount *mnt)
104{
105 ida_remove(&mnt_group_ida, mnt->mnt_group_id);
106 mnt->mnt_group_id = 0;
107}
108
86struct vfsmount *alloc_vfsmnt(const char *name) 109struct vfsmount *alloc_vfsmnt(const char *name)
87{ 110{
88 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); 111 struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
@@ -533,6 +556,17 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
533 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); 556 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
534 557
535 if (mnt) { 558 if (mnt) {
559 if (flag & (CL_SLAVE | CL_PRIVATE))
560 mnt->mnt_group_id = 0; /* not a peer of original */
561 else
562 mnt->mnt_group_id = old->mnt_group_id;
563
564 if ((flag & CL_MAKE_SHARED) && !mnt->mnt_group_id) {
565 int err = mnt_alloc_group_id(mnt);
566 if (err)
567 goto out_free;
568 }
569
536 mnt->mnt_flags = old->mnt_flags; 570 mnt->mnt_flags = old->mnt_flags;
537 atomic_inc(&sb->s_active); 571 atomic_inc(&sb->s_active);
538 mnt->mnt_sb = sb; 572 mnt->mnt_sb = sb;
@@ -562,6 +596,10 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
562 } 596 }
563 } 597 }
564 return mnt; 598 return mnt;
599
600 out_free:
601 free_vfsmnt(mnt);
602 return NULL;
565} 603}
566 604
567static inline void __mntput(struct vfsmount *mnt) 605static inline void __mntput(struct vfsmount *mnt)
@@ -1142,6 +1180,33 @@ void drop_collected_mounts(struct vfsmount *mnt)
1142 release_mounts(&umount_list); 1180 release_mounts(&umount_list);
1143} 1181}
1144 1182
1183static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
1184{
1185 struct vfsmount *p;
1186
1187 for (p = mnt; p != end; p = next_mnt(p, mnt)) {
1188 if (p->mnt_group_id && !IS_MNT_SHARED(p))
1189 mnt_release_group_id(p);
1190 }
1191}
1192
1193static int invent_group_ids(struct vfsmount *mnt, bool recurse)
1194{
1195 struct vfsmount *p;
1196
1197 for (p = mnt; p; p = recurse ? next_mnt(p, mnt) : NULL) {
1198 if (!p->mnt_group_id && !IS_MNT_SHARED(p)) {
1199 int err = mnt_alloc_group_id(p);
1200 if (err) {
1201 cleanup_group_ids(mnt, p);
1202 return err;
1203 }
1204 }
1205 }
1206
1207 return 0;
1208}
1209
1145/* 1210/*
1146 * @source_mnt : mount tree to be attached 1211 * @source_mnt : mount tree to be attached
1147 * @nd : place the mount tree @source_mnt is attached 1212 * @nd : place the mount tree @source_mnt is attached
@@ -1212,9 +1277,16 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
1212 struct vfsmount *dest_mnt = path->mnt; 1277 struct vfsmount *dest_mnt = path->mnt;
1213 struct dentry *dest_dentry = path->dentry; 1278 struct dentry *dest_dentry = path->dentry;
1214 struct vfsmount *child, *p; 1279 struct vfsmount *child, *p;
1280 int err;
1215 1281
1216 if (propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list)) 1282 if (IS_MNT_SHARED(dest_mnt)) {
1217 return -EINVAL; 1283 err = invent_group_ids(source_mnt, true);
1284 if (err)
1285 goto out;
1286 }
1287 err = propagate_mnt(dest_mnt, dest_dentry, source_mnt, &tree_list);
1288 if (err)
1289 goto out_cleanup_ids;
1218 1290
1219 if (IS_MNT_SHARED(dest_mnt)) { 1291 if (IS_MNT_SHARED(dest_mnt)) {
1220 for (p = source_mnt; p; p = next_mnt(p, source_mnt)) 1292 for (p = source_mnt; p; p = next_mnt(p, source_mnt))
@@ -1237,6 +1309,12 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
1237 } 1309 }
1238 spin_unlock(&vfsmount_lock); 1310 spin_unlock(&vfsmount_lock);
1239 return 0; 1311 return 0;
1312
1313 out_cleanup_ids:
1314 if (IS_MNT_SHARED(dest_mnt))
1315 cleanup_group_ids(source_mnt, NULL);
1316 out:
1317 return err;
1240} 1318}
1241 1319
1242static int graft_tree(struct vfsmount *mnt, struct path *path) 1320static int graft_tree(struct vfsmount *mnt, struct path *path)
@@ -1277,6 +1355,7 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
1277 struct vfsmount *m, *mnt = nd->path.mnt; 1355 struct vfsmount *m, *mnt = nd->path.mnt;
1278 int recurse = flag & MS_REC; 1356 int recurse = flag & MS_REC;
1279 int type = flag & ~MS_REC; 1357 int type = flag & ~MS_REC;
1358 int err = 0;
1280 1359
1281 if (!capable(CAP_SYS_ADMIN)) 1360 if (!capable(CAP_SYS_ADMIN))
1282 return -EPERM; 1361 return -EPERM;
@@ -1285,12 +1364,20 @@ static noinline int do_change_type(struct nameidata *nd, int flag)
1285 return -EINVAL; 1364 return -EINVAL;
1286 1365
1287 down_write(&namespace_sem); 1366 down_write(&namespace_sem);
1367 if (type == MS_SHARED) {
1368 err = invent_group_ids(mnt, recurse);
1369 if (err)
1370 goto out_unlock;
1371 }
1372
1288 spin_lock(&vfsmount_lock); 1373 spin_lock(&vfsmount_lock);
1289 for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL)) 1374 for (m = mnt; m; m = (recurse ? next_mnt(m, mnt) : NULL))
1290 change_mnt_propagation(m, type); 1375 change_mnt_propagation(m, type);
1291 spin_unlock(&vfsmount_lock); 1376 spin_unlock(&vfsmount_lock);
1377
1378 out_unlock:
1292 up_write(&namespace_sem); 1379 up_write(&namespace_sem);
1293 return 0; 1380 return err;
1294} 1381}
1295 1382
1296/* 1383/*
diff --git a/fs/pnode.c b/fs/pnode.c
index f968e35d9785..d18d66491a01 100644
--- a/fs/pnode.c
+++ b/fs/pnode.c
@@ -46,7 +46,11 @@ static int do_make_slave(struct vfsmount *mnt)
46 if (peer_mnt == mnt) 46 if (peer_mnt == mnt)
47 peer_mnt = NULL; 47 peer_mnt = NULL;
48 } 48 }
49 if (IS_MNT_SHARED(mnt) && list_empty(&mnt->mnt_share))
50 mnt_release_group_id(mnt);
51
49 list_del_init(&mnt->mnt_share); 52 list_del_init(&mnt->mnt_share);
53 mnt->mnt_group_id = 0;
50 54
51 if (peer_mnt) 55 if (peer_mnt)
52 master = peer_mnt; 56 master = peer_mnt;
@@ -68,7 +72,6 @@ static int do_make_slave(struct vfsmount *mnt)
68 } 72 }
69 mnt->mnt_master = master; 73 mnt->mnt_master = master;
70 CLEAR_MNT_SHARED(mnt); 74 CLEAR_MNT_SHARED(mnt);
71 INIT_LIST_HEAD(&mnt->mnt_slave_list);
72 return 0; 75 return 0;
73} 76}
74 77
diff --git a/include/linux/mount.h b/include/linux/mount.h
index f0dfb17ffccc..b4836d58f428 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -57,6 +57,7 @@ struct vfsmount {
57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */ 57 struct vfsmount *mnt_master; /* slave is on master->mnt_slave_list */
58 struct mnt_namespace *mnt_ns; /* containing namespace */ 58 struct mnt_namespace *mnt_ns; /* containing namespace */
59 int mnt_id; /* mount identifier */ 59 int mnt_id; /* mount identifier */
60 int mnt_group_id; /* peer group identifier */
60 /* 61 /*
61 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 62 * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount
62 * to let these frequently modified fields in a separate cache line 63 * to let these frequently modified fields in a separate cache line