Loading fs/namespace.c +29 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ static inline int sysfs_init(void) /* spinlock for vfsmount related operations, inplace of dcache_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; static kmem_cache_t *mnt_cache; Loading Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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: Loading Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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; Loading fs/proc/base.c +47 −15 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include <linux/seccomp.h> #include <linux/cpuset.h> #include <linux/audit.h> #include <linux/poll.h> #include "internal.h" /* Loading Loading @@ -660,26 +661,38 @@ static struct file_operations proc_smaps_operations = { #endif extern struct seq_operations mounts_op; struct proc_mounts { struct seq_file m; int event; }; static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = proc_task(inode); int ret = seq_open(file, &mounts_op); if (!ret) { struct seq_file *m = file->private_data; struct namespace *namespace; struct proc_mounts *p; int ret = -EINVAL; task_lock(task); namespace = task->namespace; if (namespace) get_namespace(namespace); task_unlock(task); if (namespace) m->private = namespace; else { seq_release(inode, file); ret = -EINVAL; if (namespace) { ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (p) { file->private_data = &p->m; ret = seq_open(file, &mounts_op); if (!ret) { p->m.private = namespace; p->event = namespace->event; return 0; } kfree(p); } put_namespace(namespace); } return ret; } Loading @@ -692,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file) return seq_release(inode, file); } static unsigned mounts_poll(struct file *file, poll_table *wait) { struct proc_mounts *p = file->private_data; struct namespace *ns = p->m.private; unsigned res = 0; poll_wait(file, &ns->poll, wait); spin_lock(&vfsmount_lock); if (p->event != ns->event) { p->event = ns->event; res = POLLERR; } spin_unlock(&vfsmount_lock); return res; } static struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, .release = mounts_release, .poll = mounts_poll, }; #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ Loading include/linux/namespace.h +2 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ struct namespace { struct vfsmount * root; struct list_head list; struct rw_semaphore sem; wait_queue_head_t poll; int event; }; extern int copy_namespace(int, struct task_struct *); Loading Loading
fs/namespace.c +29 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,8 @@ static inline int sysfs_init(void) /* spinlock for vfsmount related operations, inplace of dcache_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; static kmem_cache_t *mnt_cache; Loading Loading @@ -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; Loading Loading @@ -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; } Loading Loading @@ -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) { Loading Loading @@ -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: Loading Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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 */ Loading Loading @@ -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); Loading Loading @@ -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; Loading
fs/proc/base.c +47 −15 Original line number Diff line number Diff line Loading @@ -70,6 +70,7 @@ #include <linux/seccomp.h> #include <linux/cpuset.h> #include <linux/audit.h> #include <linux/poll.h> #include "internal.h" /* Loading Loading @@ -660,26 +661,38 @@ static struct file_operations proc_smaps_operations = { #endif extern struct seq_operations mounts_op; struct proc_mounts { struct seq_file m; int event; }; static int mounts_open(struct inode *inode, struct file *file) { struct task_struct *task = proc_task(inode); int ret = seq_open(file, &mounts_op); if (!ret) { struct seq_file *m = file->private_data; struct namespace *namespace; struct proc_mounts *p; int ret = -EINVAL; task_lock(task); namespace = task->namespace; if (namespace) get_namespace(namespace); task_unlock(task); if (namespace) m->private = namespace; else { seq_release(inode, file); ret = -EINVAL; if (namespace) { ret = -ENOMEM; p = kmalloc(sizeof(struct proc_mounts), GFP_KERNEL); if (p) { file->private_data = &p->m; ret = seq_open(file, &mounts_op); if (!ret) { p->m.private = namespace; p->event = namespace->event; return 0; } kfree(p); } put_namespace(namespace); } return ret; } Loading @@ -692,11 +705,30 @@ static int mounts_release(struct inode *inode, struct file *file) return seq_release(inode, file); } static unsigned mounts_poll(struct file *file, poll_table *wait) { struct proc_mounts *p = file->private_data; struct namespace *ns = p->m.private; unsigned res = 0; poll_wait(file, &ns->poll, wait); spin_lock(&vfsmount_lock); if (p->event != ns->event) { p->event = ns->event; res = POLLERR; } spin_unlock(&vfsmount_lock); return res; } static struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, .release = mounts_release, .poll = mounts_poll, }; #define PROC_BLOCK_SIZE (3*1024) /* 4K page size but our output routines use some slack for overruns */ Loading
include/linux/namespace.h +2 −0 Original line number Diff line number Diff line Loading @@ -10,6 +10,8 @@ struct namespace { struct vfsmount * root; struct list_head list; struct rw_semaphore sem; wait_queue_head_t poll; int event; }; extern int copy_namespace(int, struct task_struct *); Loading