2006-10-02 13:18:06 +04:00
/*
* Copyright ( C ) 2006 IBM Corporation
*
* Author : Serge Hallyn < serue @ us . ibm . com >
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation , version 2 of the
* License .
2006-10-02 13:18:19 +04:00
*
* Jun 2006 - namespaces support
* OpenVZ , SWsoft Inc .
* Pavel Emelianov < xemul @ openvz . org >
2006-10-02 13:18:06 +04:00
*/
# include <linux/module.h>
# include <linux/version.h>
# include <linux/nsproxy.h>
2006-10-02 13:18:07 +04:00
# include <linux/init_task.h>
2006-12-08 13:37:56 +03:00
# include <linux/mnt_namespace.h>
2006-10-02 13:18:14 +04:00
# include <linux/utsname.h>
2006-12-08 13:37:59 +03:00
# include <linux/pid_namespace.h>
2006-10-02 13:18:07 +04:00
struct nsproxy init_nsproxy = INIT_NSPROXY ( init_nsproxy ) ;
2006-10-02 13:18:06 +04:00
static inline void get_nsproxy ( struct nsproxy * ns )
{
atomic_inc ( & ns - > count ) ;
}
void get_task_namespaces ( struct task_struct * tsk )
{
struct nsproxy * ns = tsk - > nsproxy ;
if ( ns ) {
get_nsproxy ( ns ) ;
}
}
/*
* creates a copy of " orig " with refcount 1.
* This does not grab references to the contained namespaces ,
* so that needs to be done by dup_namespaces .
*/
static inline struct nsproxy * clone_namespaces ( struct nsproxy * orig )
{
struct nsproxy * ns ;
2006-10-20 10:29:12 +04:00
ns = kmemdup ( orig , sizeof ( struct nsproxy ) , GFP_KERNEL ) ;
2006-12-13 11:34:04 +03:00
if ( ns )
2006-10-02 13:18:06 +04:00
atomic_set ( & ns - > count , 1 ) ;
return ns ;
}
/*
* copies the nsproxy , setting refcount to 1 , and grabbing a
* reference to all contained namespaces . Called from
* sys_unshare ( )
*/
struct nsproxy * dup_namespaces ( struct nsproxy * orig )
{
struct nsproxy * ns = clone_namespaces ( orig ) ;
2006-10-02 13:18:08 +04:00
if ( ns ) {
2006-12-08 13:37:56 +03:00
if ( ns - > mnt_ns )
get_mnt_ns ( ns - > mnt_ns ) ;
2006-10-02 13:18:14 +04:00
if ( ns - > uts_ns )
get_uts_ns ( ns - > uts_ns ) ;
2006-10-02 13:18:19 +04:00
if ( ns - > ipc_ns )
get_ipc_ns ( ns - > ipc_ns ) ;
2006-12-08 13:37:59 +03:00
if ( ns - > pid_ns )
get_pid_ns ( ns - > pid_ns ) ;
2006-10-02 13:18:08 +04:00
}
2006-10-02 13:18:06 +04:00
return ns ;
}
/*
* called from clone . This now handles copy for nsproxy and all
* namespaces therein .
*/
int copy_namespaces ( int flags , struct task_struct * tsk )
{
struct nsproxy * old_ns = tsk - > nsproxy ;
2006-10-02 13:18:08 +04:00
struct nsproxy * new_ns ;
int err = 0 ;
2006-10-02 13:18:06 +04:00
if ( ! old_ns )
return 0 ;
get_nsproxy ( old_ns ) ;
2006-10-02 13:18:19 +04:00
if ( ! ( flags & ( CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC ) ) )
2006-10-02 13:18:08 +04:00
return 0 ;
new_ns = clone_namespaces ( old_ns ) ;
if ( ! new_ns ) {
err = - ENOMEM ;
goto out ;
}
tsk - > nsproxy = new_ns ;
2006-12-08 13:37:56 +03:00
err = copy_mnt_ns ( flags , tsk ) ;
2006-10-02 13:18:19 +04:00
if ( err )
goto out_ns ;
2006-10-02 13:18:08 +04:00
2006-10-02 13:18:14 +04:00
err = copy_utsname ( flags , tsk ) ;
2006-10-02 13:18:19 +04:00
if ( err )
goto out_uts ;
err = copy_ipcs ( flags , tsk ) ;
if ( err )
goto out_ipc ;
2006-10-02 13:18:14 +04:00
2006-12-08 13:37:59 +03:00
err = copy_pid_ns ( flags , tsk ) ;
if ( err )
goto out_pid ;
2006-10-02 13:18:08 +04:00
out :
2007-01-31 00:35:18 +03:00
put_nsproxy ( old_ns ) ;
2006-10-02 13:18:08 +04:00
return err ;
2006-10-02 13:18:19 +04:00
2006-12-08 13:37:59 +03:00
out_pid :
if ( new_ns - > ipc_ns )
put_ipc_ns ( new_ns - > ipc_ns ) ;
2006-10-02 13:18:19 +04:00
out_ipc :
if ( new_ns - > uts_ns )
put_uts_ns ( new_ns - > uts_ns ) ;
out_uts :
2006-12-08 13:37:56 +03:00
if ( new_ns - > mnt_ns )
put_mnt_ns ( new_ns - > mnt_ns ) ;
2006-10-02 13:18:19 +04:00
out_ns :
tsk - > nsproxy = old_ns ;
2006-10-02 13:18:24 +04:00
kfree ( new_ns ) ;
2006-10-02 13:18:19 +04:00
goto out ;
2006-10-02 13:18:06 +04:00
}
void free_nsproxy ( struct nsproxy * ns )
{
2006-12-08 13:37:59 +03:00
if ( ns - > mnt_ns )
put_mnt_ns ( ns - > mnt_ns ) ;
if ( ns - > uts_ns )
put_uts_ns ( ns - > uts_ns ) ;
if ( ns - > ipc_ns )
put_ipc_ns ( ns - > ipc_ns ) ;
if ( ns - > pid_ns )
put_pid_ns ( ns - > pid_ns ) ;
kfree ( ns ) ;
2006-10-02 13:18:06 +04:00
}