Commit 6b13168b authored by Stanislav Kinsbursky's avatar Stanislav Kinsbursky Committed by Trond Myklebust

NFS: make nfs_client_list per net ns

This patch splits global list of NFS clients into per-net-ns array of lists.
This looks more strict and clearer.
BTW, this patch also makes "/proc/fs/nfsfs/servers" entry content depends on
/proc mount owner pid namespace. See below for details.

NOTE: few words about how was /proc/fs/nfsfs/ entries content show per network
namespace done. This is a little bit tricky and not the best is could be. But
it's cheap (proper fix for /proc conteinerization is a hard nut to crack).
The idea is simple: take proper network namespace from pid namespace
child reaper nsproxy of /proc/ mount creator.
This actually means, that if there are 2 containers with different net
namespace sharing pid namespace, then read of /proc/fs/nfsfs/ entries will
always return content, taken from net namespace of pid namespace creator task
(and thus second namespace set wil be unvisible).
Signed-off-by: default avatarStanislav Kinsbursky <skinsbursky@parallels.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a602bea3
...@@ -39,6 +39,8 @@ ...@@ -39,6 +39,8 @@
#include <net/ipv6.h> #include <net/ipv6.h>
#include <linux/nfs_xdr.h> #include <linux/nfs_xdr.h>
#include <linux/sunrpc/bc_xprt.h> #include <linux/sunrpc/bc_xprt.h>
#include <linux/nsproxy.h>
#include <linux/pid_namespace.h>
#include <asm/system.h> #include <asm/system.h>
...@@ -49,11 +51,11 @@ ...@@ -49,11 +51,11 @@
#include "internal.h" #include "internal.h"
#include "fscache.h" #include "fscache.h"
#include "pnfs.h" #include "pnfs.h"
#include "netns.h"
#define NFSDBG_FACILITY NFSDBG_CLIENT #define NFSDBG_FACILITY NFSDBG_CLIENT
DEFINE_SPINLOCK(nfs_client_lock); DEFINE_SPINLOCK(nfs_client_lock);
LIST_HEAD(nfs_client_list);
static LIST_HEAD(nfs_volume_list); static LIST_HEAD(nfs_volume_list);
static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq); static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
...@@ -464,8 +466,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat ...@@ -464,8 +466,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
{ {
struct nfs_client *clp; struct nfs_client *clp;
const struct sockaddr *sap = data->addr; const struct sockaddr *sap = data->addr;
struct nfs_net *nn = net_generic(data->net, nfs_net_id);
list_for_each_entry(clp, &nfs_client_list, cl_share_link) { list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; const struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr;
/* Don't match clients that failed to initialise properly */ /* Don't match clients that failed to initialise properly */
if (clp->cl_cons_state < 0) if (clp->cl_cons_state < 0)
...@@ -483,9 +486,6 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat ...@@ -483,9 +486,6 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat
/* Match the full socket address */ /* Match the full socket address */
if (!nfs_sockaddr_cmp(sap, clap)) if (!nfs_sockaddr_cmp(sap, clap))
continue; continue;
/* Match network namespace */
if (clp->net != data->net)
continue;
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
return clp; return clp;
...@@ -506,6 +506,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, ...@@ -506,6 +506,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
{ {
struct nfs_client *clp, *new = NULL; struct nfs_client *clp, *new = NULL;
int error; int error;
struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);
dprintk("--> nfs_get_client(%s,v%u)\n", dprintk("--> nfs_get_client(%s,v%u)\n",
cl_init->hostname ?: "", cl_init->rpc_ops->version); cl_init->hostname ?: "", cl_init->rpc_ops->version);
...@@ -531,7 +532,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, ...@@ -531,7 +532,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,
/* install a new client and return with it unready */ /* install a new client and return with it unready */
install_client: install_client:
clp = new; clp = new;
list_add(&clp->cl_share_link, &nfs_client_list); list_add(&clp->cl_share_link, &nn->nfs_client_list);
spin_unlock(&nfs_client_lock); spin_unlock(&nfs_client_lock);
error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr, error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,
...@@ -1227,9 +1228,10 @@ nfs4_find_client_sessionid(const struct sockaddr *addr, ...@@ -1227,9 +1228,10 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,
struct nfs4_sessionid *sid) struct nfs4_sessionid *sid)
{ {
struct nfs_client *clp; struct nfs_client *clp;
struct nfs_net *nn = net_generic(&init_net, nfs_net_id);
spin_lock(&nfs_client_lock); spin_lock(&nfs_client_lock);
list_for_each_entry(clp, &nfs_client_list, cl_share_link) { list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
if (nfs4_cb_match_client(addr, clp, 1) == false) if (nfs4_cb_match_client(addr, clp, 1) == false)
continue; continue;
...@@ -1757,6 +1759,13 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source, ...@@ -1757,6 +1759,13 @@ struct nfs_server *nfs_clone_server(struct nfs_server *source,
return ERR_PTR(error); return ERR_PTR(error);
} }
void nfs_clients_init(struct net *net)
{
struct nfs_net *nn = net_generic(net, nfs_net_id);
INIT_LIST_HEAD(&nn->nfs_client_list);
}
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static struct proc_dir_entry *proc_fs_nfs; static struct proc_dir_entry *proc_fs_nfs;
...@@ -1810,13 +1819,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) ...@@ -1810,13 +1819,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
{ {
struct seq_file *m; struct seq_file *m;
int ret; int ret;
struct pid_namespace *pid_ns = file->f_dentry->d_sb->s_fs_info;
struct net *net = pid_ns->child_reaper->nsproxy->net_ns;
ret = seq_open(file, &nfs_server_list_ops); ret = seq_open(file, &nfs_server_list_ops);
if (ret < 0) if (ret < 0)
return ret; return ret;
m = file->private_data; m = file->private_data;
m->private = PDE(inode)->data; m->private = net;
return 0; return 0;
} }
...@@ -1826,9 +1837,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file) ...@@ -1826,9 +1837,11 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)
*/ */
static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
{ {
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
/* lock the list against modification */ /* lock the list against modification */
spin_lock(&nfs_client_lock); spin_lock(&nfs_client_lock);
return seq_list_start_head(&nfs_client_list, *_pos); return seq_list_start_head(&nn->nfs_client_list, *_pos);
} }
/* /*
...@@ -1836,7 +1849,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos) ...@@ -1836,7 +1849,9 @@ static void *nfs_server_list_start(struct seq_file *m, loff_t *_pos)
*/ */
static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos) static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)
{ {
return seq_list_next(v, &nfs_client_list, pos); struct nfs_net *nn = net_generic(p->private, nfs_net_id);
return seq_list_next(v, &nn->nfs_client_list, pos);
} }
/* /*
...@@ -1853,9 +1868,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v) ...@@ -1853,9 +1868,10 @@ static void nfs_server_list_stop(struct seq_file *p, void *v)
static int nfs_server_list_show(struct seq_file *m, void *v) static int nfs_server_list_show(struct seq_file *m, void *v)
{ {
struct nfs_client *clp; struct nfs_client *clp;
struct nfs_net *nn = net_generic(m->private, nfs_net_id);
/* display header on line 1 */ /* display header on line 1 */
if (v == &nfs_client_list) { if (v == &nn->nfs_client_list) {
seq_puts(m, "NV SERVER PORT USE HOSTNAME\n"); seq_puts(m, "NV SERVER PORT USE HOSTNAME\n");
return 0; return 0;
} }
......
...@@ -532,13 +532,12 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event, ...@@ -532,13 +532,12 @@ static int rpc_pipefs_event(struct notifier_block *nb, unsigned long event,
void *ptr) void *ptr)
{ {
struct super_block *sb = ptr; struct super_block *sb = ptr;
struct nfs_net *nn = net_generic(sb->s_fs_info, nfs_net_id);
struct nfs_client *clp; struct nfs_client *clp;
int error = 0; int error = 0;
spin_lock(&nfs_client_lock); spin_lock(&nfs_client_lock);
list_for_each_entry(clp, &nfs_client_list, cl_share_link) { list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {
if (clp->net != sb->s_fs_info)
continue;
if (clp->rpc_ops != &nfs_v4_clientops) if (clp->rpc_ops != &nfs_v4_clientops)
continue; continue;
error = __rpc_pipefs_event(clp, event, sb); error = __rpc_pipefs_event(clp, event, sb);
......
...@@ -1558,6 +1558,7 @@ EXPORT_SYMBOL_GPL(nfs_net_id); ...@@ -1558,6 +1558,7 @@ EXPORT_SYMBOL_GPL(nfs_net_id);
static int nfs_net_init(struct net *net) static int nfs_net_init(struct net *net)
{ {
nfs_clients_init(net);
return nfs_dns_resolver_cache_init(net); return nfs_dns_resolver_cache_init(net);
} }
......
...@@ -146,6 +146,7 @@ extern void nfs_umount(const struct nfs_mount_request *info); ...@@ -146,6 +146,7 @@ extern void nfs_umount(const struct nfs_mount_request *info);
/* client.c */ /* client.c */
extern const struct rpc_program nfs_program; extern const struct rpc_program nfs_program;
extern void nfs_clients_init(struct net *net);
extern void nfs_cleanup_cb_ident_idr(void); extern void nfs_cleanup_cb_ident_idr(void);
extern void nfs_put_client(struct nfs_client *); extern void nfs_put_client(struct nfs_client *);
...@@ -183,7 +184,6 @@ static inline void nfs_fs_proc_exit(void) ...@@ -183,7 +184,6 @@ static inline void nfs_fs_proc_exit(void)
#endif #endif
#ifdef CONFIG_NFS_V4 #ifdef CONFIG_NFS_V4
extern spinlock_t nfs_client_lock; extern spinlock_t nfs_client_lock;
extern struct list_head nfs_client_list;
#endif #endif
/* nfs4namespace.c */ /* nfs4namespace.c */
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
struct nfs_net { struct nfs_net {
struct cache_detail *nfs_dns_resolve; struct cache_detail *nfs_dns_resolve;
struct rpc_pipe *bl_device_pipe; struct rpc_pipe *bl_device_pipe;
struct list_head nfs_client_list;
}; };
extern int nfs_net_id; extern int nfs_net_id;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment