This moves the mount namespace into the nsproxy. The mount namespace count
now refers to the number of nsproxies point to it, rather than the number of
tasks. As a result, the unshare_namespace() function in kernel/fork.c no
longer checks whether it is being shared.
Signed-off-by: Serge Hallyn <serue@us.ibm.com>
Cc: Kirill Korotaev <dev@openvz.org>
Cc: "Eric W. Biederman" <ebiederm@xmission.com>
Cc: Herbert Poetzl <herbert@13thfloor.at>
Cc: Andrey Savochkin <saw@sw.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
static inline int check_mnt(struct vfsmount *mnt)
{
static inline int check_mnt(struct vfsmount *mnt)
{
- return mnt->mnt_namespace == current->namespace;
+ return mnt->mnt_namespace == current->nsproxy->namespace;
}
static void touch_namespace(struct namespace *ns)
}
static void touch_namespace(struct namespace *ns)
if (parent_nd) {
detach_mnt(source_mnt, parent_nd);
attach_mnt(source_mnt, nd);
if (parent_nd) {
detach_mnt(source_mnt, parent_nd);
attach_mnt(source_mnt, nd);
- touch_namespace(current->namespace);
+ touch_namespace(current->nsproxy->namespace);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
} else {
mnt_set_mountpoint(dest_mnt, dest_dentry, source_mnt);
commit_tree(source_mnt);
*/
struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
{
*/
struct namespace *dup_namespace(struct task_struct *tsk, struct fs_struct *fs)
{
- struct namespace *namespace = tsk->namespace;
+ struct namespace *namespace = tsk->nsproxy->namespace;
struct namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
struct namespace *new_ns;
struct vfsmount *rootmnt = NULL, *pwdmnt = NULL, *altrootmnt = NULL;
struct vfsmount *p, *q;
int copy_namespace(int flags, struct task_struct *tsk)
{
int copy_namespace(int flags, struct task_struct *tsk)
{
- struct namespace *namespace = tsk->namespace;
+ struct namespace *namespace = tsk->nsproxy->namespace;
struct namespace *new_ns;
int err = 0;
struct namespace *new_ns;
int err = 0;
- tsk->namespace = new_ns;
+ tsk->nsproxy->namespace = new_ns;
out:
put_namespace(namespace);
out:
put_namespace(namespace);
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 / */
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);
+ touch_namespace(current->nsproxy->namespace);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&user_nd, &new_nd);
security_sb_post_pivotroot(&user_nd, &new_nd);
spin_unlock(&vfsmount_lock);
chroot_fs_refs(&user_nd, &new_nd);
security_sb_post_pivotroot(&user_nd, &new_nd);
{
struct vfsmount *mnt;
struct namespace *namespace;
{
struct vfsmount *mnt;
struct namespace *namespace;
- struct task_struct *g, *p;
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
if (IS_ERR(mnt))
namespace->root = mnt;
mnt->mnt_namespace = namespace;
namespace->root = mnt;
mnt->mnt_namespace = namespace;
- init_task.namespace = namespace;
- read_lock(&tasklist_lock);
- do_each_thread(g, p) {
- get_namespace(namespace);
- p->namespace = namespace;
- } while_each_thread(g, p);
- read_unlock(&tasklist_lock);
+ init_task.nsproxy->namespace = namespace;
+ get_namespace(namespace);
set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
set_fs_pwd(current->fs, namespace->root, namespace->root->mnt_root);
set_fs_root(current->fs, namespace->root, namespace->root->mnt_root);
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
#include <linux/cpuset.h>
#include <linux/audit.h>
#include <linux/poll.h>
+#include <linux/nsproxy.h>
#include "internal.h"
/* NOTE:
#include "internal.h"
/* NOTE:
if (task) {
task_lock(task);
if (task) {
task_lock(task);
- namespace = task->namespace;
+ namespace = task->nsproxy->namespace;
if (namespace)
get_namespace(namespace);
task_unlock(task);
if (namespace)
get_namespace(namespace);
task_unlock(task);
if (task) {
task_lock(task);
if (task) {
task_lock(task);
- namespace = task->namespace;
+ namespace = task->nsproxy->namespace;
if (namespace)
get_namespace(namespace);
task_unlock(task);
if (namespace)
get_namespace(namespace);
task_unlock(task);
#define INIT_NSPROXY(nsproxy) { \
.count = ATOMIC_INIT(1), \
.nslock = SPIN_LOCK_UNLOCKED, \
#define INIT_NSPROXY(nsproxy) { \
.count = ATOMIC_INIT(1), \
.nslock = SPIN_LOCK_UNLOCKED, \
}
#define INIT_SIGHAND(sighand) { \
}
#define INIT_SIGHAND(sighand) { \
#include <linux/mount.h>
#include <linux/sched.h>
#include <linux/mount.h>
#include <linux/sched.h>
+#include <linux/nsproxy.h>
struct namespace {
atomic_t count;
struct namespace {
atomic_t count;
static inline void exit_namespace(struct task_struct *p)
{
static inline void exit_namespace(struct task_struct *p)
{
- struct namespace *namespace = p->namespace;
+ struct namespace *namespace = p->nsproxy->namespace;
- task_lock(p);
- p->namespace = NULL;
- task_unlock(p);
put_namespace(namespace);
}
}
put_namespace(namespace);
}
}
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
/*
* A structure to contain pointers to all per-process
* namespaces - fs (mount), uts, network, sysvipc, etc.
/*
* A structure to contain pointers to all per-process
* namespaces - fs (mount), uts, network, sysvipc, etc.
struct nsproxy {
atomic_t count;
spinlock_t nslock;
struct nsproxy {
atomic_t count;
spinlock_t nslock;
+ struct namespace *namespace;
};
extern struct nsproxy init_nsproxy;
};
extern struct nsproxy init_nsproxy;
extern signed long schedule_timeout_uninterruptible(signed long timeout);
asmlinkage void schedule(void);
extern signed long schedule_timeout_uninterruptible(signed long timeout);
asmlinkage void schedule(void);
struct nsproxy;
/* Maximum number of active map areas.. This is a random (large) number */
struct nsproxy;
/* Maximum number of active map areas.. This is a random (large) number */
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
struct fs_struct *fs;
/* open file information */
struct files_struct *files;
-/* namespace */
- struct namespace *namespace;
struct nsproxy *nsproxy;
/* signal handlers */
struct signal_struct *signal;
struct nsproxy *nsproxy;
/* signal handlers */
struct signal_struct *signal;
current->fs = fs;
atomic_inc(&fs->count);
current->fs = fs;
atomic_inc(&fs->count);
- exit_namespace(current);
exit_task_namespaces(current);
exit_task_namespaces(current);
- current->namespace = init_task.namespace;
current->nsproxy = init_task.nsproxy;
current->nsproxy = init_task.nsproxy;
- get_namespace(current->namespace);
get_task_namespaces(current);
exit_files(current);
get_task_namespaces(current);
exit_files(current);
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
exit_sem(tsk);
__exit_files(tsk);
__exit_fs(tsk);
exit_task_namespaces(tsk);
exit_thread();
cpuset_exit(tsk);
exit_task_namespaces(tsk);
exit_thread();
cpuset_exit(tsk);
goto bad_fork_cleanup_mm;
if ((retval = copy_namespaces(clone_flags, p)))
goto bad_fork_cleanup_keys;
goto bad_fork_cleanup_mm;
if ((retval = copy_namespaces(clone_flags, p)))
goto bad_fork_cleanup_keys;
- if ((retval = copy_namespace(clone_flags, p)))
- goto bad_fork_cleanup_namespaces;
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
retval = copy_thread(0, clone_flags, stack_start, stack_size, p, regs);
if (retval)
- goto bad_fork_cleanup_namespace;
+ goto bad_fork_cleanup_namespaces;
p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
/*
p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL;
/*
spin_unlock(¤t->sighand->siglock);
write_unlock_irq(&tasklist_lock);
retval = -ERESTARTNOINTR;
spin_unlock(¤t->sighand->siglock);
write_unlock_irq(&tasklist_lock);
retval = -ERESTARTNOINTR;
- goto bad_fork_cleanup_namespace;
+ goto bad_fork_cleanup_namespaces;
}
if (clone_flags & CLONE_THREAD) {
}
if (clone_flags & CLONE_THREAD) {
proc_fork_connector(p);
return p;
proc_fork_connector(p);
return p;
-bad_fork_cleanup_namespace:
- exit_namespace(p);
bad_fork_cleanup_namespaces:
exit_task_namespaces(p);
bad_fork_cleanup_keys:
bad_fork_cleanup_namespaces:
exit_task_namespaces(p);
bad_fork_cleanup_keys:
*/
static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
{
*/
static int unshare_namespace(unsigned long unshare_flags, struct namespace **new_nsp, struct fs_struct *new_fs)
{
- struct namespace *ns = current->namespace;
+ struct namespace *ns = current->nsproxy->namespace;
- if ((unshare_flags & CLONE_NEWNS) &&
- (ns && atomic_read(&ns->count) > 1)) {
+ if ((unshare_flags & CLONE_NEWNS) && ns) {
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
if (!capable(CAP_SYS_ADMIN))
return -EPERM;
- ns = current->namespace;
- current->namespace = new_ns;
+ ns = current->nsproxy->namespace;
+ current->nsproxy->namespace = new_ns;
#include <linux/version.h>
#include <linux/nsproxy.h>
#include <linux/init_task.h>
#include <linux/version.h>
#include <linux/nsproxy.h>
#include <linux/init_task.h>
+#include <linux/namespace.h>
struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
struct nsproxy init_nsproxy = INIT_NSPROXY(init_nsproxy);
{
struct nsproxy *ns = clone_namespaces(orig);
{
struct nsproxy *ns = clone_namespaces(orig);
+ if (ns) {
+ if (ns->namespace)
+ get_namespace(ns->namespace);
+ }
+
int copy_namespaces(int flags, struct task_struct *tsk)
{
struct nsproxy *old_ns = tsk->nsproxy;
int copy_namespaces(int flags, struct task_struct *tsk)
{
struct nsproxy *old_ns = tsk->nsproxy;
+ struct nsproxy *new_ns;
+ int err = 0;
if (!old_ns)
return 0;
get_nsproxy(old_ns);
if (!old_ns)
return 0;
get_nsproxy(old_ns);
+ if (!(flags & CLONE_NEWNS))
+ return 0;
+
+ new_ns = clone_namespaces(old_ns);
+ if (!new_ns) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ tsk->nsproxy = new_ns;
+
+ err = copy_namespace(flags, tsk);
+ if (err) {
+ tsk->nsproxy = old_ns;
+ put_nsproxy(new_ns);
+ goto out;
+ }
+
+out:
+ put_nsproxy(old_ns);
+ return err;
}
void free_nsproxy(struct nsproxy *ns)
{
}
void free_nsproxy(struct nsproxy *ns)
{
+ if (ns->namespace)
+ put_namespace(ns->namespace);