diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-01 17:00:56 -0500 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2012-03-02 15:36:38 -0500 |
commit | 2446ab6070861aba2dd9229463ffbc40016a9f33 (patch) | |
tree | 2e366c3236788936b9f4f58c0787ae01c265f4a4 | |
parent | a3ca5651cb5eebe2e56e510bbf5cd60abc301c9f (diff) |
SUNRPC: Use RCU to dereference the rpc_clnt.cl_xprt field
A migration event will replace the rpc_xprt used by an rpc_clnt. To
ensure this can be done safely, all references to cl_xprt must now use
a form of rcu_dereference().
Special care is taken with rpc_peeraddr2str(), which returns a pointer
to memory whose lifetime is the same as the rpc_xprt.
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
[ cel: fix lockdep splats and layering violations ]
[ cel: forward ported to 3.4 ]
[ cel: remove rpc_max_reqs(), add rpc_net_ns() ]
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-rw-r--r-- | fs/nfs/callback_proc.c | 9 | ||||
-rw-r--r-- | fs/nfs/client.c | 16 | ||||
-rw-r--r-- | fs/nfs/nfs4namespace.c | 2 | ||||
-rw-r--r-- | fs/nfs/nfs4proc.c | 13 | ||||
-rw-r--r-- | fs/nfs/nfs4state.c | 25 | ||||
-rw-r--r-- | fs/nfs/super.c | 5 | ||||
-rw-r--r-- | include/linux/sunrpc/clnt.h | 4 | ||||
-rw-r--r-- | include/linux/sunrpc/debug.h | 13 | ||||
-rw-r--r-- | net/sunrpc/auth_gss/auth_gss.c | 4 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 110 | ||||
-rw-r--r-- | net/sunrpc/rpc_pipe.c | 3 | ||||
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 15 | ||||
-rw-r--r-- | net/sunrpc/stats.c | 6 |
13 files changed, 175 insertions, 50 deletions
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c index 0e0865e38065..1bb297243624 100644 --- a/fs/nfs/callback_proc.c +++ b/fs/nfs/callback_proc.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <linux/nfs4.h> | 8 | #include <linux/nfs4.h> |
9 | #include <linux/nfs_fs.h> | 9 | #include <linux/nfs_fs.h> |
10 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
11 | #include <linux/rcupdate.h> | ||
11 | #include "nfs4_fs.h" | 12 | #include "nfs4_fs.h" |
12 | #include "callback.h" | 13 | #include "callback.h" |
13 | #include "delegation.h" | 14 | #include "delegation.h" |
@@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, | |||
33 | res->bitmap[0] = res->bitmap[1] = 0; | 34 | res->bitmap[0] = res->bitmap[1] = 0; |
34 | res->status = htonl(NFS4ERR_BADHANDLE); | 35 | res->status = htonl(NFS4ERR_BADHANDLE); |
35 | 36 | ||
36 | dprintk("NFS: GETATTR callback request from %s\n", | 37 | dprintk_rcu("NFS: GETATTR callback request from %s\n", |
37 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 38 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
38 | 39 | ||
39 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); | 40 | inode = nfs_delegation_find_inode(cps->clp, &args->fh); |
@@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, | |||
73 | if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ | 74 | if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ |
74 | goto out; | 75 | goto out; |
75 | 76 | ||
76 | dprintk("NFS: RECALL callback request from %s\n", | 77 | dprintk_rcu("NFS: RECALL callback request from %s\n", |
77 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 78 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
78 | 79 | ||
79 | res = htonl(NFS4ERR_BADHANDLE); | 80 | res = htonl(NFS4ERR_BADHANDLE); |
@@ -533,7 +534,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy, | |||
533 | if (!cps->clp) /* set in cb_sequence */ | 534 | if (!cps->clp) /* set in cb_sequence */ |
534 | goto out; | 535 | goto out; |
535 | 536 | ||
536 | dprintk("NFS: RECALL_ANY callback request from %s\n", | 537 | dprintk_rcu("NFS: RECALL_ANY callback request from %s\n", |
537 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); | 538 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
538 | 539 | ||
539 | status = cpu_to_be32(NFS4ERR_INVAL); | 540 | status = cpu_to_be32(NFS4ERR_INVAL); |
@@ -568,7 +569,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, | |||
568 | if (!cps->clp) /* set in cb_sequence */ | 569 | if (!cps->clp) /* set in cb_sequence */ |
569 | goto out; | 570 | goto out; |
570 | 571 | ||
571 | dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", | 572 | dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", |
572 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), | 573 | rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), |
573 | args->crsa_target_max_slots); | 574 | args->crsa_target_max_slots); |
574 | 575 | ||
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 1506adf4d4ed..d038dc5916e5 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
@@ -1284,16 +1284,18 @@ static int nfs4_init_callback(struct nfs_client *clp) | |||
1284 | int error; | 1284 | int error; |
1285 | 1285 | ||
1286 | if (clp->rpc_ops->version == 4) { | 1286 | if (clp->rpc_ops->version == 4) { |
1287 | struct rpc_xprt *xprt; | ||
1288 | |||
1289 | xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt); | ||
1290 | |||
1287 | if (nfs4_has_session(clp)) { | 1291 | if (nfs4_has_session(clp)) { |
1288 | error = xprt_setup_backchannel( | 1292 | error = xprt_setup_backchannel(xprt, |
1289 | clp->cl_rpcclient->cl_xprt, | ||
1290 | NFS41_BC_MIN_CALLBACKS); | 1293 | NFS41_BC_MIN_CALLBACKS); |
1291 | if (error < 0) | 1294 | if (error < 0) |
1292 | return error; | 1295 | return error; |
1293 | } | 1296 | } |
1294 | 1297 | ||
1295 | error = nfs_callback_up(clp->cl_mvops->minor_version, | 1298 | error = nfs_callback_up(clp->cl_mvops->minor_version, xprt); |
1296 | clp->cl_rpcclient->cl_xprt); | ||
1297 | if (error < 0) { | 1299 | if (error < 0) { |
1298 | dprintk("%s: failed to start callback. Error = %d\n", | 1300 | dprintk("%s: failed to start callback. Error = %d\n", |
1299 | __func__, error); | 1301 | __func__, error); |
@@ -1678,7 +1680,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, | |||
1678 | data->addrlen, | 1680 | data->addrlen, |
1679 | parent_client->cl_ipaddr, | 1681 | parent_client->cl_ipaddr, |
1680 | data->authflavor, | 1682 | data->authflavor, |
1681 | parent_server->client->cl_xprt->prot, | 1683 | rpc_protocol(parent_server->client), |
1682 | parent_server->client->cl_timeout, | 1684 | parent_server->client->cl_timeout, |
1683 | parent_client->cl_mvops->minor_version, | 1685 | parent_client->cl_mvops->minor_version, |
1684 | parent_client->net); | 1686 | parent_client->net); |
@@ -1905,12 +1907,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v) | |||
1905 | if (clp->cl_cons_state != NFS_CS_READY) | 1907 | if (clp->cl_cons_state != NFS_CS_READY) |
1906 | return 0; | 1908 | return 0; |
1907 | 1909 | ||
1910 | rcu_read_lock(); | ||
1908 | seq_printf(m, "v%u %s %s %3d %s\n", | 1911 | seq_printf(m, "v%u %s %s %3d %s\n", |
1909 | clp->rpc_ops->version, | 1912 | clp->rpc_ops->version, |
1910 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 1913 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
1911 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), | 1914 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), |
1912 | atomic_read(&clp->cl_count), | 1915 | atomic_read(&clp->cl_count), |
1913 | clp->cl_hostname); | 1916 | clp->cl_hostname); |
1917 | rcu_read_unlock(); | ||
1914 | 1918 | ||
1915 | return 0; | 1919 | return 0; |
1916 | } | 1920 | } |
@@ -1993,6 +1997,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
1993 | (unsigned long long) server->fsid.major, | 1997 | (unsigned long long) server->fsid.major, |
1994 | (unsigned long long) server->fsid.minor); | 1998 | (unsigned long long) server->fsid.minor); |
1995 | 1999 | ||
2000 | rcu_read_lock(); | ||
1996 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", | 2001 | seq_printf(m, "v%u %s %s %-7s %-17s %s\n", |
1997 | clp->rpc_ops->version, | 2002 | clp->rpc_ops->version, |
1998 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), | 2003 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), |
@@ -2000,6 +2005,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) | |||
2000 | dev, | 2005 | dev, |
2001 | fsid, | 2006 | fsid, |
2002 | nfs_server_fscache_state(server)); | 2007 | nfs_server_fscache_state(server)); |
2008 | rcu_read_unlock(); | ||
2003 | 2009 | ||
2004 | return 0; | 2010 | return 0; |
2005 | } | 2011 | } |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 667ea7406fd3..9c8eca315f43 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
@@ -96,8 +96,8 @@ static int nfs4_validate_fspath(struct dentry *dentry, | |||
96 | static size_t nfs_parse_server_name(char *string, size_t len, | 96 | static size_t nfs_parse_server_name(char *string, size_t len, |
97 | struct sockaddr *sa, size_t salen, struct nfs_server *server) | 97 | struct sockaddr *sa, size_t salen, struct nfs_server *server) |
98 | { | 98 | { |
99 | struct net *net = rpc_net_ns(server->client); | ||
99 | ssize_t ret; | 100 | ssize_t ret; |
100 | struct net *net = server->client->cl_xprt->xprt_net; | ||
101 | 101 | ||
102 | ret = rpc_pton(net, string, len, sa, salen); | 102 | ret = rpc_pton(net, string, len, sa, salen); |
103 | if (ret == 0) { | 103 | if (ret == 0) { |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 6c8e170e2e6b..671510cc14c0 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -3833,6 +3833,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3833 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); | 3833 | *p = htonl((u32)clp->cl_boot_time.tv_nsec); |
3834 | 3834 | ||
3835 | for(;;) { | 3835 | for(;;) { |
3836 | rcu_read_lock(); | ||
3836 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, | 3837 | setclientid.sc_name_len = scnprintf(setclientid.sc_name, |
3837 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", | 3838 | sizeof(setclientid.sc_name), "%s/%s %s %s %u", |
3838 | clp->cl_ipaddr, | 3839 | clp->cl_ipaddr, |
@@ -3849,6 +3850,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
3849 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, | 3850 | setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, |
3850 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", | 3851 | sizeof(setclientid.sc_uaddr), "%s.%u.%u", |
3851 | clp->cl_ipaddr, port >> 8, port & 255); | 3852 | clp->cl_ipaddr, port >> 8, port & 255); |
3853 | rcu_read_unlock(); | ||
3852 | 3854 | ||
3853 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 3855 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); |
3854 | if (status != -NFS4ERR_CLID_INUSE) | 3856 | if (status != -NFS4ERR_CLID_INUSE) |
@@ -5244,11 +5246,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) | |||
5244 | 5246 | ||
5245 | void nfs4_destroy_session(struct nfs4_session *session) | 5247 | void nfs4_destroy_session(struct nfs4_session *session) |
5246 | { | 5248 | { |
5249 | struct rpc_xprt *xprt; | ||
5250 | |||
5247 | nfs4_proc_destroy_session(session); | 5251 | nfs4_proc_destroy_session(session); |
5252 | |||
5253 | rcu_read_lock(); | ||
5254 | xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt); | ||
5255 | rcu_read_unlock(); | ||
5248 | dprintk("%s Destroy backchannel for xprt %p\n", | 5256 | dprintk("%s Destroy backchannel for xprt %p\n", |
5249 | __func__, session->clp->cl_rpcclient->cl_xprt); | 5257 | __func__, xprt); |
5250 | xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, | 5258 | xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS); |
5251 | NFS41_BC_MIN_CALLBACKS); | ||
5252 | nfs4_destroy_slot_tables(session); | 5259 | nfs4_destroy_slot_tables(session); |
5253 | kfree(session); | 5260 | kfree(session); |
5254 | } | 5261 | } |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index c1111a37dc14..bae959e294cd 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
@@ -1037,19 +1037,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp) | |||
1037 | void nfs4_schedule_state_manager(struct nfs_client *clp) | 1037 | void nfs4_schedule_state_manager(struct nfs_client *clp) |
1038 | { | 1038 | { |
1039 | struct task_struct *task; | 1039 | struct task_struct *task; |
1040 | char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1]; | ||
1040 | 1041 | ||
1041 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) | 1042 | if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) |
1042 | return; | 1043 | return; |
1043 | __module_get(THIS_MODULE); | 1044 | __module_get(THIS_MODULE); |
1044 | atomic_inc(&clp->cl_count); | 1045 | atomic_inc(&clp->cl_count); |
1045 | task = kthread_run(nfs4_run_state_manager, clp, "%s-manager", | 1046 | |
1046 | rpc_peeraddr2str(clp->cl_rpcclient, | 1047 | /* The rcu_read_lock() is not strictly necessary, as the state |
1047 | RPC_DISPLAY_ADDR)); | 1048 | * manager is the only thread that ever changes the rpc_xprt |
1048 | if (!IS_ERR(task)) | 1049 | * after it's initialized. At this point, we're single threaded. */ |
1049 | return; | 1050 | rcu_read_lock(); |
1050 | nfs4_clear_state_manager_bit(clp); | 1051 | snprintf(buf, sizeof(buf), "%s-manager", |
1051 | nfs_put_client(clp); | 1052 | rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR)); |
1052 | module_put(THIS_MODULE); | 1053 | rcu_read_unlock(); |
1054 | task = kthread_run(nfs4_run_state_manager, clp, buf); | ||
1055 | if (IS_ERR(task)) { | ||
1056 | printk(KERN_ERR "%s: kthread_run: %ld\n", | ||
1057 | __func__, PTR_ERR(task)); | ||
1058 | nfs4_clear_state_manager_bit(clp); | ||
1059 | nfs_put_client(clp); | ||
1060 | module_put(THIS_MODULE); | ||
1061 | } | ||
1053 | } | 1062 | } |
1054 | 1063 | ||
1055 | /* | 1064 | /* |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f4ccdae6a0cf..7002be11d99f 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
@@ -53,6 +53,7 @@ | |||
53 | #include <linux/magic.h> | 53 | #include <linux/magic.h> |
54 | #include <linux/parser.h> | 54 | #include <linux/parser.h> |
55 | #include <linux/nsproxy.h> | 55 | #include <linux/nsproxy.h> |
56 | #include <linux/rcupdate.h> | ||
56 | 57 | ||
57 | #include <asm/system.h> | 58 | #include <asm/system.h> |
58 | #include <asm/uaccess.h> | 59 | #include <asm/uaccess.h> |
@@ -701,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
701 | else | 702 | else |
702 | seq_puts(m, nfs_infop->nostr); | 703 | seq_puts(m, nfs_infop->nostr); |
703 | } | 704 | } |
705 | rcu_read_lock(); | ||
704 | seq_printf(m, ",proto=%s", | 706 | seq_printf(m, ",proto=%s", |
705 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); | 707 | rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); |
708 | rcu_read_unlock(); | ||
706 | if (version == 4) { | 709 | if (version == 4) { |
707 | if (nfss->port != NFS_PORT) | 710 | if (nfss->port != NFS_PORT) |
708 | seq_printf(m, ",port=%u", nfss->port); | 711 | seq_printf(m, ",port=%u", nfss->port); |
@@ -751,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root) | |||
751 | 754 | ||
752 | nfs_show_mount_options(m, nfss, 0); | 755 | nfs_show_mount_options(m, nfss, 0); |
753 | 756 | ||
757 | rcu_read_lock(); | ||
754 | seq_printf(m, ",addr=%s", | 758 | seq_printf(m, ",addr=%s", |
755 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, | 759 | rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, |
756 | RPC_DISPLAY_ADDR)); | 760 | RPC_DISPLAY_ADDR)); |
761 | rcu_read_unlock(); | ||
757 | 762 | ||
758 | return 0; | 763 | return 0; |
759 | } | 764 | } |
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index a4c62e95c720..e3d12b4a0314 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h | |||
@@ -35,7 +35,7 @@ struct rpc_clnt { | |||
35 | struct list_head cl_clients; /* Global list of clients */ | 35 | struct list_head cl_clients; /* Global list of clients */ |
36 | struct list_head cl_tasks; /* List of tasks */ | 36 | struct list_head cl_tasks; /* List of tasks */ |
37 | spinlock_t cl_lock; /* spinlock */ | 37 | spinlock_t cl_lock; /* spinlock */ |
38 | struct rpc_xprt * cl_xprt; /* transport */ | 38 | struct rpc_xprt __rcu * cl_xprt; /* transport */ |
39 | struct rpc_procinfo * cl_procinfo; /* procedure info */ | 39 | struct rpc_procinfo * cl_procinfo; /* procedure info */ |
40 | u32 cl_prog, /* RPC program number */ | 40 | u32 cl_prog, /* RPC program number */ |
41 | cl_vers, /* RPC version number */ | 41 | cl_vers, /* RPC version number */ |
@@ -156,6 +156,8 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, | |||
156 | int rpc_restart_call_prepare(struct rpc_task *); | 156 | int rpc_restart_call_prepare(struct rpc_task *); |
157 | int rpc_restart_call(struct rpc_task *); | 157 | int rpc_restart_call(struct rpc_task *); |
158 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); | 158 | void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); |
159 | int rpc_protocol(struct rpc_clnt *); | ||
160 | struct net * rpc_net_ns(struct rpc_clnt *); | ||
159 | size_t rpc_max_payload(struct rpc_clnt *); | 161 | size_t rpc_max_payload(struct rpc_clnt *); |
160 | void rpc_force_rebind(struct rpc_clnt *); | 162 | void rpc_force_rebind(struct rpc_clnt *); |
161 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); | 163 | size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); |
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h index b506936f4ce6..6cb2517bcf75 100644 --- a/include/linux/sunrpc/debug.h +++ b/include/linux/sunrpc/debug.h | |||
@@ -50,19 +50,32 @@ extern unsigned int nlm_debug; | |||
50 | #endif | 50 | #endif |
51 | 51 | ||
52 | #define dprintk(args...) dfprintk(FACILITY, ## args) | 52 | #define dprintk(args...) dfprintk(FACILITY, ## args) |
53 | #define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args) | ||
53 | 54 | ||
54 | #undef ifdebug | 55 | #undef ifdebug |
55 | #ifdef RPC_DEBUG | 56 | #ifdef RPC_DEBUG |
56 | # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) | 57 | # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) |
58 | |||
57 | # define dfprintk(fac, args...) \ | 59 | # define dfprintk(fac, args...) \ |
58 | do { \ | 60 | do { \ |
59 | ifdebug(fac) \ | 61 | ifdebug(fac) \ |
60 | printk(KERN_DEFAULT args); \ | 62 | printk(KERN_DEFAULT args); \ |
61 | } while (0) | 63 | } while (0) |
64 | |||
65 | # define dfprintk_rcu(fac, args...) \ | ||
66 | do { \ | ||
67 | ifdebug(fac) { \ | ||
68 | rcu_read_lock(); \ | ||
69 | printk(KERN_DEFAULT args); \ | ||
70 | rcu_read_unlock(); \ | ||
71 | } \ | ||
72 | } while (0) | ||
73 | |||
62 | # define RPC_IFDEBUG(x) x | 74 | # define RPC_IFDEBUG(x) x |
63 | #else | 75 | #else |
64 | # define ifdebug(fac) if (0) | 76 | # define ifdebug(fac) if (0) |
65 | # define dfprintk(fac, args...) do ; while (0) | 77 | # define dfprintk(fac, args...) do ; while (0) |
78 | # define dfprintk_rcu(fac, args...) do ; while (0) | ||
66 | # define RPC_IFDEBUG(x) | 79 | # define RPC_IFDEBUG(x) |
67 | #endif | 80 | #endif |
68 | 81 | ||
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index cb2e56452748..d3ad81f8da5b 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
@@ -799,7 +799,7 @@ err_unlink_pipe_1: | |||
799 | static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, | 799 | static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, |
800 | struct rpc_auth *auth) | 800 | struct rpc_auth *auth) |
801 | { | 801 | { |
802 | struct net *net = clnt->cl_xprt->xprt_net; | 802 | struct net *net = rpc_net_ns(clnt); |
803 | struct super_block *sb; | 803 | struct super_block *sb; |
804 | 804 | ||
805 | sb = rpc_get_sb_net(net); | 805 | sb = rpc_get_sb_net(net); |
@@ -813,7 +813,7 @@ static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, | |||
813 | static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, | 813 | static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, |
814 | struct rpc_auth *auth) | 814 | struct rpc_auth *auth) |
815 | { | 815 | { |
816 | struct net *net = clnt->cl_xprt->xprt_net; | 816 | struct net *net = rpc_net_ns(clnt); |
817 | struct super_block *sb; | 817 | struct super_block *sb; |
818 | int err = 0; | 818 | int err = 0; |
819 | 819 | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 25c3da53fb69..7783fc0e7263 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/in.h> | 31 | #include <linux/in.h> |
32 | #include <linux/in6.h> | 32 | #include <linux/in6.h> |
33 | #include <linux/un.h> | 33 | #include <linux/un.h> |
34 | #include <linux/rcupdate.h> | ||
34 | 35 | ||
35 | #include <linux/sunrpc/clnt.h> | 36 | #include <linux/sunrpc/clnt.h> |
36 | #include <linux/sunrpc/rpc_pipe_fs.h> | 37 | #include <linux/sunrpc/rpc_pipe_fs.h> |
@@ -81,7 +82,8 @@ static int rpc_ping(struct rpc_clnt *clnt); | |||
81 | 82 | ||
82 | static void rpc_register_client(struct rpc_clnt *clnt) | 83 | static void rpc_register_client(struct rpc_clnt *clnt) |
83 | { | 84 | { |
84 | struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); | 85 | struct net *net = rpc_net_ns(clnt); |
86 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
85 | 87 | ||
86 | spin_lock(&sn->rpc_client_lock); | 88 | spin_lock(&sn->rpc_client_lock); |
87 | list_add(&clnt->cl_clients, &sn->all_clients); | 89 | list_add(&clnt->cl_clients, &sn->all_clients); |
@@ -90,7 +92,8 @@ static void rpc_register_client(struct rpc_clnt *clnt) | |||
90 | 92 | ||
91 | static void rpc_unregister_client(struct rpc_clnt *clnt) | 93 | static void rpc_unregister_client(struct rpc_clnt *clnt) |
92 | { | 94 | { |
93 | struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); | 95 | struct net *net = rpc_net_ns(clnt); |
96 | struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); | ||
94 | 97 | ||
95 | spin_lock(&sn->rpc_client_lock); | 98 | spin_lock(&sn->rpc_client_lock); |
96 | list_del(&clnt->cl_clients); | 99 | list_del(&clnt->cl_clients); |
@@ -109,12 +112,13 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | |||
109 | 112 | ||
110 | static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) | 113 | static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) |
111 | { | 114 | { |
115 | struct net *net = rpc_net_ns(clnt); | ||
112 | struct super_block *pipefs_sb; | 116 | struct super_block *pipefs_sb; |
113 | 117 | ||
114 | pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); | 118 | pipefs_sb = rpc_get_sb_net(net); |
115 | if (pipefs_sb) { | 119 | if (pipefs_sb) { |
116 | __rpc_clnt_remove_pipedir(clnt); | 120 | __rpc_clnt_remove_pipedir(clnt); |
117 | rpc_put_sb_net(clnt->cl_xprt->xprt_net); | 121 | rpc_put_sb_net(net); |
118 | } | 122 | } |
119 | } | 123 | } |
120 | 124 | ||
@@ -155,17 +159,18 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, | |||
155 | static int | 159 | static int |
156 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) | 160 | rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) |
157 | { | 161 | { |
162 | struct net *net = rpc_net_ns(clnt); | ||
158 | struct super_block *pipefs_sb; | 163 | struct super_block *pipefs_sb; |
159 | struct dentry *dentry; | 164 | struct dentry *dentry; |
160 | 165 | ||
161 | clnt->cl_dentry = NULL; | 166 | clnt->cl_dentry = NULL; |
162 | if (dir_name == NULL) | 167 | if (dir_name == NULL) |
163 | return 0; | 168 | return 0; |
164 | pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); | 169 | pipefs_sb = rpc_get_sb_net(net); |
165 | if (!pipefs_sb) | 170 | if (!pipefs_sb) |
166 | return 0; | 171 | return 0; |
167 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); | 172 | dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); |
168 | rpc_put_sb_net(clnt->cl_xprt->xprt_net); | 173 | rpc_put_sb_net(net); |
169 | if (IS_ERR(dentry)) | 174 | if (IS_ERR(dentry)) |
170 | return PTR_ERR(dentry); | 175 | return PTR_ERR(dentry); |
171 | clnt->cl_dentry = dentry; | 176 | clnt->cl_dentry = dentry; |
@@ -295,7 +300,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
295 | if (clnt->cl_server == NULL) | 300 | if (clnt->cl_server == NULL) |
296 | goto out_no_server; | 301 | goto out_no_server; |
297 | 302 | ||
298 | clnt->cl_xprt = xprt; | 303 | rcu_assign_pointer(clnt->cl_xprt, xprt); |
299 | clnt->cl_procinfo = version->procs; | 304 | clnt->cl_procinfo = version->procs; |
300 | clnt->cl_maxproc = version->nrprocs; | 305 | clnt->cl_maxproc = version->nrprocs; |
301 | clnt->cl_protname = program->name; | 306 | clnt->cl_protname = program->name; |
@@ -310,7 +315,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru | |||
310 | INIT_LIST_HEAD(&clnt->cl_tasks); | 315 | INIT_LIST_HEAD(&clnt->cl_tasks); |
311 | spin_lock_init(&clnt->cl_lock); | 316 | spin_lock_init(&clnt->cl_lock); |
312 | 317 | ||
313 | if (!xprt_bound(clnt->cl_xprt)) | 318 | if (!xprt_bound(xprt)) |
314 | clnt->cl_autobind = 1; | 319 | clnt->cl_autobind = 1; |
315 | 320 | ||
316 | clnt->cl_timeout = xprt->timeout; | 321 | clnt->cl_timeout = xprt->timeout; |
@@ -477,6 +482,7 @@ struct rpc_clnt * | |||
477 | rpc_clone_client(struct rpc_clnt *clnt) | 482 | rpc_clone_client(struct rpc_clnt *clnt) |
478 | { | 483 | { |
479 | struct rpc_clnt *new; | 484 | struct rpc_clnt *new; |
485 | struct rpc_xprt *xprt; | ||
480 | int err = -ENOMEM; | 486 | int err = -ENOMEM; |
481 | 487 | ||
482 | new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); | 488 | new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); |
@@ -499,18 +505,25 @@ rpc_clone_client(struct rpc_clnt *clnt) | |||
499 | if (new->cl_principal == NULL) | 505 | if (new->cl_principal == NULL) |
500 | goto out_no_principal; | 506 | goto out_no_principal; |
501 | } | 507 | } |
508 | rcu_read_lock(); | ||
509 | xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); | ||
510 | rcu_read_unlock(); | ||
511 | if (xprt == NULL) | ||
512 | goto out_no_transport; | ||
513 | rcu_assign_pointer(new->cl_xprt, xprt); | ||
502 | atomic_set(&new->cl_count, 1); | 514 | atomic_set(&new->cl_count, 1); |
503 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); | 515 | err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); |
504 | if (err != 0) | 516 | if (err != 0) |
505 | goto out_no_path; | 517 | goto out_no_path; |
506 | if (new->cl_auth) | 518 | if (new->cl_auth) |
507 | atomic_inc(&new->cl_auth->au_count); | 519 | atomic_inc(&new->cl_auth->au_count); |
508 | xprt_get(clnt->cl_xprt); | ||
509 | atomic_inc(&clnt->cl_count); | 520 | atomic_inc(&clnt->cl_count); |
510 | rpc_register_client(new); | 521 | rpc_register_client(new); |
511 | rpciod_up(); | 522 | rpciod_up(); |
512 | return new; | 523 | return new; |
513 | out_no_path: | 524 | out_no_path: |
525 | xprt_put(xprt); | ||
526 | out_no_transport: | ||
514 | kfree(new->cl_principal); | 527 | kfree(new->cl_principal); |
515 | out_no_principal: | 528 | out_no_principal: |
516 | rpc_free_iostats(new->cl_metrics); | 529 | rpc_free_iostats(new->cl_metrics); |
@@ -590,7 +603,7 @@ rpc_free_client(struct rpc_clnt *clnt) | |||
590 | rpc_free_iostats(clnt->cl_metrics); | 603 | rpc_free_iostats(clnt->cl_metrics); |
591 | kfree(clnt->cl_principal); | 604 | kfree(clnt->cl_principal); |
592 | clnt->cl_metrics = NULL; | 605 | clnt->cl_metrics = NULL; |
593 | xprt_put(clnt->cl_xprt); | 606 | xprt_put(rcu_dereference_raw(clnt->cl_xprt)); |
594 | rpciod_down(); | 607 | rpciod_down(); |
595 | kfree(clnt); | 608 | kfree(clnt); |
596 | } | 609 | } |
@@ -879,13 +892,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start); | |||
879 | size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) | 892 | size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) |
880 | { | 893 | { |
881 | size_t bytes; | 894 | size_t bytes; |
882 | struct rpc_xprt *xprt = clnt->cl_xprt; | 895 | struct rpc_xprt *xprt; |
896 | |||
897 | rcu_read_lock(); | ||
898 | xprt = rcu_dereference(clnt->cl_xprt); | ||
883 | 899 | ||
884 | bytes = sizeof(xprt->addr); | 900 | bytes = xprt->addrlen; |
885 | if (bytes > bufsize) | 901 | if (bytes > bufsize) |
886 | bytes = bufsize; | 902 | bytes = bufsize; |
887 | memcpy(buf, &clnt->cl_xprt->addr, bytes); | 903 | memcpy(buf, &xprt->addr, bytes); |
888 | return xprt->addrlen; | 904 | rcu_read_unlock(); |
905 | |||
906 | return bytes; | ||
889 | } | 907 | } |
890 | EXPORT_SYMBOL_GPL(rpc_peeraddr); | 908 | EXPORT_SYMBOL_GPL(rpc_peeraddr); |
891 | 909 | ||
@@ -894,11 +912,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); | |||
894 | * @clnt: RPC client structure | 912 | * @clnt: RPC client structure |
895 | * @format: address format | 913 | * @format: address format |
896 | * | 914 | * |
915 | * NB: the lifetime of the memory referenced by the returned pointer is | ||
916 | * the same as the rpc_xprt itself. As long as the caller uses this | ||
917 | * pointer, it must hold the RCU read lock. | ||
897 | */ | 918 | */ |
898 | const char *rpc_peeraddr2str(struct rpc_clnt *clnt, | 919 | const char *rpc_peeraddr2str(struct rpc_clnt *clnt, |
899 | enum rpc_display_format_t format) | 920 | enum rpc_display_format_t format) |
900 | { | 921 | { |
901 | struct rpc_xprt *xprt = clnt->cl_xprt; | 922 | struct rpc_xprt *xprt; |
923 | |||
924 | xprt = rcu_dereference(clnt->cl_xprt); | ||
902 | 925 | ||
903 | if (xprt->address_strings[format] != NULL) | 926 | if (xprt->address_strings[format] != NULL) |
904 | return xprt->address_strings[format]; | 927 | return xprt->address_strings[format]; |
@@ -910,14 +933,51 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr2str); | |||
910 | void | 933 | void |
911 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) | 934 | rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) |
912 | { | 935 | { |
913 | struct rpc_xprt *xprt = clnt->cl_xprt; | 936 | struct rpc_xprt *xprt; |
937 | |||
938 | rcu_read_lock(); | ||
939 | xprt = rcu_dereference(clnt->cl_xprt); | ||
914 | if (xprt->ops->set_buffer_size) | 940 | if (xprt->ops->set_buffer_size) |
915 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); | 941 | xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); |
942 | rcu_read_unlock(); | ||
916 | } | 943 | } |
917 | EXPORT_SYMBOL_GPL(rpc_setbufsize); | 944 | EXPORT_SYMBOL_GPL(rpc_setbufsize); |
918 | 945 | ||
919 | /* | 946 | /** |
920 | * Return size of largest payload RPC client can support, in bytes | 947 | * rpc_protocol - Get transport protocol number for an RPC client |
948 | * @clnt: RPC client to query | ||
949 | * | ||
950 | */ | ||
951 | int rpc_protocol(struct rpc_clnt *clnt) | ||
952 | { | ||
953 | int protocol; | ||
954 | |||
955 | rcu_read_lock(); | ||
956 | protocol = rcu_dereference(clnt->cl_xprt)->prot; | ||
957 | rcu_read_unlock(); | ||
958 | return protocol; | ||
959 | } | ||
960 | EXPORT_SYMBOL_GPL(rpc_protocol); | ||
961 | |||
962 | /** | ||
963 | * rpc_net_ns - Get the network namespace for this RPC client | ||
964 | * @clnt: RPC client to query | ||
965 | * | ||
966 | */ | ||
967 | struct net *rpc_net_ns(struct rpc_clnt *clnt) | ||
968 | { | ||
969 | struct net *ret; | ||
970 | |||
971 | rcu_read_lock(); | ||
972 | ret = rcu_dereference(clnt->cl_xprt)->xprt_net; | ||
973 | rcu_read_unlock(); | ||
974 | return ret; | ||
975 | } | ||
976 | EXPORT_SYMBOL_GPL(rpc_net_ns); | ||
977 | |||
978 | /** | ||
979 | * rpc_max_payload - Get maximum payload size for a transport, in bytes | ||
980 | * @clnt: RPC client to query | ||
921 | * | 981 | * |
922 | * For stream transports, this is one RPC record fragment (see RFC | 982 | * For stream transports, this is one RPC record fragment (see RFC |
923 | * 1831), as we don't support multi-record requests yet. For datagram | 983 | * 1831), as we don't support multi-record requests yet. For datagram |
@@ -926,7 +986,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize); | |||
926 | */ | 986 | */ |
927 | size_t rpc_max_payload(struct rpc_clnt *clnt) | 987 | size_t rpc_max_payload(struct rpc_clnt *clnt) |
928 | { | 988 | { |
929 | return clnt->cl_xprt->max_payload; | 989 | size_t ret; |
990 | |||
991 | rcu_read_lock(); | ||
992 | ret = rcu_dereference(clnt->cl_xprt)->max_payload; | ||
993 | rcu_read_unlock(); | ||
994 | return ret; | ||
930 | } | 995 | } |
931 | EXPORT_SYMBOL_GPL(rpc_max_payload); | 996 | EXPORT_SYMBOL_GPL(rpc_max_payload); |
932 | 997 | ||
@@ -937,8 +1002,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload); | |||
937 | */ | 1002 | */ |
938 | void rpc_force_rebind(struct rpc_clnt *clnt) | 1003 | void rpc_force_rebind(struct rpc_clnt *clnt) |
939 | { | 1004 | { |
940 | if (clnt->cl_autobind) | 1005 | if (clnt->cl_autobind) { |
941 | xprt_clear_bound(clnt->cl_xprt); | 1006 | rcu_read_lock(); |
1007 | xprt_clear_bound(rcu_dereference(clnt->cl_xprt)); | ||
1008 | rcu_read_unlock(); | ||
1009 | } | ||
942 | } | 1010 | } |
943 | EXPORT_SYMBOL_GPL(rpc_force_rebind); | 1011 | EXPORT_SYMBOL_GPL(rpc_force_rebind); |
944 | 1012 | ||
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index ac9ee1590739..3d30943ed6db 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/namei.h> | 16 | #include <linux/namei.h> |
17 | #include <linux/fsnotify.h> | 17 | #include <linux/fsnotify.h> |
18 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
19 | #include <linux/rcupdate.h> | ||
19 | 20 | ||
20 | #include <asm/ioctls.h> | 21 | #include <asm/ioctls.h> |
21 | #include <linux/poll.h> | 22 | #include <linux/poll.h> |
@@ -402,12 +403,14 @@ rpc_show_info(struct seq_file *m, void *v) | |||
402 | { | 403 | { |
403 | struct rpc_clnt *clnt = m->private; | 404 | struct rpc_clnt *clnt = m->private; |
404 | 405 | ||
406 | rcu_read_lock(); | ||
405 | seq_printf(m, "RPC server: %s\n", clnt->cl_server); | 407 | seq_printf(m, "RPC server: %s\n", clnt->cl_server); |
406 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, | 408 | seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, |
407 | clnt->cl_prog, clnt->cl_vers); | 409 | clnt->cl_prog, clnt->cl_vers); |
408 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); | 410 | seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); |
409 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); | 411 | seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); |
410 | seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); | 412 | seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); |
413 | rcu_read_unlock(); | ||
411 | return 0; | 414 | return 0; |
412 | } | 415 | } |
413 | 416 | ||
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index b1f08bd67883..4f8af63798a2 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c | |||
@@ -620,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi | |||
620 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) | 620 | static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) |
621 | { | 621 | { |
622 | struct rpc_clnt *parent = clnt->cl_parent; | 622 | struct rpc_clnt *parent = clnt->cl_parent; |
623 | struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt); | ||
623 | 624 | ||
624 | while (parent != clnt) { | 625 | while (parent != clnt) { |
625 | if (parent->cl_xprt != clnt->cl_xprt) | 626 | if (rcu_dereference(parent->cl_xprt) != xprt) |
626 | break; | 627 | break; |
627 | if (clnt->cl_autobind) | 628 | if (clnt->cl_autobind) |
628 | break; | 629 | break; |
@@ -653,8 +654,12 @@ void rpcb_getport_async(struct rpc_task *task) | |||
653 | size_t salen; | 654 | size_t salen; |
654 | int status; | 655 | int status; |
655 | 656 | ||
656 | clnt = rpcb_find_transport_owner(task->tk_client); | 657 | rcu_read_lock(); |
657 | xprt = clnt->cl_xprt; | 658 | do { |
659 | clnt = rpcb_find_transport_owner(task->tk_client); | ||
660 | xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); | ||
661 | } while (xprt == NULL); | ||
662 | rcu_read_unlock(); | ||
658 | 663 | ||
659 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", | 664 | dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", |
660 | task->tk_pid, __func__, | 665 | task->tk_pid, __func__, |
@@ -667,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
667 | if (xprt_test_and_set_binding(xprt)) { | 672 | if (xprt_test_and_set_binding(xprt)) { |
668 | dprintk("RPC: %5u %s: waiting for another binder\n", | 673 | dprintk("RPC: %5u %s: waiting for another binder\n", |
669 | task->tk_pid, __func__); | 674 | task->tk_pid, __func__); |
675 | xprt_put(xprt); | ||
670 | return; | 676 | return; |
671 | } | 677 | } |
672 | 678 | ||
@@ -734,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task) | |||
734 | switch (bind_version) { | 740 | switch (bind_version) { |
735 | case RPCBVERS_4: | 741 | case RPCBVERS_4: |
736 | case RPCBVERS_3: | 742 | case RPCBVERS_3: |
737 | map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); | 743 | map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID]; |
738 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); | 744 | map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); |
739 | map->r_owner = ""; | 745 | map->r_owner = ""; |
740 | break; | 746 | break; |
@@ -763,6 +769,7 @@ bailout_release_client: | |||
763 | bailout_nofree: | 769 | bailout_nofree: |
764 | rpcb_wake_rpcbind_waiters(xprt, status); | 770 | rpcb_wake_rpcbind_waiters(xprt, status); |
765 | task->tk_status = status; | 771 | task->tk_status = status; |
772 | xprt_put(xprt); | ||
766 | } | 773 | } |
767 | EXPORT_SYMBOL_GPL(rpcb_getport_async); | 774 | EXPORT_SYMBOL_GPL(rpcb_getport_async); |
768 | 775 | ||
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c index 1eb3304bc105..bc2068ee795b 100644 --- a/net/sunrpc/stats.c +++ b/net/sunrpc/stats.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/sunrpc/clnt.h> | 22 | #include <linux/sunrpc/clnt.h> |
23 | #include <linux/sunrpc/svcsock.h> | 23 | #include <linux/sunrpc/svcsock.h> |
24 | #include <linux/sunrpc/metrics.h> | 24 | #include <linux/sunrpc/metrics.h> |
25 | #include <linux/rcupdate.h> | ||
25 | 26 | ||
26 | #include "netns.h" | 27 | #include "netns.h" |
27 | 28 | ||
@@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op, | |||
179 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | 180 | void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) |
180 | { | 181 | { |
181 | struct rpc_iostats *stats = clnt->cl_metrics; | 182 | struct rpc_iostats *stats = clnt->cl_metrics; |
182 | struct rpc_xprt *xprt = clnt->cl_xprt; | 183 | struct rpc_xprt *xprt; |
183 | unsigned int op, maxproc = clnt->cl_maxproc; | 184 | unsigned int op, maxproc = clnt->cl_maxproc; |
184 | 185 | ||
185 | if (!stats) | 186 | if (!stats) |
@@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) | |||
189 | seq_printf(seq, "p/v: %u/%u (%s)\n", | 190 | seq_printf(seq, "p/v: %u/%u (%s)\n", |
190 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); | 191 | clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); |
191 | 192 | ||
193 | rcu_read_lock(); | ||
194 | xprt = rcu_dereference(clnt->cl_xprt); | ||
192 | if (xprt) | 195 | if (xprt) |
193 | xprt->ops->print_stats(xprt, seq); | 196 | xprt->ops->print_stats(xprt, seq); |
197 | rcu_read_unlock(); | ||
194 | 198 | ||
195 | seq_printf(seq, "\tper-op statistics\n"); | 199 | seq_printf(seq, "\tper-op statistics\n"); |
196 | for (op = 0; op < maxproc; op++) { | 200 | for (op = 0; op < maxproc; op++) { |