New helper function returns pointer to struct ns_common, can check namespace type and uses struct fd for returning file reference: this saves couple atomic operations for single-threaded applications. Signed-off-by: Konstantin Khlebnikov <khlebnikov@xxxxxxxxxxxxxx> --- fs/nsfs.c | 20 +++++++++++++------- include/linux/proc_ns.h | 4 +++- kernel/nsproxy.c | 15 +++++---------- net/core/net_namespace.c | 18 ++++++------------ 4 files changed, 27 insertions(+), 30 deletions(-) diff --git a/fs/nsfs.c b/fs/nsfs.c index 8f20d6016e20..a2e803c97960 100644 --- a/fs/nsfs.c +++ b/fs/nsfs.c @@ -119,21 +119,27 @@ int ns_get_name(char *buf, size_t size, struct task_struct *task, return res; } -struct file *proc_ns_fget(int fd) +struct ns_common *proc_ns_fdget(int fd, int nstype, struct fd *fd_ref) { - struct file *file; + struct ns_common *ns; + struct fd f; - file = fget(fd); - if (!file) + f = fdget(fd); + if (!f.file) return ERR_PTR(-EBADF); - if (file->f_op != &ns_file_operations) + if (f.file->f_op != &ns_file_operations) + goto out_invalid; + + ns = get_proc_ns(file_inode(f.file)); + if (nstype && (ns->ops->type != nstype)) goto out_invalid; - return file; + *fd_ref = f; + return ns; out_invalid: - fput(file); + fdput(f); return ERR_PTR(-EINVAL); } diff --git a/include/linux/proc_ns.h b/include/linux/proc_ns.h index 42dfc615dbf8..406ea4617606 100644 --- a/include/linux/proc_ns.h +++ b/include/linux/proc_ns.h @@ -9,6 +9,7 @@ struct pid_namespace; struct nsproxy; struct path; +struct fd; struct proc_ns_operations { const char *name; @@ -65,7 +66,8 @@ static inline int ns_alloc_inum(struct ns_common *ns) #define ns_free_inum(ns) proc_free_inum((ns)->inum) -extern struct file *proc_ns_fget(int fd); +extern struct ns_common *proc_ns_fdget(int fd, int nstype, struct fd *fd_ref); + #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); diff --git a/kernel/nsproxy.c b/kernel/nsproxy.c index 49746c81ad8d..689b929a0fcb 100644 --- a/kernel/nsproxy.c +++ b/kernel/nsproxy.c @@ -222,18 +222,13 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) { struct task_struct *tsk = current; struct nsproxy *new_nsproxy; - struct file *file; + struct fd fd_ref; struct ns_common *ns; int err; - file = proc_ns_fget(fd); - if (IS_ERR(file)) - return PTR_ERR(file); - - err = -EINVAL; - ns = get_proc_ns(file_inode(file)); - if (nstype && (ns->ops->type != nstype)) - goto out; + ns = proc_ns_fdget(fd, nstype, &fd_ref); + if (IS_ERR(ns)) + return PTR_ERR(ns); new_nsproxy = create_new_namespaces(0, tsk, current_user_ns(), tsk->fs); if (IS_ERR(new_nsproxy)) { @@ -248,7 +243,7 @@ SYSCALL_DEFINE2(setns, int, fd, int, nstype) } switch_task_namespaces(tsk, new_nsproxy); out: - fput(file); + fdput(fd_ref); return err; } diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 2c2eb1b629b1..ffc5e6df86dc 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -465,21 +465,15 @@ EXPORT_SYMBOL_GPL(__put_net); struct net *get_net_ns_by_fd(int fd) { - struct file *file; struct ns_common *ns; + struct fd fd_ref; struct net *net; - file = proc_ns_fget(fd); - if (IS_ERR(file)) - return ERR_CAST(file); - - ns = get_proc_ns(file_inode(file)); - if (ns->ops == &netns_operations) - net = get_net(container_of(ns, struct net, ns)); - else - net = ERR_PTR(-EINVAL); - - fput(file); + ns = proc_ns_fdget(fd, CLONE_NEWNET, &fd_ref); + if (IS_ERR(ns)) + return ERR_CAST(ns); + net = get_net(container_of(ns, struct net, ns)); + fdput(fd_ref); return net; } -- To unsubscribe from this list: send the line "unsubscribe linux-api" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html