From 435d5f4bb2ccba3b791d9ef61d2590e30b8e806e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 31 Oct 2014 22:56:04 -0400 Subject: [PATCH 01/10] common object embedded into various struct ....ns for now - just move corresponding ->proc_inum instances over there Acked-by: "Eric W. Biederman" Signed-off-by: Al Viro --- fs/mount.h | 3 ++- fs/namespace.c | 6 +++--- include/linux/ipc_namespace.h | 3 ++- include/linux/ns_common.h | 8 ++++++++ include/linux/pid_namespace.h | 3 ++- include/linux/user_namespace.h | 3 ++- include/linux/utsname.h | 3 ++- include/net/net_namespace.h | 3 ++- init/version.c | 2 +- ipc/msgutil.c | 2 +- ipc/namespace.c | 8 ++++---- kernel/pid.c | 2 +- kernel/pid_namespace.c | 6 +++--- kernel/user.c | 2 +- kernel/user_namespace.c | 6 +++--- kernel/utsname.c | 6 +++--- net/core/net_namespace.c | 6 +++--- 17 files changed, 43 insertions(+), 29 deletions(-) create mode 100644 include/linux/ns_common.h diff --git a/fs/mount.h b/fs/mount.h index f82c62840905..0ad6f760ce52 100644 --- a/fs/mount.h +++ b/fs/mount.h @@ -1,10 +1,11 @@ #include #include #include +#include struct mnt_namespace { atomic_t count; - unsigned int proc_inum; + struct ns_common ns; struct mount * root; struct list_head list; struct user_namespace *user_ns; diff --git a/fs/namespace.c b/fs/namespace.c index 5b66b2b3624d..adc2ea2532a0 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2640,7 +2640,7 @@ dput_out: static void free_mnt_ns(struct mnt_namespace *ns) { - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); put_user_ns(ns->user_ns); kfree(ns); } @@ -2662,7 +2662,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); if (!new_ns) return ERR_PTR(-ENOMEM); - ret = proc_alloc_inum(&new_ns->proc_inum); + ret = proc_alloc_inum(&new_ns->ns.inum); if (ret) { kfree(new_ns); return ERR_PTR(ret); @@ -3201,7 +3201,7 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) static unsigned int mntns_inum(void *ns) { struct mnt_namespace *mnt_ns = ns; - return mnt_ns->proc_inum; + return mnt_ns->ns.inum; } const struct proc_ns_operations mntns_operations = { diff --git a/include/linux/ipc_namespace.h b/include/linux/ipc_namespace.h index 35e7eca4e33b..52a640128151 100644 --- a/include/linux/ipc_namespace.h +++ b/include/linux/ipc_namespace.h @@ -6,6 +6,7 @@ #include #include #include +#include /* * ipc namespace events @@ -68,7 +69,7 @@ struct ipc_namespace { /* user_ns which owns the ipc ns */ struct user_namespace *user_ns; - unsigned int proc_inum; + struct ns_common ns; }; extern struct ipc_namespace init_ipc_ns; diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h new file mode 100644 index 000000000000..e7db1cd54047 --- /dev/null +++ b/include/linux/ns_common.h @@ -0,0 +1,8 @@ +#ifndef _LINUX_NS_COMMON_H +#define _LINUX_NS_COMMON_H + +struct ns_common { + unsigned int inum; +}; + +#endif diff --git a/include/linux/pid_namespace.h b/include/linux/pid_namespace.h index 1997ffc295a7..b9cf6c51b181 100644 --- a/include/linux/pid_namespace.h +++ b/include/linux/pid_namespace.h @@ -8,6 +8,7 @@ #include #include #include +#include struct pidmap { atomic_t nr_free; @@ -43,7 +44,7 @@ struct pid_namespace { kgid_t pid_gid; int hide_pid; int reboot; /* group exit code if this pidns was rebooted */ - unsigned int proc_inum; + struct ns_common ns; }; extern struct pid_namespace init_pid_ns; diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index e95372654f09..4cf06c140e21 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -26,7 +27,7 @@ struct user_namespace { int level; kuid_t owner; kgid_t group; - unsigned int proc_inum; + struct ns_common ns; /* Register of per-UID persistent keyrings for this namespace */ #ifdef CONFIG_PERSISTENT_KEYRINGS diff --git a/include/linux/utsname.h b/include/linux/utsname.h index 239e27733d6c..5093f58ae192 100644 --- a/include/linux/utsname.h +++ b/include/linux/utsname.h @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -23,7 +24,7 @@ struct uts_namespace { struct kref kref; struct new_utsname name; struct user_namespace *user_ns; - unsigned int proc_inum; + struct ns_common ns; }; extern struct uts_namespace init_uts_ns; diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index e0d64667a4b3..2e8756b8c775 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -26,6 +26,7 @@ #endif #include #include +#include struct user_namespace; struct proc_dir_entry; @@ -60,7 +61,7 @@ struct net { struct user_namespace *user_ns; /* Owning user namespace */ - unsigned int proc_inum; + struct ns_common ns; struct proc_dir_entry *proc_net; struct proc_dir_entry *proc_net_stat; diff --git a/init/version.c b/init/version.c index 1a4718e500fe..e23dbdabb26b 100644 --- a/init/version.c +++ b/init/version.c @@ -35,7 +35,7 @@ struct uts_namespace init_uts_ns = { .domainname = UTS_DOMAINNAME, }, .user_ns = &init_user_ns, - .proc_inum = PROC_UTS_INIT_INO, + .ns.inum = PROC_UTS_INIT_INO, }; EXPORT_SYMBOL_GPL(init_uts_ns); diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 7e7095974d54..5930471a2902 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -31,7 +31,7 @@ DEFINE_SPINLOCK(mq_lock); struct ipc_namespace init_ipc_ns = { .count = ATOMIC_INIT(1), .user_ns = &init_user_ns, - .proc_inum = PROC_IPC_INIT_INO, + .ns.inum = PROC_IPC_INIT_INO, }; atomic_t nr_ipc_ns = ATOMIC_INIT(1); diff --git a/ipc/namespace.c b/ipc/namespace.c index b54468e48e32..177fa9db391d 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -26,7 +26,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, if (ns == NULL) return ERR_PTR(-ENOMEM); - err = proc_alloc_inum(&ns->proc_inum); + err = proc_alloc_inum(&ns->ns.inum); if (err) { kfree(ns); return ERR_PTR(err); @@ -35,7 +35,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, atomic_set(&ns->count, 1); err = mq_init_ns(ns); if (err) { - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); kfree(ns); return ERR_PTR(err); } @@ -119,7 +119,7 @@ static void free_ipc_ns(struct ipc_namespace *ns) */ ipcns_notify(IPCNS_REMOVED); put_user_ns(ns->user_ns); - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); kfree(ns); } @@ -186,7 +186,7 @@ static unsigned int ipcns_inum(void *vp) { struct ipc_namespace *ns = vp; - return ns->proc_inum; + return ns->ns.inum; } const struct proc_ns_operations ipcns_operations = { diff --git a/kernel/pid.c b/kernel/pid.c index 9b9a26698144..3650698cf1dc 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -79,7 +79,7 @@ struct pid_namespace init_pid_ns = { .level = 0, .child_reaper = &init_task, .user_ns = &init_user_ns, - .proc_inum = PROC_PID_INIT_INO, + .ns.inum = PROC_PID_INIT_INO, }; EXPORT_SYMBOL_GPL(init_pid_ns); diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index db95d8eb761b..99e27e5bf906 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -105,7 +105,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns if (ns->pid_cachep == NULL) goto out_free_map; - err = proc_alloc_inum(&ns->proc_inum); + err = proc_alloc_inum(&ns->ns.inum); if (err) goto out_free_map; @@ -142,7 +142,7 @@ static void destroy_pid_namespace(struct pid_namespace *ns) { int i; - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); for (i = 0; i < PIDMAP_ENTRIES; i++) kfree(ns->pidmap[i].page); put_user_ns(ns->user_ns); @@ -365,7 +365,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) static unsigned int pidns_inum(void *ns) { struct pid_namespace *pid_ns = ns; - return pid_ns->proc_inum; + return pid_ns->ns.inum; } const struct proc_ns_operations pidns_operations = { diff --git a/kernel/user.c b/kernel/user.c index 4efa39350e44..a7ca84bad8e6 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -50,7 +50,7 @@ struct user_namespace init_user_ns = { .count = ATOMIC_INIT(3), .owner = GLOBAL_ROOT_UID, .group = GLOBAL_ROOT_GID, - .proc_inum = PROC_USER_INIT_INO, + .ns.inum = PROC_USER_INIT_INO, #ifdef CONFIG_PERSISTENT_KEYRINGS .persistent_keyring_register_sem = __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index aa312b0dc3ec..fde584082673 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -86,7 +86,7 @@ int create_user_ns(struct cred *new) if (!ns) return -ENOMEM; - ret = proc_alloc_inum(&ns->proc_inum); + ret = proc_alloc_inum(&ns->ns.inum); if (ret) { kmem_cache_free(user_ns_cachep, ns); return ret; @@ -136,7 +136,7 @@ void free_user_ns(struct user_namespace *ns) #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); #endif - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); kmem_cache_free(user_ns_cachep, ns); ns = parent; } while (atomic_dec_and_test(&parent->count)); @@ -891,7 +891,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns) static unsigned int userns_inum(void *ns) { struct user_namespace *user_ns = ns; - return user_ns->proc_inum; + return user_ns->ns.inum; } const struct proc_ns_operations userns_operations = { diff --git a/kernel/utsname.c b/kernel/utsname.c index 883aaaa7de8a..b1cd00b828f2 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -42,7 +42,7 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, if (!ns) return ERR_PTR(-ENOMEM); - err = proc_alloc_inum(&ns->proc_inum); + err = proc_alloc_inum(&ns->ns.inum); if (err) { kfree(ns); return ERR_PTR(err); @@ -84,7 +84,7 @@ void free_uts_ns(struct kref *kref) ns = container_of(kref, struct uts_namespace, kref); put_user_ns(ns->user_ns); - proc_free_inum(ns->proc_inum); + proc_free_inum(ns->ns.inum); kfree(ns); } @@ -127,7 +127,7 @@ static unsigned int utsns_inum(void *vp) { struct uts_namespace *ns = vp; - return ns->proc_inum; + return ns->ns.inum; } const struct proc_ns_operations utsns_operations = { diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 7f155175bba8..f2f756ce99d7 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -386,12 +386,12 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_pid); static __net_init int net_ns_net_init(struct net *net) { - return proc_alloc_inum(&net->proc_inum); + return proc_alloc_inum(&net->ns.inum); } static __net_exit void net_ns_net_exit(struct net *net) { - proc_free_inum(net->proc_inum); + proc_free_inum(net->ns.inum); } static struct pernet_operations __net_initdata net_ns_ops = { @@ -664,7 +664,7 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) static unsigned int netns_inum(void *ns) { struct net *net = ns; - return net->proc_inum; + return net->ns.inum; } const struct proc_ns_operations netns_operations = { From 58be28256d98a6b996b20f49130ea11afb8de75a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:00:23 -0400 Subject: [PATCH 02/10] make mntns ->get()/->put()/->install()/->inum() work with &mnt_ns->ns Acked-by: "Eric W. Biederman" Signed-off-by: Al Viro --- fs/namespace.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index adc2ea2532a0..5c21fdadabe4 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1582,6 +1582,11 @@ static bool is_mnt_ns_file(struct dentry *dentry) return true; } +struct mnt_namespace *to_mnt_ns(struct ns_common *ns) +{ + return container_of(ns, struct mnt_namespace, ns); +} + static bool mnt_ns_loop(struct dentry *dentry) { /* Could bind mounting the mount namespace inode cause a @@ -1591,7 +1596,7 @@ static bool mnt_ns_loop(struct dentry *dentry) if (!is_mnt_ns_file(dentry)) return false; - mnt_ns = get_proc_ns(dentry->d_inode)->ns; + mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)->ns); return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; } @@ -3146,14 +3151,14 @@ found: static void *mntns_get(struct task_struct *task) { - struct mnt_namespace *ns = NULL; + struct ns_common *ns = NULL; struct nsproxy *nsproxy; task_lock(task); nsproxy = task->nsproxy; if (nsproxy) { - ns = nsproxy->mnt_ns; - get_mnt_ns(ns); + ns = &nsproxy->mnt_ns->ns; + get_mnt_ns(to_mnt_ns(ns)); } task_unlock(task); @@ -3162,13 +3167,13 @@ static void *mntns_get(struct task_struct *task) static void mntns_put(void *ns) { - put_mnt_ns(ns); + put_mnt_ns(to_mnt_ns(ns)); } static int mntns_install(struct nsproxy *nsproxy, void *ns) { struct fs_struct *fs = current->fs; - struct mnt_namespace *mnt_ns = ns; + struct mnt_namespace *mnt_ns = to_mnt_ns(ns); struct path root; if (!ns_capable(mnt_ns->user_ns, CAP_SYS_ADMIN) || @@ -3200,8 +3205,8 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) static unsigned int mntns_inum(void *ns) { - struct mnt_namespace *mnt_ns = ns; - return mnt_ns->ns.inum; + struct ns_common *p = ns; + return p->inum; } const struct proc_ns_operations mntns_operations = { From ff24870f46d51d79fc74a241fd7c12ccb933c69f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:10:50 -0400 Subject: [PATCH 03/10] netns: switch ->get()/->put()/->install()/->inum() to working with &net->ns Signed-off-by: Al Viro --- net/core/net_namespace.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index f2f756ce99d7..97f4dc2132ad 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -347,7 +347,7 @@ struct net *get_net_ns_by_fd(int fd) ei = get_proc_ns(file_inode(file)); if (ei->ns_ops == &netns_operations) - net = get_net(ei->ns); + net = get_net(container_of(ei->ns, struct net, ns)); else net = ERR_PTR(-EINVAL); @@ -640,17 +640,22 @@ static void *netns_get(struct task_struct *task) net = get_net(nsproxy->net_ns); task_unlock(task); - return net; + return net ? &net->ns : NULL; +} + +static inline struct net *to_net_ns(struct ns_common *ns) +{ + return container_of(ns, struct net, ns); } static void netns_put(void *ns) { - put_net(ns); + put_net(to_net_ns(ns)); } static int netns_install(struct nsproxy *nsproxy, void *ns) { - struct net *net = ns; + struct net *net = to_net_ns(ns); if (!ns_capable(net->user_ns, CAP_SYS_ADMIN) || !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) @@ -663,8 +668,7 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) static unsigned int netns_inum(void *ns) { - struct net *net = ns; - return net->ns.inum; + return ((struct ns_common *)ns)->inum; } const struct proc_ns_operations netns_operations = { From 3c0411846118a578de3a979faf2da3ab5fb81179 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:25:30 -0400 Subject: [PATCH 04/10] switch the rest of proc_ns_operations to working with &...->ns Signed-off-by: Al Viro --- ipc/namespace.c | 15 +++++++++------ kernel/pid_namespace.c | 14 +++++++++----- kernel/user_namespace.c | 14 +++++++++----- kernel/utsname.c | 15 +++++++++------ 4 files changed, 36 insertions(+), 22 deletions(-) diff --git a/ipc/namespace.c b/ipc/namespace.c index 177fa9db391d..3c1e8d3bd7d3 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -149,6 +149,11 @@ void put_ipc_ns(struct ipc_namespace *ns) } } +static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns) +{ + return container_of(ns, struct ipc_namespace, ns); +} + static void *ipcns_get(struct task_struct *task) { struct ipc_namespace *ns = NULL; @@ -160,17 +165,17 @@ static void *ipcns_get(struct task_struct *task) ns = get_ipc_ns(nsproxy->ipc_ns); task_unlock(task); - return ns; + return ns ? &ns->ns : NULL; } static void ipcns_put(void *ns) { - return put_ipc_ns(ns); + return put_ipc_ns(to_ipc_ns(ns)); } static int ipcns_install(struct nsproxy *nsproxy, void *new) { - struct ipc_namespace *ns = new; + struct ipc_namespace *ns = to_ipc_ns(new); if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) return -EPERM; @@ -184,9 +189,7 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new) static unsigned int ipcns_inum(void *vp) { - struct ipc_namespace *ns = vp; - - return ns->ns.inum; + return ((struct ns_common *)vp)->inum; } const struct proc_ns_operations ipcns_operations = { diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 99e27e5bf906..dd961ad86fbd 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -313,6 +313,11 @@ int reboot_pid_ns(struct pid_namespace *pid_ns, int cmd) return 0; } +static inline struct pid_namespace *to_pid_ns(struct ns_common *ns) +{ + return container_of(ns, struct pid_namespace, ns); +} + static void *pidns_get(struct task_struct *task) { struct pid_namespace *ns; @@ -323,18 +328,18 @@ static void *pidns_get(struct task_struct *task) get_pid_ns(ns); rcu_read_unlock(); - return ns; + return ns ? &ns->ns : NULL; } static void pidns_put(void *ns) { - put_pid_ns(ns); + put_pid_ns(to_pid_ns(ns)); } static int pidns_install(struct nsproxy *nsproxy, void *ns) { struct pid_namespace *active = task_active_pid_ns(current); - struct pid_namespace *ancestor, *new = ns; + struct pid_namespace *ancestor, *new = to_pid_ns(ns); if (!ns_capable(new->user_ns, CAP_SYS_ADMIN) || !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) @@ -364,8 +369,7 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) static unsigned int pidns_inum(void *ns) { - struct pid_namespace *pid_ns = ns; - return pid_ns->ns.inum; + return ((struct ns_common *)ns)->inum; } const struct proc_ns_operations pidns_operations = { diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index fde584082673..1ab2209228ff 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -841,6 +841,11 @@ static bool new_idmap_permitted(const struct file *file, return false; } +static inline struct user_namespace *to_user_ns(struct ns_common *ns) +{ + return container_of(ns, struct user_namespace, ns); +} + static void *userns_get(struct task_struct *task) { struct user_namespace *user_ns; @@ -849,17 +854,17 @@ static void *userns_get(struct task_struct *task) user_ns = get_user_ns(__task_cred(task)->user_ns); rcu_read_unlock(); - return user_ns; + return user_ns ? &user_ns->ns : NULL; } static void userns_put(void *ns) { - put_user_ns(ns); + put_user_ns(to_user_ns(ns)); } static int userns_install(struct nsproxy *nsproxy, void *ns) { - struct user_namespace *user_ns = ns; + struct user_namespace *user_ns = to_user_ns(ns); struct cred *cred; /* Don't allow gaining capabilities by reentering @@ -890,8 +895,7 @@ static int userns_install(struct nsproxy *nsproxy, void *ns) static unsigned int userns_inum(void *ns) { - struct user_namespace *user_ns = ns; - return user_ns->ns.inum; + return ((struct ns_common *)ns)->inum; } const struct proc_ns_operations userns_operations = { diff --git a/kernel/utsname.c b/kernel/utsname.c index b1cd00b828f2..1917f74be8ec 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -88,6 +88,11 @@ void free_uts_ns(struct kref *kref) kfree(ns); } +static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) +{ + return container_of(ns, struct uts_namespace, ns); +} + static void *utsns_get(struct task_struct *task) { struct uts_namespace *ns = NULL; @@ -101,17 +106,17 @@ static void *utsns_get(struct task_struct *task) } task_unlock(task); - return ns; + return ns ? &ns->ns : NULL; } static void utsns_put(void *ns) { - put_uts_ns(ns); + put_uts_ns(to_uts_ns(ns)); } static int utsns_install(struct nsproxy *nsproxy, void *new) { - struct uts_namespace *ns = new; + struct uts_namespace *ns = to_uts_ns(new); if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || !ns_capable(current_user_ns(), CAP_SYS_ADMIN)) @@ -125,9 +130,7 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) static unsigned int utsns_inum(void *vp) { - struct uts_namespace *ns = vp; - - return ns->ns.inum; + return ((struct ns_common *)vp)->inum; } const struct proc_ns_operations utsns_operations = { From 64964528b24ea390824f0e5ce9d34b8d39b28cde Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:37:32 -0400 Subject: [PATCH 05/10] make proc_ns_operations work with struct ns_common * instead of void * We can do that now. And kill ->inum(), while we are at it - all instances are identical. Signed-off-by: Al Viro --- fs/namespace.c | 13 +++---------- fs/proc/inode.c | 2 +- fs/proc/namespaces.c | 8 ++++---- include/linux/proc_ns.h | 10 +++++----- ipc/namespace.c | 12 +++--------- kernel/pid_namespace.c | 12 +++--------- kernel/user_namespace.c | 12 +++--------- kernel/utsname.c | 12 +++--------- net/core/net_namespace.c | 12 +++--------- 9 files changed, 28 insertions(+), 65 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 5c21fdadabe4..b9c16c3f63f5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -3149,7 +3149,7 @@ found: return visible; } -static void *mntns_get(struct task_struct *task) +static struct ns_common *mntns_get(struct task_struct *task) { struct ns_common *ns = NULL; struct nsproxy *nsproxy; @@ -3165,12 +3165,12 @@ static void *mntns_get(struct task_struct *task) return ns; } -static void mntns_put(void *ns) +static void mntns_put(struct ns_common *ns) { put_mnt_ns(to_mnt_ns(ns)); } -static int mntns_install(struct nsproxy *nsproxy, void *ns) +static int mntns_install(struct nsproxy *nsproxy, struct ns_common *ns) { struct fs_struct *fs = current->fs; struct mnt_namespace *mnt_ns = to_mnt_ns(ns); @@ -3203,17 +3203,10 @@ static int mntns_install(struct nsproxy *nsproxy, void *ns) return 0; } -static unsigned int mntns_inum(void *ns) -{ - struct ns_common *p = ns; - return p->inum; -} - const struct proc_ns_operations mntns_operations = { .name = "mnt", .type = CLONE_NEWNS, .get = mntns_get, .put = mntns_put, .install = mntns_install, - .inum = mntns_inum, }; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 333080d7a671..43b703c6cd3b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -33,7 +33,7 @@ static void proc_evict_inode(struct inode *inode) struct proc_dir_entry *de; struct ctl_table_header *head; const struct proc_ns_operations *ns_ops; - void *ns; + struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); clear_inode(inode); diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 89026095f2b5..995e8e98237d 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -64,7 +64,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, struct inode *inode; struct proc_inode *ei; struct qstr qname = { .name = "", }; - void *ns; + struct ns_common *ns; ns = ns_ops->get(task); if (!ns) @@ -76,7 +76,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, return ERR_PTR(-ENOMEM); } - inode = iget_locked(sb, ns_ops->inum(ns)); + inode = iget_locked(sb, ns->inum); if (!inode) { dput(dentry); ns_ops->put(ns); @@ -144,7 +144,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl struct proc_inode *ei = PROC_I(inode); const struct proc_ns_operations *ns_ops = ei->ns.ns_ops; struct task_struct *task; - void *ns; + struct ns_common *ns; char name[50]; int res = -EACCES; @@ -160,7 +160,7 @@ static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int bufl if (!ns) goto out_put_task; - snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns_ops->inum(ns)); + snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns->inum); res = readlink_copy(buffer, buflen, name); ns_ops->put(ns); out_put_task: diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index 34a1e105bef4..f284959391fd 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -6,18 +6,18 @@ struct pid_namespace; struct nsproxy; +struct ns_common; struct proc_ns_operations { const char *name; int type; - void *(*get)(struct task_struct *task); - void (*put)(void *ns); - int (*install)(struct nsproxy *nsproxy, void *ns); - unsigned int (*inum)(void *ns); + struct ns_common *(*get)(struct task_struct *task); + void (*put)(struct ns_common *ns); + int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); }; struct proc_ns { - void *ns; + struct ns_common *ns; const struct proc_ns_operations *ns_ops; }; diff --git a/ipc/namespace.c b/ipc/namespace.c index 3c1e8d3bd7d3..531029a67fef 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -154,7 +154,7 @@ static inline struct ipc_namespace *to_ipc_ns(struct ns_common *ns) return container_of(ns, struct ipc_namespace, ns); } -static void *ipcns_get(struct task_struct *task) +static struct ns_common *ipcns_get(struct task_struct *task) { struct ipc_namespace *ns = NULL; struct nsproxy *nsproxy; @@ -168,12 +168,12 @@ static void *ipcns_get(struct task_struct *task) return ns ? &ns->ns : NULL; } -static void ipcns_put(void *ns) +static void ipcns_put(struct ns_common *ns) { return put_ipc_ns(to_ipc_ns(ns)); } -static int ipcns_install(struct nsproxy *nsproxy, void *new) +static int ipcns_install(struct nsproxy *nsproxy, struct ns_common *new) { struct ipc_namespace *ns = to_ipc_ns(new); if (!ns_capable(ns->user_ns, CAP_SYS_ADMIN) || @@ -187,16 +187,10 @@ static int ipcns_install(struct nsproxy *nsproxy, void *new) return 0; } -static unsigned int ipcns_inum(void *vp) -{ - return ((struct ns_common *)vp)->inum; -} - const struct proc_ns_operations ipcns_operations = { .name = "ipc", .type = CLONE_NEWIPC, .get = ipcns_get, .put = ipcns_put, .install = ipcns_install, - .inum = ipcns_inum, }; diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index dd961ad86fbd..79aabce49a85 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -318,7 +318,7 @@ static inline struct pid_namespace *to_pid_ns(struct ns_common *ns) return container_of(ns, struct pid_namespace, ns); } -static void *pidns_get(struct task_struct *task) +static struct ns_common *pidns_get(struct task_struct *task) { struct pid_namespace *ns; @@ -331,12 +331,12 @@ static void *pidns_get(struct task_struct *task) return ns ? &ns->ns : NULL; } -static void pidns_put(void *ns) +static void pidns_put(struct ns_common *ns) { put_pid_ns(to_pid_ns(ns)); } -static int pidns_install(struct nsproxy *nsproxy, void *ns) +static int pidns_install(struct nsproxy *nsproxy, struct ns_common *ns) { struct pid_namespace *active = task_active_pid_ns(current); struct pid_namespace *ancestor, *new = to_pid_ns(ns); @@ -367,18 +367,12 @@ static int pidns_install(struct nsproxy *nsproxy, void *ns) return 0; } -static unsigned int pidns_inum(void *ns) -{ - return ((struct ns_common *)ns)->inum; -} - const struct proc_ns_operations pidns_operations = { .name = "pid", .type = CLONE_NEWPID, .get = pidns_get, .put = pidns_put, .install = pidns_install, - .inum = pidns_inum, }; static __init int pid_namespaces_init(void) diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 1ab2209228ff..29cd5ccfc37a 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -846,7 +846,7 @@ static inline struct user_namespace *to_user_ns(struct ns_common *ns) return container_of(ns, struct user_namespace, ns); } -static void *userns_get(struct task_struct *task) +static struct ns_common *userns_get(struct task_struct *task) { struct user_namespace *user_ns; @@ -857,12 +857,12 @@ static void *userns_get(struct task_struct *task) return user_ns ? &user_ns->ns : NULL; } -static void userns_put(void *ns) +static void userns_put(struct ns_common *ns) { put_user_ns(to_user_ns(ns)); } -static int userns_install(struct nsproxy *nsproxy, void *ns) +static int userns_install(struct nsproxy *nsproxy, struct ns_common *ns) { struct user_namespace *user_ns = to_user_ns(ns); struct cred *cred; @@ -893,18 +893,12 @@ static int userns_install(struct nsproxy *nsproxy, void *ns) return commit_creds(cred); } -static unsigned int userns_inum(void *ns) -{ - return ((struct ns_common *)ns)->inum; -} - const struct proc_ns_operations userns_operations = { .name = "user", .type = CLONE_NEWUSER, .get = userns_get, .put = userns_put, .install = userns_install, - .inum = userns_inum, }; static __init int user_namespaces_init(void) diff --git a/kernel/utsname.c b/kernel/utsname.c index 1917f74be8ec..20697befe466 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -93,7 +93,7 @@ static inline struct uts_namespace *to_uts_ns(struct ns_common *ns) return container_of(ns, struct uts_namespace, ns); } -static void *utsns_get(struct task_struct *task) +static struct ns_common *utsns_get(struct task_struct *task) { struct uts_namespace *ns = NULL; struct nsproxy *nsproxy; @@ -109,12 +109,12 @@ static void *utsns_get(struct task_struct *task) return ns ? &ns->ns : NULL; } -static void utsns_put(void *ns) +static void utsns_put(struct ns_common *ns) { put_uts_ns(to_uts_ns(ns)); } -static int utsns_install(struct nsproxy *nsproxy, void *new) +static int utsns_install(struct nsproxy *nsproxy, struct ns_common *new) { struct uts_namespace *ns = to_uts_ns(new); @@ -128,16 +128,10 @@ static int utsns_install(struct nsproxy *nsproxy, void *new) return 0; } -static unsigned int utsns_inum(void *vp) -{ - return ((struct ns_common *)vp)->inum; -} - const struct proc_ns_operations utsns_operations = { .name = "uts", .type = CLONE_NEWUTS, .get = utsns_get, .put = utsns_put, .install = utsns_install, - .inum = utsns_inum, }; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 97f4dc2132ad..2161f0979fce 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -629,7 +629,7 @@ void unregister_pernet_device(struct pernet_operations *ops) EXPORT_SYMBOL_GPL(unregister_pernet_device); #ifdef CONFIG_NET_NS -static void *netns_get(struct task_struct *task) +static struct ns_common *netns_get(struct task_struct *task) { struct net *net = NULL; struct nsproxy *nsproxy; @@ -648,12 +648,12 @@ static inline struct net *to_net_ns(struct ns_common *ns) return container_of(ns, struct net, ns); } -static void netns_put(void *ns) +static void netns_put(struct ns_common *ns) { put_net(to_net_ns(ns)); } -static int netns_install(struct nsproxy *nsproxy, void *ns) +static int netns_install(struct nsproxy *nsproxy, struct ns_common *ns) { struct net *net = to_net_ns(ns); @@ -666,17 +666,11 @@ static int netns_install(struct nsproxy *nsproxy, void *ns) return 0; } -static unsigned int netns_inum(void *ns) -{ - return ((struct ns_common *)ns)->inum; -} - const struct proc_ns_operations netns_operations = { .name = "net", .type = CLONE_NEWNET, .get = netns_get, .put = netns_put, .install = netns_install, - .inum = netns_inum, }; #endif From 6344c433a452b1a05d03a61a6a85d89f793bb7b8 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 00:45:45 -0400 Subject: [PATCH 06/10] new helpers: ns_alloc_inum/ns_free_inum take struct ns_common *, for now simply wrappers around proc_{alloc,free}_inum() Signed-off-by: Al Viro --- fs/namespace.c | 4 ++-- include/linux/proc_ns.h | 3 +++ ipc/namespace.c | 6 +++--- kernel/pid_namespace.c | 4 ++-- kernel/user_namespace.c | 4 ++-- kernel/utsname.c | 4 ++-- net/core/net_namespace.c | 4 ++-- 7 files changed, 16 insertions(+), 13 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index b9c16c3f63f5..30738d200866 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2645,7 +2645,7 @@ dput_out: static void free_mnt_ns(struct mnt_namespace *ns) { - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); put_user_ns(ns->user_ns); kfree(ns); } @@ -2667,7 +2667,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) new_ns = kmalloc(sizeof(struct mnt_namespace), GFP_KERNEL); if (!new_ns) return ERR_PTR(-ENOMEM); - ret = proc_alloc_inum(&new_ns->ns.inum); + ret = ns_alloc_inum(&new_ns->ns); if (ret) { kfree(new_ns); return ERR_PTR(ret); diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index f284959391fd..f5780ee7f8f7 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -71,4 +71,7 @@ static inline bool proc_ns_inode(struct inode *inode) { return false; } #endif /* CONFIG_PROC_FS */ +#define ns_alloc_inum(ns) proc_alloc_inum(&(ns)->inum) +#define ns_free_inum(ns) proc_free_inum((ns)->inum) + #endif /* _LINUX_PROC_NS_H */ diff --git a/ipc/namespace.c b/ipc/namespace.c index 531029a67fef..bcdd7a5c122a 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -26,7 +26,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, if (ns == NULL) return ERR_PTR(-ENOMEM); - err = proc_alloc_inum(&ns->ns.inum); + err = ns_alloc_inum(&ns->ns); if (err) { kfree(ns); return ERR_PTR(err); @@ -35,7 +35,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, atomic_set(&ns->count, 1); err = mq_init_ns(ns); if (err) { - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); kfree(ns); return ERR_PTR(err); } @@ -119,7 +119,7 @@ static void free_ipc_ns(struct ipc_namespace *ns) */ ipcns_notify(IPCNS_REMOVED); put_user_ns(ns->user_ns); - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); kfree(ns); } diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 79aabce49a85..5aa9158a84d5 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -105,7 +105,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns if (ns->pid_cachep == NULL) goto out_free_map; - err = proc_alloc_inum(&ns->ns.inum); + err = ns_alloc_inum(&ns->ns); if (err) goto out_free_map; @@ -142,7 +142,7 @@ static void destroy_pid_namespace(struct pid_namespace *ns) { int i; - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); for (i = 0; i < PIDMAP_ENTRIES; i++) kfree(ns->pidmap[i].page); put_user_ns(ns->user_ns); diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 29cd5ccfc37a..6bf8177768e5 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -86,7 +86,7 @@ int create_user_ns(struct cred *new) if (!ns) return -ENOMEM; - ret = proc_alloc_inum(&ns->ns.inum); + ret = ns_alloc_inum(&ns->ns); if (ret) { kmem_cache_free(user_ns_cachep, ns); return ret; @@ -136,7 +136,7 @@ void free_user_ns(struct user_namespace *ns) #ifdef CONFIG_PERSISTENT_KEYRINGS key_put(ns->persistent_keyring_register); #endif - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); kmem_cache_free(user_ns_cachep, ns); ns = parent; } while (atomic_dec_and_test(&parent->count)); diff --git a/kernel/utsname.c b/kernel/utsname.c index 20697befe466..c2a2b321d88a 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -42,7 +42,7 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, if (!ns) return ERR_PTR(-ENOMEM); - err = proc_alloc_inum(&ns->ns.inum); + err = ns_alloc_inum(&ns->ns); if (err) { kfree(ns); return ERR_PTR(err); @@ -84,7 +84,7 @@ void free_uts_ns(struct kref *kref) ns = container_of(kref, struct uts_namespace, kref); put_user_ns(ns->user_ns); - proc_free_inum(ns->ns.inum); + ns_free_inum(&ns->ns); kfree(ns); } diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 2161f0979fce..da775f53f3fd 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -386,12 +386,12 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_pid); static __net_init int net_ns_net_init(struct net *net) { - return proc_alloc_inum(&net->ns.inum); + return ns_alloc_inum(&net->ns); } static __net_exit void net_ns_net_exit(struct net *net) { - proc_free_inum(net->ns.inum); + ns_free_inum(&net->ns); } static struct pernet_operations __net_initdata net_ns_ops = { From 33c429405a2c8d9e42afb9fee88a63cfb2de1e98 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 02:32:53 -0400 Subject: [PATCH 07/10] copy address of proc_ns_ops into ns_common Signed-off-by: Al Viro --- fs/namespace.c | 1 + fs/proc/inode.c | 6 ++---- include/linux/ns_common.h | 3 +++ init/version.c | 3 +++ ipc/msgutil.c | 3 +++ ipc/namespace.c | 1 + kernel/nsproxy.c | 8 ++++---- kernel/pid.c | 3 +++ kernel/pid_namespace.c | 1 + kernel/user.c | 3 +++ kernel/user_namespace.c | 1 + kernel/utsname.c | 2 ++ net/core/net_namespace.c | 9 +++++++-- 13 files changed, 34 insertions(+), 10 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 30738d200866..f815218f92d3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2672,6 +2672,7 @@ static struct mnt_namespace *alloc_mnt_ns(struct user_namespace *user_ns) kfree(new_ns); return ERR_PTR(ret); } + new_ns->ns.ops = &mntns_operations; new_ns->seq = atomic64_add_return(1, &mnt_ns_seq); atomic_set(&new_ns->count, 1); new_ns->root = NULL; diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 43b703c6cd3b..a212996e0987 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -32,7 +32,6 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; struct ctl_table_header *head; - const struct proc_ns_operations *ns_ops; struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); @@ -51,10 +50,9 @@ static void proc_evict_inode(struct inode *inode) sysctl_head_put(head); } /* Release any associated namespace */ - ns_ops = PROC_I(inode)->ns.ns_ops; ns = PROC_I(inode)->ns.ns; - if (ns_ops && ns) - ns_ops->put(ns); + if (ns && ns->ops) + ns->ops->put(ns); } static struct kmem_cache * proc_inode_cachep; diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h index e7db1cd54047..ce23cf4bbe69 100644 --- a/include/linux/ns_common.h +++ b/include/linux/ns_common.h @@ -1,7 +1,10 @@ #ifndef _LINUX_NS_COMMON_H #define _LINUX_NS_COMMON_H +struct proc_ns_operations; + struct ns_common { + const struct proc_ns_operations *ops; unsigned int inum; }; diff --git a/init/version.c b/init/version.c index e23dbdabb26b..fe41a63efed6 100644 --- a/init/version.c +++ b/init/version.c @@ -36,6 +36,9 @@ struct uts_namespace init_uts_ns = { }, .user_ns = &init_user_ns, .ns.inum = PROC_UTS_INIT_INO, +#ifdef CONFIG_UTS_NS + .ns.ops = &utsns_operations, +#endif }; EXPORT_SYMBOL_GPL(init_uts_ns); diff --git a/ipc/msgutil.c b/ipc/msgutil.c index 5930471a2902..2b491590ebab 100644 --- a/ipc/msgutil.c +++ b/ipc/msgutil.c @@ -32,6 +32,9 @@ struct ipc_namespace init_ipc_ns = { .count = ATOMIC_INIT(1), .user_ns = &init_user_ns, .ns.inum = PROC_IPC_INIT_INO, +#ifdef CONFIG_IPC_NS + .ns.ops = &ipcns_operations, +#endif }; atomic_t nr_ipc_ns = ATOMIC_INIT(1); diff --git a/ipc/namespace.c b/ipc/namespace.c index bcdd7a5c122a..382e2aa42d8a 100644 --- a/ipc/namespace.c +++ b/ipc/namespace.c @@ -31,6 +31,7 @@ static struct ipc_namespace *create_ipc_ns(struct user_namespace *user_ns, kfree(ns); return ERR_PTR(err); } + ns->ns.ops = &ipcns_operations; atomic_set(&ns->count, 1); err = mq_init_ns(ns); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index ef42d0ab3115..87c37221cb7f 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -220,11 +220,11 @@ void exit_task_namespaces(struct task_struct *p) SYSCALL_DEFINE2(setns, int, fd, int, nstype) { - const struct proc_ns_operations *ops; struct task_struct *tsk = current; struct nsproxy *new_nsproxy; struct proc_ns *ei; struct file *file; + struct ns_common *ns; int err; file = proc_ns_fget(fd); @@ -233,8 +233,8 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) err = -EINVAL; ei = get_proc_ns(file_inode(file)); - ops = ei->ns_ops; - if (nstype && (ops->type != nstype)) + ns = ei->ns; + if (nstype && (ns->ops->type != nstype)) goto out; new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); @@ -243,7 +243,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) goto out; } - err = ops->install(new_nsproxy, ei->ns); + err = ns->ops->install(new_nsproxy, ns); if (err) { free_nsproxy(new_nsproxy); goto out; diff --git a/kernel/pid.c b/kernel/pid.c index 3650698cf1dc..c17a993a4d2a 100644 --- a/kernel/pid.c +++ b/kernel/pid.c @@ -80,6 +80,9 @@ struct pid_namespace init_pid_ns = { .child_reaper = &init_task, .user_ns = &init_user_ns, .ns.inum = PROC_PID_INIT_INO, +#ifdef CONFIG_PID_NS + .ns.ops = &pidns_operations, +#endif }; EXPORT_SYMBOL_GPL(init_pid_ns); diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c index 5aa9158a84d5..e1bafe3b47bb 100644 --- a/kernel/pid_namespace.c +++ b/kernel/pid_namespace.c @@ -108,6 +108,7 @@ static struct pid_namespace *create_pid_namespace(struct user_namespace *user_ns err = ns_alloc_inum(&ns->ns); if (err) goto out_free_map; + ns->ns.ops = &pidns_operations; kref_init(&ns->kref); ns->level = level; diff --git a/kernel/user.c b/kernel/user.c index a7ca84bad8e6..69b800aebf13 100644 --- a/kernel/user.c +++ b/kernel/user.c @@ -51,6 +51,9 @@ struct user_namespace init_user_ns = { .owner = GLOBAL_ROOT_UID, .group = GLOBAL_ROOT_GID, .ns.inum = PROC_USER_INIT_INO, +#ifdef CONFIG_USER_NS + .ns.ops = &userns_operations, +#endif #ifdef CONFIG_PERSISTENT_KEYRINGS .persistent_keyring_register_sem = __RWSEM_INITIALIZER(init_user_ns.persistent_keyring_register_sem), diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c index 6bf8177768e5..1491ad00388f 100644 --- a/kernel/user_namespace.c +++ b/kernel/user_namespace.c @@ -91,6 +91,7 @@ int create_user_ns(struct cred *new) kmem_cache_free(user_ns_cachep, ns); return ret; } + ns->ns.ops = &userns_operations; atomic_set(&ns->count, 1); /* Leave the new->user_ns reference with the new user namespace. */ diff --git a/kernel/utsname.c b/kernel/utsname.c index c2a2b321d88a..831ea7108232 100644 --- a/kernel/utsname.c +++ b/kernel/utsname.c @@ -48,6 +48,8 @@ static struct uts_namespace *clone_uts_ns(struct user_namespace *user_ns, return ERR_PTR(err); } + ns->ns.ops = &utsns_operations; + down_read(&uts_sem); memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); ns->user_ns = get_user_ns(user_ns); diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index da775f53f3fd..4d4acaf7b498 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -339,6 +339,7 @@ struct net *get_net_ns_by_fd(int fd) { struct proc_ns *ei; struct file *file; + struct ns_common *ns; struct net *net; file = proc_ns_fget(fd); @@ -346,8 +347,9 @@ struct net *get_net_ns_by_fd(int fd) return ERR_CAST(file); ei = get_proc_ns(file_inode(file)); - if (ei->ns_ops == &netns_operations) - net = get_net(container_of(ei->ns, struct net, ns)); + ns = ei->ns; + if (ns->ops == &netns_operations) + net = get_net(container_of(ns, struct net, ns)); else net = ERR_PTR(-EINVAL); @@ -386,6 +388,9 @@ EXPORT_SYMBOL_GPL(get_net_ns_by_pid); static __net_init int net_ns_net_init(struct net *net) { +#ifdef CONFIG_NET_NS + net->ns.ops = &netns_operations; +#endif return ns_alloc_inum(&net->ns); } From f77c80142e1afe6d5c16975ca5d7d1fc324b16f9 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 03:13:17 -0400 Subject: [PATCH 08/10] bury struct proc_ns in fs/proc a) make get_proc_ns() return a pointer to struct ns_common b) mirror ns_ops in dentry->d_fsdata of ns dentries, so that is_mnt_ns_file() could get away with fewer dereferences. That way struct proc_ns becomes invisible outside of fs/proc/*.c Signed-off-by: Al Viro --- fs/namespace.c | 13 ++----------- fs/proc/internal.h | 5 +++++ fs/proc/namespaces.c | 7 ++++--- include/linux/proc_ns.h | 9 ++------- kernel/nsproxy.c | 4 +--- net/core/net_namespace.c | 4 +--- 6 files changed, 15 insertions(+), 27 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index f815218f92d3..9dfb4cac0c41 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1570,16 +1570,7 @@ static bool is_mnt_ns_file(struct dentry *dentry) { /* Is this a proxy for a mount namespace? */ struct inode *inode = dentry->d_inode; - struct proc_ns *ei; - - if (!proc_ns_inode(inode)) - return false; - - ei = get_proc_ns(inode); - if (ei->ns_ops != &mntns_operations) - return false; - - return true; + return proc_ns_inode(inode) && dentry->d_fsdata == &mntns_operations; } struct mnt_namespace *to_mnt_ns(struct ns_common *ns) @@ -1596,7 +1587,7 @@ static bool mnt_ns_loop(struct dentry *dentry) if (!is_mnt_ns_file(dentry)) return false; - mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)->ns); + mnt_ns = to_mnt_ns(get_proc_ns(dentry->d_inode)); return current->nsproxy->mnt_ns->seq >= mnt_ns->seq; } diff --git a/fs/proc/internal.h b/fs/proc/internal.h index aa7a0ee182e1..0fabc48d905f 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -57,6 +57,11 @@ union proc_op { struct task_struct *task); }; +struct proc_ns { + struct ns_common *ns; + const struct proc_ns_operations *ns_ops; +}; + struct proc_inode { struct pid *pid; int fd; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 995e8e98237d..18fc1cf899de 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -45,7 +45,7 @@ static const struct inode_operations ns_inode_operations = { static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = dentry->d_fsdata; return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", ns_ops->name, inode->i_ino); @@ -75,6 +75,7 @@ static struct dentry *proc_ns_get_dentry(struct super_block *sb, ns_ops->put(ns); return ERR_PTR(-ENOMEM); } + dentry->d_fsdata = (void *)ns_ops; inode = iget_locked(sb, ns->inum); if (!inode) { @@ -286,9 +287,9 @@ out_invalid: return ERR_PTR(-EINVAL); } -struct proc_ns *get_proc_ns(struct inode *inode) +struct ns_common *get_proc_ns(struct inode *inode) { - return &PROC_I(inode)->ns; + return PROC_I(inode)->ns.ns; } bool proc_ns_inode(struct inode *inode) diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index f5780ee7f8f7..2837ff41cfe3 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -16,11 +16,6 @@ struct proc_ns_operations { int (*install)(struct nsproxy *nsproxy, struct ns_common *ns); }; -struct proc_ns { - struct ns_common *ns; - const struct proc_ns_operations *ns_ops; -}; - extern const struct proc_ns_operations netns_operations; extern const struct proc_ns_operations utsns_operations; extern const struct proc_ns_operations ipcns_operations; @@ -44,7 +39,7 @@ enum { extern int pid_ns_prepare_proc(struct pid_namespace *ns); extern void pid_ns_release_proc(struct pid_namespace *ns); extern struct file *proc_ns_fget(int fd); -extern struct proc_ns *get_proc_ns(struct inode *); +extern struct ns_common *get_proc_ns(struct inode *); extern int proc_alloc_inum(unsigned int *pino); extern void proc_free_inum(unsigned int inum); extern bool proc_ns_inode(struct inode *inode); @@ -59,7 +54,7 @@ static inline struct file *proc_ns_fget(int fd) return ERR_PTR(-EINVAL); } -static inline struct proc_ns *get_proc_ns(struct inode *inode) { return NULL; } +static inline struct ns_common *get_proc_ns(struct inode *inode) { return NULL; } static inline int proc_alloc_inum(unsigned int *inum) { diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 87c37221cb7f..49746c81ad8d 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -222,7 +222,6 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) { struct task_struct *tsk = current; struct nsproxy *new_nsproxy; - struct proc_ns *ei; struct file *file; struct ns_common *ns; int err; @@ -232,8 +231,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) return PTR_ERR(file); err = -EINVAL; - ei = get_proc_ns(file_inode(file)); - ns = ei->ns; + ns = get_proc_ns(file_inode(file)); if (nstype && (ns->ops->type != nstype)) goto out; diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 4d4acaf7b498..ce780c722e48 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -337,7 +337,6 @@ EXPORT_SYMBOL_GPL(__put_net); struct net *get_net_ns_by_fd(int fd) { - struct proc_ns *ei; struct file *file; struct ns_common *ns; struct net *net; @@ -346,8 +345,7 @@ struct net *get_net_ns_by_fd(int fd) if (IS_ERR(file)) return ERR_CAST(file); - ei = get_proc_ns(file_inode(file)); - ns = ei->ns; + ns = get_proc_ns(file_inode(file)); if (ns->ops == &netns_operations) net = get_net(container_of(ns, struct net, ns)); else From e149ed2b805fefdccf7ccdfc19eca22fdd4514ac Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 10:57:28 -0400 Subject: [PATCH 09/10] take the targets of /proc/*/ns/* symlinks to separate fs New pseudo-filesystem: nsfs. Targets of /proc/*/ns/* live there now. It's not mountable (not even registered, so it's not in /proc/filesystems, etc.). Files on it *are* bindable - we explicitly permit that in do_loopback(). This stuff lives in fs/nsfs.c now; proc_ns_fget() moved there as well. get_proc_ns() is a macro now (it's simply returning ->i_private; would have been an inline, if not for header ordering headache). proc_ns_inode() is an ex-parrot. The interface used in procfs is ns_get_path(path, task, ops) and ns_get_name(buf, size, task, ops). Dentries and inodes are never hashed; a non-counting reference to dentry is stashed in ns_common (removed by ->d_prune()) and reused by ns_get_path() if present. See ns_get_path()/ns_prune_dentry/nsfs_evict() for details of that mechanism. As the result, proc_ns_follow_link() has stopped poking in nd->path.mnt; it does nd_jump_link() on a consistent pair it gets from ns_get_path(). Signed-off-by: Al Viro --- fs/Makefile | 2 +- fs/internal.h | 5 ++ fs/namespace.c | 9 ++- fs/nsfs.c | 161 +++++++++++++++++++++++++++++++++++++ fs/proc/inode.c | 5 -- fs/proc/namespaces.c | 152 +++------------------------------- include/linux/ns_common.h | 1 + include/linux/proc_ns.h | 31 ++++--- include/uapi/linux/magic.h | 1 + init/main.c | 2 + 10 files changed, 208 insertions(+), 161 deletions(-) create mode 100644 fs/nsfs.c diff --git a/fs/Makefile b/fs/Makefile index 34a1b9dea6dd..34393376eaa2 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -11,7 +11,7 @@ obj-y := open.o read_write.o file_table.o super.o \ attr.o bad_inode.o file.o filesystems.o namespace.o \ seq_file.o xattr.o libfs.o fs-writeback.o \ pnode.o splice.o sync.o utimes.o \ - stack.o fs_struct.o statfs.o fs_pin.o + stack.o fs_struct.o statfs.o fs_pin.o nsfs.o ifeq ($(CONFIG_BLOCK),y) obj-y += buffer.o block_dev.o direct-io.o mpage.o diff --git a/fs/internal.h b/fs/internal.h index 757ba2abf21e..e9a61fe67575 100644 --- a/fs/internal.h +++ b/fs/internal.h @@ -147,3 +147,8 @@ extern const struct file_operations pipefifo_fops; */ extern void sb_pin_kill(struct super_block *sb); extern void mnt_pin_kill(struct mount *m); + +/* + * fs/nsfs.c + */ +extern struct dentry_operations ns_dentry_operations; diff --git a/fs/namespace.c b/fs/namespace.c index 9dfb4cac0c41..30df6e7dd807 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -1569,8 +1569,8 @@ SYSCALL_DEFINE1(oldumount, char __user *, name) static bool is_mnt_ns_file(struct dentry *dentry) { /* Is this a proxy for a mount namespace? */ - struct inode *inode = dentry->d_inode; - return proc_ns_inode(inode) && dentry->d_fsdata == &mntns_operations; + return dentry->d_op == &ns_dentry_operations && + dentry->d_fsdata == &mntns_operations; } struct mnt_namespace *to_mnt_ns(struct ns_common *ns) @@ -2016,7 +2016,10 @@ static int do_loopback(struct path *path, const char *old_name, if (IS_MNT_UNBINDABLE(old)) goto out2; - if (!check_mnt(parent) || !check_mnt(old)) + if (!check_mnt(parent)) + goto out2; + + if (!check_mnt(old) && old_path.dentry->d_op != &ns_dentry_operations) goto out2; if (!recurse && has_locked_children(old, old_path.dentry)) diff --git a/fs/nsfs.c b/fs/nsfs.c new file mode 100644 index 000000000000..af1b24fa899d --- /dev/null +++ b/fs/nsfs.c @@ -0,0 +1,161 @@ +#include +#include +#include +#include +#include +#include + +static struct vfsmount *nsfs_mnt; + +static const struct file_operations ns_file_operations = { + .llseek = no_llseek, +}; + +static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) +{ + struct inode *inode = dentry->d_inode; + const struct proc_ns_operations *ns_ops = dentry->d_fsdata; + + return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", + ns_ops->name, inode->i_ino); +} + +static void ns_prune_dentry(struct dentry *dentry) +{ + struct inode *inode = dentry->d_inode; + if (inode) { + struct ns_common *ns = inode->i_private; + atomic_long_set(&ns->stashed, 0); + } +} + +const struct dentry_operations ns_dentry_operations = +{ + .d_prune = ns_prune_dentry, + .d_delete = always_delete_dentry, + .d_dname = ns_dname, +}; + +static void nsfs_evict(struct inode *inode) +{ + struct ns_common *ns = inode->i_private; + clear_inode(inode); + ns->ops->put(ns); +} + +void *ns_get_path(struct path *path, struct task_struct *task, + const struct proc_ns_operations *ns_ops) +{ + struct vfsmount *mnt = mntget(nsfs_mnt); + struct qstr qname = { .name = "", }; + struct dentry *dentry; + struct inode *inode; + struct ns_common *ns; + unsigned long d; + +again: + ns = ns_ops->get(task); + if (!ns) { + mntput(mnt); + return ERR_PTR(-ENOENT); + } + rcu_read_lock(); + d = atomic_long_read(&ns->stashed); + if (!d) + goto slow; + dentry = (struct dentry *)d; + if (!lockref_get_not_dead(&dentry->d_lockref)) + goto slow; + rcu_read_unlock(); + ns_ops->put(ns); +got_it: + path->mnt = mnt; + path->dentry = dentry; + return NULL; +slow: + rcu_read_unlock(); + inode = new_inode_pseudo(mnt->mnt_sb); + if (!inode) { + ns_ops->put(ns); + mntput(mnt); + return ERR_PTR(-ENOMEM); + } + inode->i_ino = ns->inum; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_flags |= S_IMMUTABLE; + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_fop = &ns_file_operations; + inode->i_private = ns; + + dentry = d_alloc_pseudo(mnt->mnt_sb, &qname); + if (!dentry) { + iput(inode); + mntput(mnt); + return ERR_PTR(-ENOMEM); + } + d_instantiate(dentry, inode); + dentry->d_fsdata = (void *)ns_ops; + d = atomic_long_cmpxchg(&ns->stashed, 0, (unsigned long)dentry); + if (d) { + d_delete(dentry); /* make sure ->d_prune() does nothing */ + dput(dentry); + cpu_relax(); + goto again; + } + goto got_it; +} + +int ns_get_name(char *buf, size_t size, struct task_struct *task, + const struct proc_ns_operations *ns_ops) +{ + struct ns_common *ns; + int res = -ENOENT; + ns = ns_ops->get(task); + if (ns) { + res = snprintf(buf, size, "%s:[%u]", ns_ops->name, ns->inum); + ns_ops->put(ns); + } + return res; +} + +struct file *proc_ns_fget(int fd) +{ + struct file *file; + + file = fget(fd); + if (!file) + return ERR_PTR(-EBADF); + + if (file->f_op != &ns_file_operations) + goto out_invalid; + + return file; + +out_invalid: + fput(file); + return ERR_PTR(-EINVAL); +} + +static const struct super_operations nsfs_ops = { + .statfs = simple_statfs, + .evict_inode = nsfs_evict, +}; +static struct dentry *nsfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "nsfs:", &nsfs_ops, + &ns_dentry_operations, NSFS_MAGIC); +} +static struct file_system_type nsfs = { + .name = "nsfs", + .mount = nsfs_mount, + .kill_sb = kill_anon_super, +}; + +void __init nsfs_init(void) +{ + nsfs_mnt = kern_mount(&nsfs); + if (IS_ERR(nsfs_mnt)) + panic("can't set nsfs up\n"); + nsfs_mnt->mnt_sb->s_flags &= ~MS_NOUSER; +} diff --git a/fs/proc/inode.c b/fs/proc/inode.c index a212996e0987..57a9be9a6668 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -32,7 +32,6 @@ static void proc_evict_inode(struct inode *inode) { struct proc_dir_entry *de; struct ctl_table_header *head; - struct ns_common *ns; truncate_inode_pages_final(&inode->i_data); clear_inode(inode); @@ -49,10 +48,6 @@ static void proc_evict_inode(struct inode *inode) RCU_INIT_POINTER(PROC_I(inode)->sysctl, NULL); sysctl_head_put(head); } - /* Release any associated namespace */ - ns = PROC_I(inode)->ns.ns; - if (ns && ns->ops) - ns->ops->put(ns); } static struct kmem_cache * proc_inode_cachep; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index 18fc1cf899de..aaaac77abad0 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -1,10 +1,6 @@ #include #include -#include #include -#include -#include -#include #include #include #include @@ -34,139 +30,45 @@ static const struct proc_ns_operations *ns_entries[] = { &mntns_operations, }; -static const struct file_operations ns_file_operations = { - .llseek = no_llseek, -}; - -static const struct inode_operations ns_inode_operations = { - .setattr = proc_setattr, -}; - -static char *ns_dname(struct dentry *dentry, char *buffer, int buflen) -{ - struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = dentry->d_fsdata; - - return dynamic_dname(dentry, buffer, buflen, "%s:[%lu]", - ns_ops->name, inode->i_ino); -} - -const struct dentry_operations ns_dentry_operations = -{ - .d_delete = always_delete_dentry, - .d_dname = ns_dname, -}; - -static struct dentry *proc_ns_get_dentry(struct super_block *sb, - struct task_struct *task, const struct proc_ns_operations *ns_ops) -{ - struct dentry *dentry, *result; - struct inode *inode; - struct proc_inode *ei; - struct qstr qname = { .name = "", }; - struct ns_common *ns; - - ns = ns_ops->get(task); - if (!ns) - return ERR_PTR(-ENOENT); - - dentry = d_alloc_pseudo(sb, &qname); - if (!dentry) { - ns_ops->put(ns); - return ERR_PTR(-ENOMEM); - } - dentry->d_fsdata = (void *)ns_ops; - - inode = iget_locked(sb, ns->inum); - if (!inode) { - dput(dentry); - ns_ops->put(ns); - return ERR_PTR(-ENOMEM); - } - - ei = PROC_I(inode); - if (inode->i_state & I_NEW) { - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_op = &ns_inode_operations; - inode->i_mode = S_IFREG | S_IRUGO; - inode->i_fop = &ns_file_operations; - ei->ns.ns_ops = ns_ops; - ei->ns.ns = ns; - unlock_new_inode(inode); - } else { - ns_ops->put(ns); - } - - d_set_d_op(dentry, &ns_dentry_operations); - result = d_instantiate_unique(dentry, inode); - if (result) { - dput(dentry); - dentry = result; - } - - return dentry; -} - static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; - struct super_block *sb = inode->i_sb; - struct proc_inode *ei = PROC_I(inode); + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; struct task_struct *task; struct path ns_path; void *error = ERR_PTR(-EACCES); task = get_proc_task(inode); if (!task) - goto out; + return error; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) - goto out_put_task; - - ns_path.dentry = proc_ns_get_dentry(sb, task, ei->ns.ns_ops); - if (IS_ERR(ns_path.dentry)) { - error = ERR_CAST(ns_path.dentry); - goto out_put_task; + if (ptrace_may_access(task, PTRACE_MODE_READ)) { + error = ns_get_path(&ns_path, task, ns_ops); + if (!error) + nd_jump_link(nd, &ns_path); } - - ns_path.mnt = mntget(nd->path.mnt); - nd_jump_link(nd, &ns_path); - error = NULL; - -out_put_task: put_task_struct(task); -out: return error; } static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct inode *inode = dentry->d_inode; - struct proc_inode *ei = PROC_I(inode); - const struct proc_ns_operations *ns_ops = ei->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; struct task_struct *task; - struct ns_common *ns; char name[50]; int res = -EACCES; task = get_proc_task(inode); if (!task) - goto out; + return res; - if (!ptrace_may_access(task, PTRACE_MODE_READ)) - goto out_put_task; - - res = -ENOENT; - ns = ns_ops->get(task); - if (!ns) - goto out_put_task; - - snprintf(name, sizeof(name), "%s:[%u]", ns_ops->name, ns->inum); - res = readlink_copy(buffer, buflen, name); - ns_ops->put(ns); -out_put_task: + if (ptrace_may_access(task, PTRACE_MODE_READ)) { + res = ns_get_name(name, sizeof(name), task, ns_ops); + if (res >= 0) + res = readlink_copy(buffer, buflen, name); + } put_task_struct(task); -out: return res; } @@ -268,31 +170,3 @@ const struct inode_operations proc_ns_dir_inode_operations = { .getattr = pid_getattr, .setattr = proc_setattr, }; - -struct file *proc_ns_fget(int fd) -{ - struct file *file; - - file = fget(fd); - if (!file) - return ERR_PTR(-EBADF); - - if (file->f_op != &ns_file_operations) - goto out_invalid; - - return file; - -out_invalid: - fput(file); - return ERR_PTR(-EINVAL); -} - -struct ns_common *get_proc_ns(struct inode *inode) -{ - return PROC_I(inode)->ns.ns; -} - -bool proc_ns_inode(struct inode *inode) -{ - return inode->i_fop == &ns_file_operations; -} diff --git a/include/linux/ns_common.h b/include/linux/ns_common.h index ce23cf4bbe69..85a5c8c16be9 100644 --- a/include/linux/ns_common.h +++ b/include/linux/ns_common.h @@ -4,6 +4,7 @@ struct proc_ns_operations; struct ns_common { + atomic_long_t stashed; const struct proc_ns_operations *ops; unsigned int inum; }; diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index 2837ff41cfe3..42dfc615dbf8 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -4,9 +4,11 @@ #ifndef _LINUX_PROC_NS_H #define _LINUX_PROC_NS_H +#include + struct pid_namespace; struct nsproxy; -struct ns_common; +struct path; struct proc_ns_operations { const char *name; @@ -38,35 +40,38 @@ enum { extern int pid_ns_prepare_proc(struct pid_namespace *ns); extern void pid_ns_release_proc(struct pid_namespace *ns); -extern struct file *proc_ns_fget(int fd); -extern struct ns_common *get_proc_ns(struct inode *); extern int proc_alloc_inum(unsigned int *pino); extern void proc_free_inum(unsigned int inum); -extern bool proc_ns_inode(struct inode *inode); #else /* CONFIG_PROC_FS */ static inline int pid_ns_prepare_proc(struct pid_namespace *ns) { return 0; } static inline void pid_ns_release_proc(struct pid_namespace *ns) {} -static inline struct file *proc_ns_fget(int fd) -{ - return ERR_PTR(-EINVAL); -} - -static inline struct ns_common *get_proc_ns(struct inode *inode) { return NULL; } - static inline int proc_alloc_inum(unsigned int *inum) { *inum = 1; return 0; } static inline void proc_free_inum(unsigned int inum) {} -static inline bool proc_ns_inode(struct inode *inode) { return false; } #endif /* CONFIG_PROC_FS */ -#define ns_alloc_inum(ns) proc_alloc_inum(&(ns)->inum) +static inline int ns_alloc_inum(struct ns_common *ns) +{ + atomic_long_set(&ns->stashed, 0); + return proc_alloc_inum(&ns->inum); +} + #define ns_free_inum(ns) proc_free_inum((ns)->inum) +extern struct file *proc_ns_fget(int fd); +#define get_proc_ns(inode) ((struct ns_common *)(inode)->i_private) +extern void *ns_get_path(struct path *path, struct task_struct *task, + const struct proc_ns_operations *ns_ops); + +extern int ns_get_name(char *buf, size_t size, struct task_struct *task, + const struct proc_ns_operations *ns_ops); +extern void nsfs_init(void); + #endif /* _LINUX_PROC_NS_H */ diff --git a/include/uapi/linux/magic.h b/include/uapi/linux/magic.h index 77c60311a6c6..7d664ea85ebd 100644 --- a/include/uapi/linux/magic.h +++ b/include/uapi/linux/magic.h @@ -72,5 +72,6 @@ #define MTD_INODE_FS_MAGIC 0x11307854 #define ANON_INODE_FS_MAGIC 0x09041934 #define BTRFS_TEST_MAGIC 0x73727279 +#define NSFS_MAGIC 0x6e736673 #endif /* __LINUX_MAGIC_H__ */ diff --git a/init/main.c b/init/main.c index 800a0daede7e..bcc75057ea87 100644 --- a/init/main.c +++ b/init/main.c @@ -78,6 +78,7 @@ #include #include #include +#include #include #include @@ -660,6 +661,7 @@ asmlinkage __visible void __init start_kernel(void) /* rootfs populating might need page-writeback */ page_writeback_init(); proc_root_init(); + nsfs_init(); cgroup_init(); cpuset_init(); taskstats_init_early(); From 3d3d35b1e94ec918fc0ae670663235bf197d8609 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 1 Nov 2014 11:10:28 -0400 Subject: [PATCH 10/10] kill proc_ns completely procfs inodes need only the ns_ops part; nsfs inodes don't need it at all Signed-off-by: Al Viro --- fs/proc/inode.c | 3 +-- fs/proc/internal.h | 7 +------ fs/proc/namespaces.c | 6 +++--- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 57a9be9a6668..8420a2f80811 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -66,8 +66,7 @@ static struct inode *proc_alloc_inode(struct super_block *sb) ei->pde = NULL; ei->sysctl = NULL; ei->sysctl_entry = NULL; - ei->ns.ns = NULL; - ei->ns.ns_ops = NULL; + ei->ns_ops = NULL; inode = &ei->vfs_inode; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; return inode; diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 0fabc48d905f..d689fd6960d5 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -57,11 +57,6 @@ union proc_op { struct task_struct *task); }; -struct proc_ns { - struct ns_common *ns; - const struct proc_ns_operations *ns_ops; -}; - struct proc_inode { struct pid *pid; int fd; @@ -69,7 +64,7 @@ struct proc_inode { struct proc_dir_entry *pde; struct ctl_table_header *sysctl; struct ctl_table *sysctl_entry; - struct proc_ns ns; + const struct proc_ns_operations *ns_ops; struct inode vfs_inode; }; diff --git a/fs/proc/namespaces.c b/fs/proc/namespaces.c index aaaac77abad0..c9eac4563fa8 100644 --- a/fs/proc/namespaces.c +++ b/fs/proc/namespaces.c @@ -33,7 +33,7 @@ static const struct proc_ns_operations *ns_entries[] = { static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; struct path ns_path; void *error = ERR_PTR(-EACCES); @@ -54,7 +54,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd) static int proc_ns_readlink(struct dentry *dentry, char __user *buffer, int buflen) { struct inode *inode = dentry->d_inode; - const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns.ns_ops; + const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops; struct task_struct *task; char name[50]; int res = -EACCES; @@ -92,7 +92,7 @@ static int proc_ns_instantiate(struct inode *dir, ei = PROC_I(inode); inode->i_mode = S_IFLNK|S_IRWXUGO; inode->i_op = &proc_ns_link_inode_operations; - ei->ns.ns_ops = ns_ops; + ei->ns_ops = ns_ops; d_set_d_op(dentry, &pid_dentry_operations); d_add(dentry, inode);