aboutsummaryrefslogtreecommitdiffstats
path: root/fs/namespace.c
diff options
context:
space:
mode:
authorRam Pai <linuxram@us.ibm.com>2005-11-07 17:17:22 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2005-11-07 21:18:10 -0500
commit36341f64569b0c4572478237ec5ed318f0762510 (patch)
treec3babb815d36445d2478581569f6d4c892f0202a /fs/namespace.c
parent70fbcdf4d252c6b17cc249cb9ac9b220cb0b863d (diff)
[PATCH] mount expiry fixes
- clean up the ugliness in may_umount_tree() - fix a bug in do_loopback(). after cloning a tree, do_loopback() unlinks only the topmost mount of the cloned tree, leaving behind the children mounts on their corresponding expiry list. 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.c64
1 files changed, 22 insertions, 42 deletions
diff --git a/fs/namespace.c b/fs/namespace.c
index c2ffa0f349fd..65f9c0ecc21c 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -27,6 +27,8 @@
27 27
28extern int __init init_rootfs(void); 28extern int __init init_rootfs(void);
29 29
30#define CL_EXPIRE 0x01
31
30#ifdef CONFIG_SYSFS 32#ifdef CONFIG_SYSFS
31extern int __init sysfs_init(void); 33extern int __init sysfs_init(void);
32#else 34#else
@@ -165,7 +167,8 @@ static struct vfsmount *next_mnt(struct vfsmount *p, struct vfsmount *root)
165 return list_entry(next, struct vfsmount, mnt_child); 167 return list_entry(next, struct vfsmount, mnt_child);
166} 168}
167 169
168static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root) 170static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
171 int flag)
169{ 172{
170 struct super_block *sb = old->mnt_sb; 173 struct super_block *sb = old->mnt_sb;
171 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname); 174 struct vfsmount *mnt = alloc_vfsmnt(old->mnt_devname);
@@ -181,10 +184,12 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root)
181 184
182 /* stick the duplicate mount on the same expiry list 185 /* stick the duplicate mount on the same expiry list
183 * as the original if that was on one */ 186 * as the original if that was on one */
184 spin_lock(&vfsmount_lock); 187 if (flag & CL_EXPIRE) {
185 if (!list_empty(&old->mnt_expire)) 188 spin_lock(&vfsmount_lock);
186 list_add(&mnt->mnt_expire, &old->mnt_expire); 189 if (!list_empty(&old->mnt_expire))
187 spin_unlock(&vfsmount_lock); 190 list_add(&mnt->mnt_expire, &old->mnt_expire);
191 spin_unlock(&vfsmount_lock);
192 }
188 } 193 }
189 return mnt; 194 return mnt;
190} 195}
@@ -331,36 +336,14 @@ struct seq_operations mounts_op = {
331 */ 336 */
332int may_umount_tree(struct vfsmount *mnt) 337int may_umount_tree(struct vfsmount *mnt)
333{ 338{
334 struct list_head *next; 339 int actual_refs = 0;
335 struct vfsmount *this_parent = mnt; 340 int minimum_refs = 0;
336 int actual_refs; 341 struct vfsmount *p;
337 int minimum_refs;
338 342
339 spin_lock(&vfsmount_lock); 343 spin_lock(&vfsmount_lock);
340 actual_refs = atomic_read(&mnt->mnt_count); 344 for (p = mnt; p; p = next_mnt(p, mnt)) {
341 minimum_refs = 2;
342repeat:
343 next = this_parent->mnt_mounts.next;
344resume:
345 while (next != &this_parent->mnt_mounts) {
346 struct vfsmount *p =
347 list_entry(next, struct vfsmount, mnt_child);
348
349 next = next->next;
350
351 actual_refs += atomic_read(&p->mnt_count); 345 actual_refs += atomic_read(&p->mnt_count);
352 minimum_refs += 2; 346 minimum_refs += 2;
353
354 if (!list_empty(&p->mnt_mounts)) {
355 this_parent = p;
356 goto repeat;
357 }
358 }
359
360 if (this_parent != mnt) {
361 next = this_parent->mnt_child.next;
362 this_parent = this_parent->mnt_parent;
363 goto resume;
364 } 347 }
365 spin_unlock(&vfsmount_lock); 348 spin_unlock(&vfsmount_lock);
366 349
@@ -596,12 +579,13 @@ static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
596 } 579 }
597} 580}
598 581
599static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry) 582static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
583 int flag)
600{ 584{
601 struct vfsmount *res, *p, *q, *r, *s; 585 struct vfsmount *res, *p, *q, *r, *s;
602 struct nameidata nd; 586 struct nameidata nd;
603 587
604 res = q = clone_mnt(mnt, dentry); 588 res = q = clone_mnt(mnt, dentry, flag);
605 if (!q) 589 if (!q)
606 goto Enomem; 590 goto Enomem;
607 q->mnt_mountpoint = mnt->mnt_mountpoint; 591 q->mnt_mountpoint = mnt->mnt_mountpoint;
@@ -619,7 +603,7 @@ static struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry)
619 p = s; 603 p = s;
620 nd.mnt = q; 604 nd.mnt = q;
621 nd.dentry = p->mnt_mountpoint; 605 nd.dentry = p->mnt_mountpoint;
622 q = clone_mnt(p, p->mnt_root); 606 q = clone_mnt(p, p->mnt_root, flag);
623 if (!q) 607 if (!q)
624 goto Enomem; 608 goto Enomem;
625 spin_lock(&vfsmount_lock); 609 spin_lock(&vfsmount_lock);
@@ -701,18 +685,13 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
701 685
702 err = -ENOMEM; 686 err = -ENOMEM;
703 if (recurse) 687 if (recurse)
704 mnt = copy_tree(old_nd.mnt, old_nd.dentry); 688 mnt = copy_tree(old_nd.mnt, old_nd.dentry, 0);
705 else 689 else
706 mnt = clone_mnt(old_nd.mnt, old_nd.dentry); 690 mnt = clone_mnt(old_nd.mnt, old_nd.dentry, 0);
707 691
708 if (!mnt) 692 if (!mnt)
709 goto out; 693 goto out;
710 694
711 /* stop bind mounts from expiring */
712 spin_lock(&vfsmount_lock);
713 list_del_init(&mnt->mnt_expire);
714 spin_unlock(&vfsmount_lock);
715
716 err = graft_tree(mnt, nd); 695 err = graft_tree(mnt, nd);
717 if (err) { 696 if (err) {
718 LIST_HEAD(umount_list); 697 LIST_HEAD(umount_list);
@@ -1155,7 +1134,8 @@ int copy_namespace(int flags, struct task_struct *tsk)
1155 1134
1156 down_write(&tsk->namespace->sem); 1135 down_write(&tsk->namespace->sem);
1157 /* First pass: copy the tree topology */ 1136 /* First pass: copy the tree topology */
1158 new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root); 1137 new_ns->root = copy_tree(namespace->root, namespace->root->mnt_root,
1138 CL_EXPIRE);
1159 if (!new_ns->root) { 1139 if (!new_ns->root) {
1160 up_write(&tsk->namespace->sem); 1140 up_write(&tsk->namespace->sem);
1161 kfree(new_ns); 1141 kfree(new_ns);