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 /net | |
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>
Diffstat (limited to 'net')
-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 |
5 files changed, 110 insertions, 28 deletions
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++) { |