diff options
Diffstat (limited to 'fs/namespace.c')
-rw-r--r-- | fs/namespace.c | 30 |
1 files changed, 29 insertions, 1 deletions
diff --git a/fs/namespace.c b/fs/namespace.c index 611f777bbd61..d1aca685aacf 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -37,7 +37,9 @@ static inline int sysfs_init(void) #endif /* spinlock for vfsmount related operations, inplace of dcache_lock */ - __cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); +__cacheline_aligned_in_smp DEFINE_SPINLOCK(vfsmount_lock); + +static int event; static struct list_head *mount_hashtable; static int hash_mask __read_mostly, hash_bits __read_mostly; @@ -111,6 +113,22 @@ static inline int check_mnt(struct vfsmount *mnt) return mnt->mnt_namespace == current->namespace; } +static void touch_namespace(struct namespace *ns) +{ + if (ns) { + ns->event = ++event; + wake_up_interruptible(&ns->poll); + } +} + +static void __touch_namespace(struct namespace *ns) +{ + if (ns && ns->event != event) { + ns->event = event; + wake_up_interruptible(&ns->poll); + } +} + static void detach_mnt(struct vfsmount *mnt, struct nameidata *old_nd) { old_nd->dentry = mnt->mnt_mountpoint; @@ -384,6 +402,7 @@ static void umount_tree(struct vfsmount *mnt) for (p = mnt; p; p = next_mnt(p, mnt)) { list_del(&p->mnt_list); list_add(&p->mnt_list, &kill); + __touch_namespace(p->mnt_namespace); p->mnt_namespace = NULL; } @@ -473,6 +492,7 @@ static int do_umount(struct vfsmount *mnt, int flags) down_write(¤t->namespace->sem); spin_lock(&vfsmount_lock); + event++; retval = -EBUSY; if (atomic_read(&mnt->mnt_count) == 2 || flags & MNT_DETACH) { @@ -634,6 +654,7 @@ static int graft_tree(struct vfsmount *mnt, struct nameidata *nd) list_splice(&head, current->namespace->list.prev); mntget(mnt); err = 0; + touch_namespace(current->namespace); } spin_unlock(&vfsmount_lock); out_unlock: @@ -771,6 +792,7 @@ static int do_move_mount(struct nameidata *nd, char *old_name) detach_mnt(old_nd.mnt, &parent_nd); attach_mnt(old_nd.mnt, nd); + touch_namespace(current->namespace); /* if the mount is moved, it should no longer be expire * automatically */ @@ -877,6 +899,7 @@ static void expire_mount(struct vfsmount *mnt, struct list_head *mounts) struct nameidata old_nd; /* delete from the namespace */ + touch_namespace(mnt->mnt_namespace); list_del_init(&mnt->mnt_list); mnt->mnt_namespace = NULL; detach_mnt(mnt, &old_nd); @@ -1114,6 +1137,8 @@ int copy_namespace(int flags, struct task_struct *tsk) atomic_set(&new_ns->count, 1); init_rwsem(&new_ns->sem); INIT_LIST_HEAD(&new_ns->list); + init_waitqueue_head(&new_ns->poll); + new_ns->event = 0; down_write(&tsk->namespace->sem); /* First pass: copy the tree topology */ @@ -1377,6 +1402,7 @@ asmlinkage long sys_pivot_root(const char __user *new_root, const char __user *p detach_mnt(user_nd.mnt, &root_parent); attach_mnt(user_nd.mnt, &old_nd); /* mount old root on put_old */ attach_mnt(new_nd.mnt, &root_parent); /* mount new_root on / */ + touch_namespace(current->namespace); spin_unlock(&vfsmount_lock); chroot_fs_refs(&user_nd, &new_nd); security_sb_post_pivotroot(&user_nd, &new_nd); @@ -1413,6 +1439,8 @@ static void __init init_mount_tree(void) atomic_set(&namespace->count, 1); INIT_LIST_HEAD(&namespace->list); init_rwsem(&namespace->sem); + init_waitqueue_head(&namespace->poll); + namespace->event = 0; list_add(&mnt->mnt_list, &namespace->list); namespace->root = mnt; mnt->mnt_namespace = namespace; |