aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2005-11-07 17:20:17 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 21:18:11 -0500
commita05964f3917c7c55368c229d7985f8e7c9977e97 (patch)
tree7ec25550267ef050572c00ba2f37d6a4ff9c469e /fs/namespace.c
parent2144440327fa01b2f3f65e355120a78211685702 (diff)
[PATCH] shared mounts handling: umount
An unmount of a mount creates a umount event on the parent. If the parent is a shared mount, it gets propagated to all mounts in the peer group. Signed-off-by: Ram Pai <linuxram@us.ibm.com> Signed-off-by: Al Viro <viro@zeniv.linux.org.uk> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/namespace.c')
-rw-r--r--fs/namespace.c56
1 files changed, 38 insertions, 18 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index 1487982dbc24..4b1af01c2fb4 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -86,31 +86,44 @@ void free_vfsmnt(struct vfsmount *mnt)
86} 86}
87 87
88/* 88/*
89 * Now, lookup_mnt increments the ref count before returning 89 * find the first or last mount at @dentry on vfsmount @mnt depending on
90 * the vfsmount struct. 90 * @dir. If @dir is set return the first mount else return the last mount.
91 */ 91 */
92struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry) 92struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
93 int dir)
93{ 94{
94 struct list_head *head = mount_hashtable + hash(mnt, dentry); 95 struct list_head *head = mount_hashtable + hash(mnt, dentry);
95 struct list_head *tmp = head; 96 struct list_head *tmp = head;
96 struct vfsmount *p, *found = NULL; 97 struct vfsmount *p, *found = NULL;
97 98
98 spin_lock(&vfsmount_lock);
99 for (;;) { 99 for (;;) {
100 tmp = tmp->next; 100 tmp = dir ? tmp->next : tmp->prev;
101 p = NULL; 101 p = NULL;
102 if (tmp == head) 102 if (tmp == head)
103 break; 103 break;
104 p = list_entry(tmp, struct vfsmount, mnt_hash); 104 p = list_entry(tmp, struct vfsmount, mnt_hash);
105 if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) { 105 if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
106 found = mntget(p); 106 found = p;
107 break; 107 break;
108 } 108 }
109 } 109 }
110 spin_unlock(&vfsmount_lock);
111 return found; 110 return found;
112} 111}
113 112
113/*
114 * lookup_mnt increments the ref count before returning
115 * the vfsmount struct.
116 */
117struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
118{
119 struct vfsmount *child_mnt;
120 spin_lock(&vfsmount_lock);
121 if ((child_mnt = __lookup_mnt(mnt, dentry, 1)))
122 mntget(child_mnt);
123 spin_unlock(&vfsmount_lock);
124 return child_mnt;
125}
126
114static inline int check_mnt(struct vfsmount *mnt) 127static inline int check_mnt(struct vfsmount *mnt)
115{ 128{
116 return mnt->mnt_namespace == current->namespace; 129 return mnt->mnt_namespace == current->namespace;
@@ -404,9 +417,12 @@ EXPORT_SYMBOL(may_umount_tree);
404 */ 417 */
405int may_umount(struct vfsmount *mnt) 418int may_umount(struct vfsmount *mnt)
406{ 419{
407 if (atomic_read(&mnt->mnt_count) > 2) 420 int ret = 0;
408 return -EBUSY; 421 spin_lock(&vfsmount_lock);
409 return 0; 422 if (propagate_mount_busy(mnt, 2))
423 ret = -EBUSY;
424 spin_unlock(&vfsmount_lock);
425 return ret;
410} 426}
411 427
412EXPORT_SYMBOL(may_umount); 428EXPORT_SYMBOL(may_umount);
@@ -433,7 +449,7 @@ void release_mounts(struct list_head *head)
433 } 449 }
434} 450}
435 451
436void umount_tree(struct vfsmount *mnt, struct list_head *kill) 452void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
437{ 453{
438 struct vfsmount *p; 454 struct vfsmount *p;
439 455
@@ -442,6 +458,9 @@ void umount_tree(struct vfsmount *mnt, struct list_head *kill)
442 list_add(&p->mnt_hash, kill); 458 list_add(&p->mnt_hash, kill);
443 } 459 }
444 460
461 if (propagate)
462 propagate_umount(kill);
463
445 list_for_each_entry(p, kill, mnt_hash) { 464 list_for_each_entry(p, kill, mnt_hash) {
446 list_del_init(&p->mnt_expire); 465 list_del_init(&p->mnt_expire);
447 list_del_init(&p->mnt_list); 466 list_del_init(&p->mnt_list);
@@ -450,6 +469,7 @@ void umount_tree(struct vfsmount *mnt, struct list_head *kill)
450 list_del_init(&p->mnt_child); 469 list_del_init(&p->mnt_child);
451 if (p->mnt_parent != p) 470 if (p->mnt_parent != p)
452 mnt->mnt_mountpoint->d_mounted--; 471 mnt->mnt_mountpoint->d_mounted--;
472 change_mnt_propagation(p, MS_PRIVATE);
453 } 473 }
454} 474}
455 475
@@ -526,9 +546,9 @@ static int do_umount(struct vfsmount *mnt, int flags)
526 event++; 546 event++;
527 547
528 retval = -EBUSY; 548 retval = -EBUSY;
529 if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { 549 if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
530 if (!list_empty(&mnt->mnt_list)) 550 if (!list_empty(&mnt->mnt_list))
531 umount_tree(mnt, &umount_list); 551 umount_tree(mnt, 1, &umount_list);
532 retval = 0; 552 retval = 0;
533 } 553 }
534 spin_unlock(&vfsmount_lock); 554 spin_unlock(&vfsmount_lock);
@@ -651,7 +671,7 @@ Enomem:
651 if (res) { 671 if (res) {
652 LIST_HEAD(umount_list); 672 LIST_HEAD(umount_list);
653 spin_lock(&vfsmount_lock); 673 spin_lock(&vfsmount_lock);
654 umount_tree(res, &umount_list); 674 umount_tree(res, 0, &umount_list);
655 spin_unlock(&vfsmount_lock); 675 spin_unlock(&vfsmount_lock);
656 release_mounts(&umount_list); 676 release_mounts(&umount_list);
657 } 677 }
@@ -827,7 +847,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
827 if (err) { 847 if (err) {
828 LIST_HEAD(umount_list); 848 LIST_HEAD(umount_list);
829 spin_lock(&vfsmount_lock); 849 spin_lock(&vfsmount_lock);
830 umount_tree(mnt, &umount_list); 850 umount_tree(mnt, 0, &umount_list);
831 spin_unlock(&vfsmount_lock); 851 spin_unlock(&vfsmount_lock);
832 release_mounts(&umount_list); 852 release_mounts(&umount_list);
833 } 853 }
@@ -1023,12 +1043,12 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
1023 * Check that it is still dead: the count should now be 2 - as 1043 * Check that it is still dead: the count should now be 2 - as
1024 * contributed by the vfsmount parent and the mntget above 1044 * contributed by the vfsmount parent and the mntget above
1025 */ 1045 */
1026 if (atomic_read(&mnt->mnt_count) == 2) { 1046 if (!propagate_mount_busy(mnt, 2)) {
1027 /* delete from the namespace */ 1047 /* delete from the namespace */
1028 touch_namespace(mnt->mnt_namespace); 1048 touch_namespace(mnt->mnt_namespace);
1029 list_del_init(&mnt->mnt_list); 1049 list_del_init(&mnt->mnt_list);
1030 mnt->mnt_namespace = NULL; 1050 mnt->mnt_namespace = NULL;
1031 umount_tree(mnt, umounts); 1051 umount_tree(mnt, 1, umounts);
1032 spin_unlock(&vfsmount_lock); 1052 spin_unlock(&vfsmount_lock);
1033 } else { 1053 } else {
1034 /* 1054 /*
@@ -1647,7 +1667,7 @@ void __put_namespace(struct namespace *namespace)
1647 spin_unlock(&vfsmount_lock); 1667 spin_unlock(&vfsmount_lock);
1648 down_write(&namespace_sem); 1668 down_write(&namespace_sem);
1649 spin_lock(&vfsmount_lock); 1669 spin_lock(&vfsmount_lock);
1650 umount_tree(root, &umount_list); 1670 umount_tree(root, 0, &umount_list);
1651 spin_unlock(&vfsmount_lock); 1671 spin_unlock(&vfsmount_lock);
1652 up_write(&namespace_sem); 1672 up_write(&namespace_sem);
1653 release_mounts(&umount_list); 1673 release_mounts(&umount_list);