diff options
Diffstat (limited to 'fs/nfs/client.c')
| -rw-r--r-- | fs/nfs/client.c | 247 | 
1 files changed, 153 insertions, 94 deletions
| diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 31778f74357d..4a108a0a2a60 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -36,9 +36,12 @@  #include <linux/inet.h>  #include <linux/in6.h>  #include <linux/slab.h> +#include <linux/idr.h>  #include <net/ipv6.h>  #include <linux/nfs_xdr.h>  #include <linux/sunrpc/bc_xprt.h> +#include <linux/nsproxy.h> +#include <linux/pid_namespace.h>  #include <asm/system.h> @@ -49,15 +52,12 @@  #include "internal.h"  #include "fscache.h"  #include "pnfs.h" +#include "netns.h"  #define NFSDBG_FACILITY		NFSDBG_CLIENT -static DEFINE_SPINLOCK(nfs_client_lock); -static LIST_HEAD(nfs_client_list); -static LIST_HEAD(nfs_volume_list);  static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);  #ifdef CONFIG_NFS_V4 -static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */  /*   * Get a unique NFSv4.0 callback identifier which will be used @@ -66,15 +66,16 @@ static DEFINE_IDR(cb_ident_idr); /* Protected by nfs_client_lock */  static int nfs_get_cb_ident_idr(struct nfs_client *clp, int minorversion)  {  	int ret = 0; +	struct nfs_net *nn = net_generic(clp->net, nfs_net_id);  	if (clp->rpc_ops->version != 4 || minorversion != 0)  		return ret;  retry: -	if (!idr_pre_get(&cb_ident_idr, GFP_KERNEL)) +	if (!idr_pre_get(&nn->cb_ident_idr, GFP_KERNEL))  		return -ENOMEM; -	spin_lock(&nfs_client_lock); -	ret = idr_get_new(&cb_ident_idr, clp, &clp->cl_cb_ident); -	spin_unlock(&nfs_client_lock); +	spin_lock(&nn->nfs_client_lock); +	ret = idr_get_new(&nn->cb_ident_idr, clp, &clp->cl_cb_ident); +	spin_unlock(&nn->nfs_client_lock);  	if (ret == -EAGAIN)  		goto retry;  	return ret; @@ -89,7 +90,7 @@ static bool nfs4_disable_idmapping = true;  /*   * RPC cruft for NFS   */ -static struct rpc_version *nfs_version[5] = { +static const struct rpc_version *nfs_version[5] = {  	[2]			= &nfs_version2,  #ifdef CONFIG_NFS_V3  	[3]			= &nfs_version3, @@ -99,7 +100,7 @@ static struct rpc_version *nfs_version[5] = {  #endif  }; -struct rpc_program nfs_program = { +const struct rpc_program nfs_program = {  	.name			= "nfs",  	.number			= NFS_PROGRAM,  	.nrvers			= ARRAY_SIZE(nfs_version), @@ -115,11 +116,11 @@ struct rpc_stat nfs_rpcstat = {  #ifdef CONFIG_NFS_V3_ACL  static struct rpc_stat		nfsacl_rpcstat = { &nfsacl_program }; -static struct rpc_version *	nfsacl_version[] = { +static const struct rpc_version *nfsacl_version[] = {  	[3]			= &nfsacl_version3,  }; -struct rpc_program		nfsacl_program = { +const struct rpc_program nfsacl_program = {  	.name			= "nfsacl",  	.number			= NFS_ACL_PROGRAM,  	.nrvers			= ARRAY_SIZE(nfsacl_version), @@ -135,6 +136,7 @@ struct nfs_client_initdata {  	const struct nfs_rpc_ops *rpc_ops;  	int proto;  	u32 minorversion; +	struct net *net;  };  /* @@ -171,6 +173,7 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_  	clp->cl_rpcclient = ERR_PTR(-EINVAL);  	clp->cl_proto = cl_init->proto; +	clp->net = get_net(cl_init->net);  #ifdef CONFIG_NFS_V4  	err = nfs_get_cb_ident_idr(clp, cl_init->minorversion); @@ -202,8 +205,11 @@ error_0:  #ifdef CONFIG_NFS_V4_1  static void nfs4_shutdown_session(struct nfs_client *clp)  { -	if (nfs4_has_session(clp)) +	if (nfs4_has_session(clp)) { +		nfs4_deviceid_purge_client(clp);  		nfs4_destroy_session(clp->cl_session); +	} +  }  #else /* CONFIG_NFS_V4_1 */  static void nfs4_shutdown_session(struct nfs_client *clp) @@ -233,16 +239,20 @@ static void nfs4_shutdown_client(struct nfs_client *clp)  }  /* idr_remove_all is not needed as all id's are removed by nfs_put_client */ -void nfs_cleanup_cb_ident_idr(void) +void nfs_cleanup_cb_ident_idr(struct net *net)  { -	idr_destroy(&cb_ident_idr); +	struct nfs_net *nn = net_generic(net, nfs_net_id); + +	idr_destroy(&nn->cb_ident_idr);  }  /* nfs_client_lock held */  static void nfs_cb_idr_remove_locked(struct nfs_client *clp)  { +	struct nfs_net *nn = net_generic(clp->net, nfs_net_id); +  	if (clp->cl_cb_ident) -		idr_remove(&cb_ident_idr, clp->cl_cb_ident); +		idr_remove(&nn->cb_ident_idr, clp->cl_cb_ident);  }  static void pnfs_init_server(struct nfs_server *server) @@ -260,7 +270,7 @@ static void nfs4_shutdown_client(struct nfs_client *clp)  {  } -void nfs_cleanup_cb_ident_idr(void) +void nfs_cleanup_cb_ident_idr(struct net *net)  {  } @@ -292,10 +302,10 @@ static void nfs_free_client(struct nfs_client *clp)  	if (clp->cl_machine_cred != NULL)  		put_rpccred(clp->cl_machine_cred); -	nfs4_deviceid_purge_client(clp); - +	put_net(clp->net);  	kfree(clp->cl_hostname);  	kfree(clp->server_scope); +	kfree(clp->impl_id);  	kfree(clp);  	dprintk("<-- nfs_free_client()\n"); @@ -306,15 +316,18 @@ static void nfs_free_client(struct nfs_client *clp)   */  void nfs_put_client(struct nfs_client *clp)  { +	struct nfs_net *nn; +  	if (!clp)  		return;  	dprintk("--> nfs_put_client({%d})\n", atomic_read(&clp->cl_count)); +	nn = net_generic(clp->net, nfs_net_id); -	if (atomic_dec_and_lock(&clp->cl_count, &nfs_client_lock)) { +	if (atomic_dec_and_lock(&clp->cl_count, &nn->nfs_client_lock)) {  		list_del(&clp->cl_share_link);  		nfs_cb_idr_remove_locked(clp); -		spin_unlock(&nfs_client_lock); +		spin_unlock(&nn->nfs_client_lock);  		BUG_ON(!list_empty(&clp->cl_superblocks)); @@ -392,6 +405,7 @@ static int nfs_sockaddr_cmp_ip4(const struct sockaddr *sa1,  		(sin1->sin_port == sin2->sin_port);  } +#if defined(CONFIG_NFS_V4_1)  /*   * Test if two socket addresses represent the same actual socket,   * by comparing (only) relevant fields, excluding the port number. @@ -410,6 +424,7 @@ static int nfs_sockaddr_match_ipaddr(const struct sockaddr *sa1,  	}  	return 0;  } +#endif /* CONFIG_NFS_V4_1 */  /*   * Test if two socket addresses represent the same actual socket, @@ -430,10 +445,10 @@ static int nfs_sockaddr_cmp(const struct sockaddr *sa1,  	return 0;  } +#if defined(CONFIG_NFS_V4_1)  /* Common match routine for v4.0 and v4.1 callback services */ -bool -nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp, -		     u32 minorversion) +static bool nfs4_cb_match_client(const struct sockaddr *addr, +		struct nfs_client *clp, u32 minorversion)  {  	struct sockaddr *clap = (struct sockaddr *)&clp->cl_addr; @@ -453,6 +468,7 @@ nfs4_cb_match_client(const struct sockaddr *addr, struct nfs_client *clp,  	return true;  } +#endif /* CONFIG_NFS_V4_1 */  /*   * Find an nfs_client on the list that matches the initialisation data @@ -462,8 +478,9 @@ static struct nfs_client *nfs_match_client(const struct nfs_client_initdata *dat  {  	struct nfs_client *clp;  	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;  		/* Don't match clients that failed to initialise properly */  		if (clp->cl_cons_state < 0) @@ -501,13 +518,14 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,  {  	struct nfs_client *clp, *new = NULL;  	int error; +	struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id);  	dprintk("--> nfs_get_client(%s,v%u)\n",  		cl_init->hostname ?: "", cl_init->rpc_ops->version);  	/* see if the client already exists */  	do { -		spin_lock(&nfs_client_lock); +		spin_lock(&nn->nfs_client_lock);  		clp = nfs_match_client(cl_init);  		if (clp) @@ -515,7 +533,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,  		if (new)  			goto install_client; -		spin_unlock(&nfs_client_lock); +		spin_unlock(&nn->nfs_client_lock);  		new = nfs_alloc_client(cl_init);  	} while (!IS_ERR(new)); @@ -526,8 +544,8 @@ nfs_get_client(const struct nfs_client_initdata *cl_init,  	/* install a new client and return with it unready */  install_client:  	clp = new; -	list_add(&clp->cl_share_link, &nfs_client_list); -	spin_unlock(&nfs_client_lock); +	list_add(&clp->cl_share_link, &nn->nfs_client_list); +	spin_unlock(&nn->nfs_client_lock);  	error = cl_init->rpc_ops->init_client(clp, timeparms, ip_addr,  					      authflavour, noresvport); @@ -542,7 +560,7 @@ install_client:  	 * - make sure it's ready before returning  	 */  found_client: -	spin_unlock(&nfs_client_lock); +	spin_unlock(&nn->nfs_client_lock);  	if (new)  		nfs_free_client(new); @@ -642,7 +660,7 @@ static int nfs_create_rpc_client(struct nfs_client *clp,  {  	struct rpc_clnt		*clnt = NULL;  	struct rpc_create_args args = { -		.net		= &init_net, +		.net		= clp->net,  		.protocol	= clp->cl_proto,  		.address	= (struct sockaddr *)&clp->cl_addr,  		.addrsize	= clp->cl_addrlen, @@ -696,6 +714,7 @@ static int nfs_start_lockd(struct nfs_server *server)  		.nfs_version	= clp->rpc_ops->version,  		.noresvport	= server->flags & NFS_MOUNT_NORESVPORT ?  					1 : 0, +		.net		= clp->net,  	};  	if (nlm_init.nfs_version > 3) @@ -831,6 +850,7 @@ static int nfs_init_server(struct nfs_server *server,  		.addrlen = data->nfs_server.addrlen,  		.rpc_ops = &nfs_v2_clientops,  		.proto = data->nfs_server.protocol, +		.net = data->net,  	};  	struct rpc_timeout timeparms;  	struct nfs_client *clp; @@ -1029,25 +1049,30 @@ static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_serve  static void nfs_server_insert_lists(struct nfs_server *server)  {  	struct nfs_client *clp = server->nfs_client; +	struct nfs_net *nn = net_generic(clp->net, nfs_net_id); -	spin_lock(&nfs_client_lock); +	spin_lock(&nn->nfs_client_lock);  	list_add_tail_rcu(&server->client_link, &clp->cl_superblocks); -	list_add_tail(&server->master_link, &nfs_volume_list); +	list_add_tail(&server->master_link, &nn->nfs_volume_list);  	clear_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state); -	spin_unlock(&nfs_client_lock); +	spin_unlock(&nn->nfs_client_lock);  }  static void nfs_server_remove_lists(struct nfs_server *server)  {  	struct nfs_client *clp = server->nfs_client; +	struct nfs_net *nn; -	spin_lock(&nfs_client_lock); +	if (clp == NULL) +		return; +	nn = net_generic(clp->net, nfs_net_id); +	spin_lock(&nn->nfs_client_lock);  	list_del_rcu(&server->client_link); -	if (clp && list_empty(&clp->cl_superblocks)) +	if (list_empty(&clp->cl_superblocks))  		set_bit(NFS_CS_STOP_RENEW, &clp->cl_res_state);  	list_del(&server->master_link); -	spin_unlock(&nfs_client_lock); +	spin_unlock(&nn->nfs_client_lock);  	synchronize_rcu();  } @@ -1086,6 +1111,8 @@ static struct nfs_server *nfs_alloc_server(void)  		return NULL;  	} +	ida_init(&server->openowner_id); +	ida_init(&server->lockowner_id);  	pnfs_init_server(server);  	return server; @@ -1111,6 +1138,8 @@ void nfs_free_server(struct nfs_server *server)  	nfs_put_client(server->nfs_client); +	ida_destroy(&server->lockowner_id); +	ida_destroy(&server->openowner_id);  	nfs_free_iostats(server->io_stats);  	bdi_destroy(&server->backing_dev_info);  	kfree(server); @@ -1189,45 +1218,19 @@ error:  /*   * NFSv4.0 callback thread helper   * - * Find a client by IP address, protocol version, and minorversion - * - * Called from the pg_authenticate method. The callback identifier - * is not used as it has not been decoded. - * - * Returns NULL if no such client - */ -struct nfs_client * -nfs4_find_client_no_ident(const struct sockaddr *addr) -{ -	struct nfs_client *clp; - -	spin_lock(&nfs_client_lock); -	list_for_each_entry(clp, &nfs_client_list, cl_share_link) { -		if (nfs4_cb_match_client(addr, clp, 0) == false) -			continue; -		atomic_inc(&clp->cl_count); -		spin_unlock(&nfs_client_lock); -		return clp; -	} -	spin_unlock(&nfs_client_lock); -	return NULL; -} - -/* - * NFSv4.0 callback thread helper - *   * Find a client by callback identifier   */  struct nfs_client * -nfs4_find_client_ident(int cb_ident) +nfs4_find_client_ident(struct net *net, int cb_ident)  {  	struct nfs_client *clp; +	struct nfs_net *nn = net_generic(net, nfs_net_id); -	spin_lock(&nfs_client_lock); -	clp = idr_find(&cb_ident_idr, cb_ident); +	spin_lock(&nn->nfs_client_lock); +	clp = idr_find(&nn->cb_ident_idr, cb_ident);  	if (clp)  		atomic_inc(&clp->cl_count); -	spin_unlock(&nfs_client_lock); +	spin_unlock(&nn->nfs_client_lock);  	return clp;  } @@ -1240,13 +1243,14 @@ nfs4_find_client_ident(int cb_ident)   * Returns NULL if no such client   */  struct nfs_client * -nfs4_find_client_sessionid(const struct sockaddr *addr, +nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,  			   struct nfs4_sessionid *sid)  {  	struct nfs_client *clp; +	struct nfs_net *nn = net_generic(net, nfs_net_id); -	spin_lock(&nfs_client_lock); -	list_for_each_entry(clp, &nfs_client_list, cl_share_link) { +	spin_lock(&nn->nfs_client_lock); +	list_for_each_entry(clp, &nn->nfs_client_list, cl_share_link) {  		if (nfs4_cb_match_client(addr, clp, 1) == false)  			continue; @@ -1259,17 +1263,17 @@ nfs4_find_client_sessionid(const struct sockaddr *addr,  			continue;  		atomic_inc(&clp->cl_count); -		spin_unlock(&nfs_client_lock); +		spin_unlock(&nn->nfs_client_lock);  		return clp;  	} -	spin_unlock(&nfs_client_lock); +	spin_unlock(&nn->nfs_client_lock);  	return NULL;  }  #else /* CONFIG_NFS_V4_1 */  struct nfs_client * -nfs4_find_client_sessionid(const struct sockaddr *addr, +nfs4_find_client_sessionid(struct net *net, const struct sockaddr *addr,  			   struct nfs4_sessionid *sid)  {  	return NULL; @@ -1284,16 +1288,18 @@ static int nfs4_init_callback(struct nfs_client *clp)  	int error;  	if (clp->rpc_ops->version == 4) { +		struct rpc_xprt *xprt; + +		xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); +  		if (nfs4_has_session(clp)) { -			error = xprt_setup_backchannel( -						clp->cl_rpcclient->cl_xprt, +			error = xprt_setup_backchannel(xprt,  						NFS41_BC_MIN_CALLBACKS);  			if (error < 0)  				return error;  		} -		error = nfs_callback_up(clp->cl_mvops->minor_version, -					clp->cl_rpcclient->cl_xprt); +		error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);  		if (error < 0) {  			dprintk("%s: failed to start callback. Error = %d\n",  				__func__, error); @@ -1344,6 +1350,7 @@ int nfs4_init_client(struct nfs_client *clp,  		     rpc_authflavor_t authflavour,  		     int noresvport)  { +	char buf[INET6_ADDRSTRLEN + 1];  	int error;  	if (clp->cl_cons_state == NFS_CS_READY) { @@ -1359,6 +1366,20 @@ int nfs4_init_client(struct nfs_client *clp,  				      1, noresvport);  	if (error < 0)  		goto error; + +	/* If no clientaddr= option was specified, find a usable cb address */ +	if (ip_addr == NULL) { +		struct sockaddr_storage cb_addr; +		struct sockaddr *sap = (struct sockaddr *)&cb_addr; + +		error = rpc_localaddr(clp->cl_rpcclient, sap, sizeof(cb_addr)); +		if (error < 0) +			goto error; +		error = rpc_ntop(sap, buf, sizeof(buf)); +		if (error < 0) +			goto error; +		ip_addr = (const char *)buf; +	}  	strlcpy(clp->cl_ipaddr, ip_addr, sizeof(clp->cl_ipaddr));  	error = nfs_idmap_new(clp); @@ -1393,7 +1414,7 @@ static int nfs4_set_client(struct nfs_server *server,  		const char *ip_addr,  		rpc_authflavor_t authflavour,  		int proto, const struct rpc_timeout *timeparms, -		u32 minorversion) +		u32 minorversion, struct net *net)  {  	struct nfs_client_initdata cl_init = {  		.hostname = hostname, @@ -1402,6 +1423,7 @@ static int nfs4_set_client(struct nfs_server *server,  		.rpc_ops = &nfs_v4_clientops,  		.proto = proto,  		.minorversion = minorversion, +		.net = net,  	};  	struct nfs_client *clp;  	int error; @@ -1453,6 +1475,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp,  		.rpc_ops = &nfs_v4_clientops,  		.proto = ds_proto,  		.minorversion = mds_clp->cl_minorversion, +		.net = mds_clp->net,  	};  	struct rpc_timeout ds_timeout = {  		.to_initval = 15 * HZ, @@ -1580,7 +1603,8 @@ static int nfs4_init_server(struct nfs_server *server,  			data->auth_flavors[0],  			data->nfs_server.protocol,  			&timeparms, -			data->minorversion); +			data->minorversion, +			data->net);  	if (error < 0)  		goto error; @@ -1675,9 +1699,10 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,  				data->addrlen,  				parent_client->cl_ipaddr,  				data->authflavor, -				parent_server->client->cl_xprt->prot, +				rpc_protocol(parent_server->client),  				parent_server->client->cl_timeout, -				parent_client->cl_mvops->minor_version); +				parent_client->cl_mvops->minor_version, +				parent_client->net);  	if (error < 0)  		goto error; @@ -1770,6 +1795,18 @@ out_free_server:  	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); +	INIT_LIST_HEAD(&nn->nfs_volume_list); +#ifdef CONFIG_NFS_V4 +	idr_init(&nn->cb_ident_idr); +#endif +	spin_lock_init(&nn->nfs_client_lock); +} +  #ifdef CONFIG_PROC_FS  static struct proc_dir_entry *proc_fs_nfs; @@ -1823,13 +1860,15 @@ static int nfs_server_list_open(struct inode *inode, struct file *file)  {  	struct seq_file *m;  	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);  	if (ret < 0)  		return ret;  	m = file->private_data; -	m->private = PDE(inode)->data; +	m->private = net;  	return 0;  } @@ -1839,9 +1878,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)  { +	struct nfs_net *nn = net_generic(m->private, nfs_net_id); +  	/* lock the list against modification */ -	spin_lock(&nfs_client_lock); -	return seq_list_start_head(&nfs_client_list, *_pos); +	spin_lock(&nn->nfs_client_lock); +	return seq_list_start_head(&nn->nfs_client_list, *_pos);  }  /* @@ -1849,7 +1890,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)  { -	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);  }  /* @@ -1857,7 +1900,9 @@ static void *nfs_server_list_next(struct seq_file *p, void *v, loff_t *pos)   */  static void nfs_server_list_stop(struct seq_file *p, void *v)  { -	spin_unlock(&nfs_client_lock); +	struct nfs_net *nn = net_generic(p->private, nfs_net_id); + +	spin_unlock(&nn->nfs_client_lock);  }  /* @@ -1866,9 +1911,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)  {  	struct nfs_client *clp; +	struct nfs_net *nn = net_generic(m->private, nfs_net_id);  	/* 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");  		return 0;  	} @@ -1880,12 +1926,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v)  	if (clp->cl_cons_state != NFS_CS_READY)  		return 0; +	rcu_read_lock();  	seq_printf(m, "v%u %s %s %3d %s\n",  		   clp->rpc_ops->version,  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),  		   atomic_read(&clp->cl_count),  		   clp->cl_hostname); +	rcu_read_unlock();  	return 0;  } @@ -1897,13 +1945,15 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)  {  	struct seq_file *m;  	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_volume_list_ops);  	if (ret < 0)  		return ret;  	m = file->private_data; -	m->private = PDE(inode)->data; +	m->private = net;  	return 0;  } @@ -1913,9 +1963,11 @@ static int nfs_volume_list_open(struct inode *inode, struct file *file)   */  static void *nfs_volume_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 */ -	spin_lock(&nfs_client_lock); -	return seq_list_start_head(&nfs_volume_list, *_pos); +	spin_lock(&nn->nfs_client_lock); +	return seq_list_start_head(&nn->nfs_volume_list, *_pos);  }  /* @@ -1923,7 +1975,9 @@ static void *nfs_volume_list_start(struct seq_file *m, loff_t *_pos)   */  static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)  { -	return seq_list_next(v, &nfs_volume_list, pos); +	struct nfs_net *nn = net_generic(p->private, nfs_net_id); + +	return seq_list_next(v, &nn->nfs_volume_list, pos);  }  /* @@ -1931,7 +1985,9 @@ static void *nfs_volume_list_next(struct seq_file *p, void *v, loff_t *pos)   */  static void nfs_volume_list_stop(struct seq_file *p, void *v)  { -	spin_unlock(&nfs_client_lock); +	struct nfs_net *nn = net_generic(p->private, nfs_net_id); + +	spin_unlock(&nn->nfs_client_lock);  }  /* @@ -1942,9 +1998,10 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)  	struct nfs_server *server;  	struct nfs_client *clp;  	char dev[8], fsid[17]; +	struct nfs_net *nn = net_generic(m->private, nfs_net_id);  	/* display header on line 1 */ -	if (v == &nfs_volume_list) { +	if (v == &nn->nfs_volume_list) {  		seq_puts(m, "NV SERVER   PORT DEV     FSID              FSC\n");  		return 0;  	} @@ -1959,6 +2016,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)  		 (unsigned long long) server->fsid.major,  		 (unsigned long long) server->fsid.minor); +	rcu_read_lock();  	seq_printf(m, "v%u %s %s %-7s %-17s %s\n",  		   clp->rpc_ops->version,  		   rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), @@ -1966,6 +2024,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)  		   dev,  		   fsid,  		   nfs_server_fscache_state(server)); +	rcu_read_unlock();  	return 0;  } | 
