[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>
This commit is contained in:
Ram Pai
2005-11-07 17:20:17 -05:00
committed by Linus Torvalds
parent 2144440327
commit a05964f391
5 changed files with 128 additions and 20 deletions

View File

@ -86,31 +86,44 @@ void free_vfsmnt(struct vfsmount *mnt)
}
/*
* Now, lookup_mnt increments the ref count before returning
* the vfsmount struct.
* find the first or last mount at @dentry on vfsmount @mnt depending on
* @dir. If @dir is set return the first mount else return the last mount.
*/
struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
struct vfsmount *__lookup_mnt(struct vfsmount *mnt, struct dentry *dentry,
int dir)
{
struct list_head *head = mount_hashtable + hash(mnt, dentry);
struct list_head *tmp = head;
struct vfsmount *p, *found = NULL;
spin_lock(&vfsmount_lock);
for (;;) {
tmp = tmp->next;
tmp = dir ? tmp->next : tmp->prev;
p = NULL;
if (tmp == head)
break;
p = list_entry(tmp, struct vfsmount, mnt_hash);
if (p->mnt_parent == mnt && p->mnt_mountpoint == dentry) {
found = mntget(p);
found = p;
break;
}
}
spin_unlock(&vfsmount_lock);
return found;
}
/*
* lookup_mnt increments the ref count before returning
* the vfsmount struct.
*/
struct vfsmount *lookup_mnt(struct vfsmount *mnt, struct dentry *dentry)
{
struct vfsmount *child_mnt;
spin_lock(&vfsmount_lock);
if ((child_mnt = __lookup_mnt(mnt, dentry, 1)))
mntget(child_mnt);
spin_unlock(&vfsmount_lock);
return child_mnt;
}
static inline int check_mnt(struct vfsmount *mnt)
{
return mnt->mnt_namespace == current->namespace;
@ -404,9 +417,12 @@ EXPORT_SYMBOL(may_umount_tree);
*/
int may_umount(struct vfsmount *mnt)
{
if (atomic_read(&mnt->mnt_count) > 2)
return -EBUSY;
return 0;
int ret = 0;
spin_lock(&vfsmount_lock);
if (propagate_mount_busy(mnt, 2))
ret = -EBUSY;
spin_unlock(&vfsmount_lock);
return ret;
}
EXPORT_SYMBOL(may_umount);
@ -433,7 +449,7 @@ void release_mounts(struct list_head *head)
}
}
void umount_tree(struct vfsmount *mnt, struct list_head *kill)
void umount_tree(struct vfsmount *mnt, int propagate, struct list_head *kill)
{
struct vfsmount *p;
@ -442,6 +458,9 @@ void umount_tree(struct vfsmount *mnt, struct list_head *kill)
list_add(&p->mnt_hash, kill);
}
if (propagate)
propagate_umount(kill);
list_for_each_entry(p, kill, mnt_hash) {
list_del_init(&p->mnt_expire);
list_del_init(&p->mnt_list);
@ -450,6 +469,7 @@ void umount_tree(struct vfsmount *mnt, struct list_head *kill)
list_del_init(&p->mnt_child);
if (p->mnt_parent != p)
mnt->mnt_mountpoint->d_mounted--;
change_mnt_propagation(p, MS_PRIVATE);
}
}
@ -526,9 +546,9 @@ static int do_umount(struct vfsmount *mnt, int flags)
event++;
retval = -EBUSY;
if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) {
if (flags & MNT_DETACH || !propagate_mount_busy(mnt, 2)) {
if (!list_empty(&mnt->mnt_list))
umount_tree(mnt, &umount_list);
umount_tree(mnt, 1, &umount_list);
retval = 0;
}
spin_unlock(&vfsmount_lock);
@ -651,7 +671,7 @@ Enomem:
if (res) {
LIST_HEAD(umount_list);
spin_lock(&vfsmount_lock);
umount_tree(res, &umount_list);
umount_tree(res, 0, &umount_list);
spin_unlock(&vfsmount_lock);
release_mounts(&umount_list);
}
@ -827,7 +847,7 @@ static int do_loopback(struct nameidata *nd, char *old_name, int recurse)
if (err) {
LIST_HEAD(umount_list);
spin_lock(&vfsmount_lock);
umount_tree(mnt, &umount_list);
umount_tree(mnt, 0, &umount_list);
spin_unlock(&vfsmount_lock);
release_mounts(&umount_list);
}
@ -1023,12 +1043,12 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts,
* Check that it is still dead: the count should now be 2 - as
* contributed by the vfsmount parent and the mntget above
*/
if (atomic_read(&mnt->mnt_count) == 2) {
if (!propagate_mount_busy(mnt, 2)) {
/* delete from the namespace */
touch_namespace(mnt->mnt_namespace);
list_del_init(&mnt->mnt_list);
mnt->mnt_namespace = NULL;
umount_tree(mnt, umounts);
umount_tree(mnt, 1, umounts);
spin_unlock(&vfsmount_lock);
} else {
/*
@ -1647,7 +1667,7 @@ void __put_namespace(struct namespace *namespace)
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem);
spin_lock(&vfsmount_lock);
umount_tree(root, &umount_list);
umount_tree(root, 0, &umount_list);
spin_unlock(&vfsmount_lock);
up_write(&namespace_sem);
release_mounts(&umount_list);