diff --git a/fs/namespace.c b/fs/namespace.c index 85b5f7bea82e..88ebde39959f 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -31,6 +31,10 @@ #include #include +#ifdef CONFIG_NET_NS +#include +#endif + #include "pnode.h" #include "internal.h" @@ -1013,12 +1017,25 @@ vfs_submount(const struct dentry *mountpoint, struct file_system_type *type, } EXPORT_SYMBOL_GPL(vfs_submount); +#ifdef CONFIG_NET_NS +static bool is_net_ns_file(struct dentry *dentry) +{ + /* Is this a proxy for a mount namespace? */ + return dentry->d_op == &ns_dentry_operations && + dentry->d_fsdata == &netns_operations; +} +#endif + static struct mount *clone_mnt(struct mount *old, struct dentry *root, int flag) { struct super_block *sb = old->mnt.mnt_sb; struct mount *mnt; int err; +#ifdef CONFIG_NET_NS + struct ns_common *ns = NULL; + struct net *net = NULL; +#endif mnt = alloc_vfsmnt(old->mnt_devname); if (!mnt) @@ -1035,6 +1052,20 @@ static struct mount *clone_mnt(struct mount *old, struct dentry *root, goto out_free; } +#ifdef CONFIG_NET_NS + if (!(flag & CL_COPY_MNT_NS_FILE) && is_net_ns_file(root)) { + ns = get_proc_ns(d_inode(root)); + if (ns == NULL || ns->ops->type != CLONE_NEWNET) { + err = -EINVAL; + + goto out_free; + } + + net = to_net_ns(ns); + net = get_net(net); + } +#endif + mnt->mnt.mnt_flags = old->mnt.mnt_flags; mnt->mnt.mnt_flags &= ~(MNT_WRITE_HOLD|MNT_MARKED|MNT_INTERNAL); diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 854d39ef1ca3..df3fb066a002 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -469,4 +469,11 @@ static inline void fnhe_genid_bump(struct net *net) atomic_inc(&net->fnhe_genid); } +#ifdef CONFIG_NET_NS +static inline struct net *to_net_ns(struct ns_common *ns) +{ + return container_of(ns, struct net, ns); +} +#endif + #endif /* __NET_NET_NAMESPACE_H */ diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 757cc1d084e7..b6771c201805 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -1328,11 +1328,6 @@ static struct ns_common *netns_get(struct task_struct *task) 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(struct ns_common *ns) { put_net(to_net_ns(ns));