Commit 2446ab60 authored by Trond Myklebust's avatar Trond Myklebust

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: default avatarTrond 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: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent a3ca5651
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <linux/nfs4.h> #include <linux/nfs4.h>
#include <linux/nfs_fs.h> #include <linux/nfs_fs.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/rcupdate.h>
#include "nfs4_fs.h" #include "nfs4_fs.h"
#include "callback.h" #include "callback.h"
#include "delegation.h" #include "delegation.h"
...@@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args, ...@@ -33,7 +34,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
res->bitmap[0] = res->bitmap[1] = 0; res->bitmap[0] = res->bitmap[1] = 0;
res->status = htonl(NFS4ERR_BADHANDLE); res->status = htonl(NFS4ERR_BADHANDLE);
dprintk("NFS: GETATTR callback request from %s\n", dprintk_rcu("NFS: GETATTR callback request from %s\n",
rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
inode = nfs_delegation_find_inode(cps->clp, &args->fh); inode = nfs_delegation_find_inode(cps->clp, &args->fh);
...@@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy, ...@@ -73,7 +74,7 @@ __be32 nfs4_callback_recall(struct cb_recallargs *args, void *dummy,
if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */ if (!cps->clp) /* Always set for v4.0. Set in cb_sequence for v4.1 */
goto out; goto out;
dprintk("NFS: RECALL callback request from %s\n", dprintk_rcu("NFS: RECALL callback request from %s\n",
rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
res = htonl(NFS4ERR_BADHANDLE); res = htonl(NFS4ERR_BADHANDLE);
...@@ -533,7 +534,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy, ...@@ -533,7 +534,7 @@ __be32 nfs4_callback_recallany(struct cb_recallanyargs *args, void *dummy,
if (!cps->clp) /* set in cb_sequence */ if (!cps->clp) /* set in cb_sequence */
goto out; goto out;
dprintk("NFS: RECALL_ANY callback request from %s\n", dprintk_rcu("NFS: RECALL_ANY callback request from %s\n",
rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR)); rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR));
status = cpu_to_be32(NFS4ERR_INVAL); status = cpu_to_be32(NFS4ERR_INVAL);
...@@ -568,7 +569,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy, ...@@ -568,7 +569,7 @@ __be32 nfs4_callback_recallslot(struct cb_recallslotargs *args, void *dummy,
if (!cps->clp) /* set in cb_sequence */ if (!cps->clp) /* set in cb_sequence */
goto out; goto out;
dprintk("NFS: CB_RECALL_SLOT request from %s target max slots %d\n", dprintk_rcu("NFS: CB_RECALL_SLOT request from %s target max slots %d\n",
rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR), rpc_peeraddr2str(cps->clp->cl_rpcclient, RPC_DISPLAY_ADDR),
args->crsa_target_max_slots); args->crsa_target_max_slots);
......
...@@ -1284,16 +1284,18 @@ static int nfs4_init_callback(struct nfs_client *clp) ...@@ -1284,16 +1284,18 @@ static int nfs4_init_callback(struct nfs_client *clp)
int error; int error;
if (clp->rpc_ops->version == 4) { if (clp->rpc_ops->version == 4) {
struct rpc_xprt *xprt;
xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
if (nfs4_has_session(clp)) { if (nfs4_has_session(clp)) {
error = xprt_setup_backchannel( error = xprt_setup_backchannel(xprt,
clp->cl_rpcclient->cl_xprt,
NFS41_BC_MIN_CALLBACKS); NFS41_BC_MIN_CALLBACKS);
if (error < 0) if (error < 0)
return error; return error;
} }
error = nfs_callback_up(clp->cl_mvops->minor_version, error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
clp->cl_rpcclient->cl_xprt);
if (error < 0) { if (error < 0) {
dprintk("%s: failed to start callback. Error = %d\n", dprintk("%s: failed to start callback. Error = %d\n",
__func__, error); __func__, error);
...@@ -1678,7 +1680,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data, ...@@ -1678,7 +1680,7 @@ struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
data->addrlen, data->addrlen,
parent_client->cl_ipaddr, parent_client->cl_ipaddr,
data->authflavor, data->authflavor,
parent_server->client->cl_xprt->prot, rpc_protocol(parent_server->client),
parent_server->client->cl_timeout, parent_server->client->cl_timeout,
parent_client->cl_mvops->minor_version, parent_client->cl_mvops->minor_version,
parent_client->net); parent_client->net);
...@@ -1905,12 +1907,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v) ...@@ -1905,12 +1907,14 @@ static int nfs_server_list_show(struct seq_file *m, void *v)
if (clp->cl_cons_state != NFS_CS_READY) if (clp->cl_cons_state != NFS_CS_READY)
return 0; return 0;
rcu_read_lock();
seq_printf(m, "v%u %s %s %3d %s\n", seq_printf(m, "v%u %s %s %3d %s\n",
clp->rpc_ops->version, clp->rpc_ops->version,
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR),
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT), rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_PORT),
atomic_read(&clp->cl_count), atomic_read(&clp->cl_count),
clp->cl_hostname); clp->cl_hostname);
rcu_read_unlock();
return 0; return 0;
} }
...@@ -1993,6 +1997,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v) ...@@ -1993,6 +1997,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
(unsigned long long) server->fsid.major, (unsigned long long) server->fsid.major,
(unsigned long long) server->fsid.minor); (unsigned long long) server->fsid.minor);
rcu_read_lock();
seq_printf(m, "v%u %s %s %-7s %-17s %s\n", seq_printf(m, "v%u %s %s %-7s %-17s %s\n",
clp->rpc_ops->version, clp->rpc_ops->version,
rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_HEX_ADDR), 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,6 +2005,7 @@ static int nfs_volume_list_show(struct seq_file *m, void *v)
dev, dev,
fsid, fsid,
nfs_server_fscache_state(server)); nfs_server_fscache_state(server));
rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -96,8 +96,8 @@ static int nfs4_validate_fspath(struct dentry *dentry, ...@@ -96,8 +96,8 @@ static int nfs4_validate_fspath(struct dentry *dentry,
static size_t nfs_parse_server_name(char *string, size_t len, static size_t nfs_parse_server_name(char *string, size_t len,
struct sockaddr *sa, size_t salen, struct nfs_server *server) struct sockaddr *sa, size_t salen, struct nfs_server *server)
{ {
struct net *net = rpc_net_ns(server->client);
ssize_t ret; ssize_t ret;
struct net *net = server->client->cl_xprt->xprt_net;
ret = rpc_pton(net, string, len, sa, salen); ret = rpc_pton(net, string, len, sa, salen);
if (ret == 0) { if (ret == 0) {
......
...@@ -3833,6 +3833,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, ...@@ -3833,6 +3833,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
*p = htonl((u32)clp->cl_boot_time.tv_nsec); *p = htonl((u32)clp->cl_boot_time.tv_nsec);
for(;;) { for(;;) {
rcu_read_lock();
setclientid.sc_name_len = scnprintf(setclientid.sc_name, setclientid.sc_name_len = scnprintf(setclientid.sc_name,
sizeof(setclientid.sc_name), "%s/%s %s %s %u", sizeof(setclientid.sc_name), "%s/%s %s %s %u",
clp->cl_ipaddr, clp->cl_ipaddr,
...@@ -3849,6 +3850,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, ...@@ -3849,6 +3850,7 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr, setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
sizeof(setclientid.sc_uaddr), "%s.%u.%u", sizeof(setclientid.sc_uaddr), "%s.%u.%u",
clp->cl_ipaddr, port >> 8, port & 255); clp->cl_ipaddr, port >> 8, port & 255);
rcu_read_unlock();
status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
if (status != -NFS4ERR_CLID_INUSE) if (status != -NFS4ERR_CLID_INUSE)
...@@ -5244,11 +5246,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp) ...@@ -5244,11 +5246,16 @@ struct nfs4_session *nfs4_alloc_session(struct nfs_client *clp)
void nfs4_destroy_session(struct nfs4_session *session) void nfs4_destroy_session(struct nfs4_session *session)
{ {
struct rpc_xprt *xprt;
nfs4_proc_destroy_session(session); nfs4_proc_destroy_session(session);
rcu_read_lock();
xprt = rcu_dereference(session->clp->cl_rpcclient->cl_xprt);
rcu_read_unlock();
dprintk("%s Destroy backchannel for xprt %p\n", dprintk("%s Destroy backchannel for xprt %p\n",
__func__, session->clp->cl_rpcclient->cl_xprt); __func__, xprt);
xprt_destroy_backchannel(session->clp->cl_rpcclient->cl_xprt, xprt_destroy_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
NFS41_BC_MIN_CALLBACKS);
nfs4_destroy_slot_tables(session); nfs4_destroy_slot_tables(session);
kfree(session); kfree(session);
} }
......
...@@ -1037,19 +1037,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp) ...@@ -1037,19 +1037,28 @@ static void nfs4_clear_state_manager_bit(struct nfs_client *clp)
void nfs4_schedule_state_manager(struct nfs_client *clp) void nfs4_schedule_state_manager(struct nfs_client *clp)
{ {
struct task_struct *task; struct task_struct *task;
char buf[INET6_ADDRSTRLEN + sizeof("-manager") + 1];
if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0) if (test_and_set_bit(NFS4CLNT_MANAGER_RUNNING, &clp->cl_state) != 0)
return; return;
__module_get(THIS_MODULE); __module_get(THIS_MODULE);
atomic_inc(&clp->cl_count); atomic_inc(&clp->cl_count);
task = kthread_run(nfs4_run_state_manager, clp, "%s-manager",
rpc_peeraddr2str(clp->cl_rpcclient, /* The rcu_read_lock() is not strictly necessary, as the state
RPC_DISPLAY_ADDR)); * manager is the only thread that ever changes the rpc_xprt
if (!IS_ERR(task)) * after it's initialized. At this point, we're single threaded. */
return; rcu_read_lock();
nfs4_clear_state_manager_bit(clp); snprintf(buf, sizeof(buf), "%s-manager",
nfs_put_client(clp); rpc_peeraddr2str(clp->cl_rpcclient, RPC_DISPLAY_ADDR));
module_put(THIS_MODULE); rcu_read_unlock();
task = kthread_run(nfs4_run_state_manager, clp, buf);
if (IS_ERR(task)) {
printk(KERN_ERR "%s: kthread_run: %ld\n",
__func__, PTR_ERR(task));
nfs4_clear_state_manager_bit(clp);
nfs_put_client(clp);
module_put(THIS_MODULE);
}
} }
/* /*
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <linux/magic.h> #include <linux/magic.h>
#include <linux/parser.h> #include <linux/parser.h>
#include <linux/nsproxy.h> #include <linux/nsproxy.h>
#include <linux/rcupdate.h>
#include <asm/system.h> #include <asm/system.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
...@@ -701,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, ...@@ -701,8 +702,10 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss,
else else
seq_puts(m, nfs_infop->nostr); seq_puts(m, nfs_infop->nostr);
} }
rcu_read_lock();
seq_printf(m, ",proto=%s", seq_printf(m, ",proto=%s",
rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID)); rpc_peeraddr2str(nfss->client, RPC_DISPLAY_NETID));
rcu_read_unlock();
if (version == 4) { if (version == 4) {
if (nfss->port != NFS_PORT) if (nfss->port != NFS_PORT)
seq_printf(m, ",port=%u", nfss->port); seq_printf(m, ",port=%u", nfss->port);
...@@ -751,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root) ...@@ -751,9 +754,11 @@ static int nfs_show_options(struct seq_file *m, struct dentry *root)
nfs_show_mount_options(m, nfss, 0); nfs_show_mount_options(m, nfss, 0);
rcu_read_lock();
seq_printf(m, ",addr=%s", seq_printf(m, ",addr=%s",
rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient, rpc_peeraddr2str(nfss->nfs_client->cl_rpcclient,
RPC_DISPLAY_ADDR)); RPC_DISPLAY_ADDR));
rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -35,7 +35,7 @@ struct rpc_clnt { ...@@ -35,7 +35,7 @@ struct rpc_clnt {
struct list_head cl_clients; /* Global list of clients */ struct list_head cl_clients; /* Global list of clients */
struct list_head cl_tasks; /* List of tasks */ struct list_head cl_tasks; /* List of tasks */
spinlock_t cl_lock; /* spinlock */ spinlock_t cl_lock; /* spinlock */
struct rpc_xprt * cl_xprt; /* transport */ struct rpc_xprt __rcu * cl_xprt; /* transport */
struct rpc_procinfo * cl_procinfo; /* procedure info */ struct rpc_procinfo * cl_procinfo; /* procedure info */
u32 cl_prog, /* RPC program number */ u32 cl_prog, /* RPC program number */
cl_vers, /* RPC version number */ cl_vers, /* RPC version number */
...@@ -156,6 +156,8 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, ...@@ -156,6 +156,8 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred,
int rpc_restart_call_prepare(struct rpc_task *); int rpc_restart_call_prepare(struct rpc_task *);
int rpc_restart_call(struct rpc_task *); int rpc_restart_call(struct rpc_task *);
void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int); void rpc_setbufsize(struct rpc_clnt *, unsigned int, unsigned int);
int rpc_protocol(struct rpc_clnt *);
struct net * rpc_net_ns(struct rpc_clnt *);
size_t rpc_max_payload(struct rpc_clnt *); size_t rpc_max_payload(struct rpc_clnt *);
void rpc_force_rebind(struct rpc_clnt *); void rpc_force_rebind(struct rpc_clnt *);
size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t); size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
......
...@@ -50,19 +50,32 @@ extern unsigned int nlm_debug; ...@@ -50,19 +50,32 @@ extern unsigned int nlm_debug;
#endif #endif
#define dprintk(args...) dfprintk(FACILITY, ## args) #define dprintk(args...) dfprintk(FACILITY, ## args)
#define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args)
#undef ifdebug #undef ifdebug
#ifdef RPC_DEBUG #ifdef RPC_DEBUG
# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac)) # define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac))
# define dfprintk(fac, args...) \ # define dfprintk(fac, args...) \
do { \ do { \
ifdebug(fac) \ ifdebug(fac) \
printk(KERN_DEFAULT args); \ printk(KERN_DEFAULT args); \
} while (0) } while (0)
# define dfprintk_rcu(fac, args...) \
do { \
ifdebug(fac) { \
rcu_read_lock(); \
printk(KERN_DEFAULT args); \
rcu_read_unlock(); \
} \
} while (0)
# define RPC_IFDEBUG(x) x # define RPC_IFDEBUG(x) x
#else #else
# define ifdebug(fac) if (0) # define ifdebug(fac) if (0)
# define dfprintk(fac, args...) do ; while (0) # define dfprintk(fac, args...) do ; while (0)
# define dfprintk_rcu(fac, args...) do ; while (0)
# define RPC_IFDEBUG(x) # define RPC_IFDEBUG(x)
#endif #endif
......
...@@ -799,7 +799,7 @@ static int gss_pipes_dentries_create(struct rpc_auth *auth) ...@@ -799,7 +799,7 @@ static int gss_pipes_dentries_create(struct rpc_auth *auth)
static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
struct rpc_auth *auth) struct rpc_auth *auth)
{ {
struct net *net = clnt->cl_xprt->xprt_net; struct net *net = rpc_net_ns(clnt);
struct super_block *sb; struct super_block *sb;
sb = rpc_get_sb_net(net); sb = rpc_get_sb_net(net);
...@@ -813,7 +813,7 @@ static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt, ...@@ -813,7 +813,7 @@ static void gss_pipes_dentries_destroy_net(struct rpc_clnt *clnt,
static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt, static int gss_pipes_dentries_create_net(struct rpc_clnt *clnt,
struct rpc_auth *auth) struct rpc_auth *auth)
{ {
struct net *net = clnt->cl_xprt->xprt_net; struct net *net = rpc_net_ns(clnt);
struct super_block *sb; struct super_block *sb;
int err = 0; int err = 0;
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <linux/in6.h> #include <linux/in6.h>
#include <linux/un.h> #include <linux/un.h>
#include <linux/rcupdate.h>
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/rpc_pipe_fs.h> #include <linux/sunrpc/rpc_pipe_fs.h>
...@@ -81,7 +82,8 @@ static int rpc_ping(struct rpc_clnt *clnt); ...@@ -81,7 +82,8 @@ static int rpc_ping(struct rpc_clnt *clnt);
static void rpc_register_client(struct rpc_clnt *clnt) static void rpc_register_client(struct rpc_clnt *clnt)
{ {
struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); struct net *net = rpc_net_ns(clnt);
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
spin_lock(&sn->rpc_client_lock); spin_lock(&sn->rpc_client_lock);
list_add(&clnt->cl_clients, &sn->all_clients); list_add(&clnt->cl_clients, &sn->all_clients);
...@@ -90,7 +92,8 @@ static void rpc_register_client(struct rpc_clnt *clnt) ...@@ -90,7 +92,8 @@ static void rpc_register_client(struct rpc_clnt *clnt)
static void rpc_unregister_client(struct rpc_clnt *clnt) static void rpc_unregister_client(struct rpc_clnt *clnt)
{ {
struct sunrpc_net *sn = net_generic(clnt->cl_xprt->xprt_net, sunrpc_net_id); struct net *net = rpc_net_ns(clnt);
struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
spin_lock(&sn->rpc_client_lock); spin_lock(&sn->rpc_client_lock);
list_del(&clnt->cl_clients); list_del(&clnt->cl_clients);
...@@ -109,12 +112,13 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) ...@@ -109,12 +112,13 @@ static void __rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt) static void rpc_clnt_remove_pipedir(struct rpc_clnt *clnt)
{ {
struct net *net = rpc_net_ns(clnt);
struct super_block *pipefs_sb; struct super_block *pipefs_sb;
pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); pipefs_sb = rpc_get_sb_net(net);
if (pipefs_sb) { if (pipefs_sb) {
__rpc_clnt_remove_pipedir(clnt); __rpc_clnt_remove_pipedir(clnt);
rpc_put_sb_net(clnt->cl_xprt->xprt_net); rpc_put_sb_net(net);
} }
} }
...@@ -155,17 +159,18 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb, ...@@ -155,17 +159,18 @@ static struct dentry *rpc_setup_pipedir_sb(struct super_block *sb,
static int static int
rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name) rpc_setup_pipedir(struct rpc_clnt *clnt, const char *dir_name)
{ {
struct net *net = rpc_net_ns(clnt);
struct super_block *pipefs_sb; struct super_block *pipefs_sb;
struct dentry *dentry; struct dentry *dentry;
clnt->cl_dentry = NULL; clnt->cl_dentry = NULL;
if (dir_name == NULL) if (dir_name == NULL)
return 0; return 0;
pipefs_sb = rpc_get_sb_net(clnt->cl_xprt->xprt_net); pipefs_sb = rpc_get_sb_net(net);
if (!pipefs_sb) if (!pipefs_sb)
return 0; return 0;
dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name); dentry = rpc_setup_pipedir_sb(pipefs_sb, clnt, dir_name);
rpc_put_sb_net(clnt->cl_xprt->xprt_net); rpc_put_sb_net(net);
if (IS_ERR(dentry)) if (IS_ERR(dentry))
return PTR_ERR(dentry); return PTR_ERR(dentry);
clnt->cl_dentry = dentry; clnt->cl_dentry = dentry;
...@@ -295,7 +300,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru ...@@ -295,7 +300,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
if (clnt->cl_server == NULL) if (clnt->cl_server == NULL)
goto out_no_server; goto out_no_server;
clnt->cl_xprt = xprt; rcu_assign_pointer(clnt->cl_xprt, xprt);
clnt->cl_procinfo = version->procs; clnt->cl_procinfo = version->procs;
clnt->cl_maxproc = version->nrprocs; clnt->cl_maxproc = version->nrprocs;
clnt->cl_protname = program->name; clnt->cl_protname = program->name;
...@@ -310,7 +315,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru ...@@ -310,7 +315,7 @@ static struct rpc_clnt * rpc_new_client(const struct rpc_create_args *args, stru
INIT_LIST_HEAD(&clnt->cl_tasks); INIT_LIST_HEAD(&clnt->cl_tasks);
spin_lock_init(&clnt->cl_lock); spin_lock_init(&clnt->cl_lock);
if (!xprt_bound(clnt->cl_xprt)) if (!xprt_bound(xprt))
clnt->cl_autobind = 1; clnt->cl_autobind = 1;
clnt->cl_timeout = xprt->timeout; clnt->cl_timeout = xprt->timeout;
...@@ -477,6 +482,7 @@ struct rpc_clnt * ...@@ -477,6 +482,7 @@ struct rpc_clnt *
rpc_clone_client(struct rpc_clnt *clnt) rpc_clone_client(struct rpc_clnt *clnt)
{ {
struct rpc_clnt *new; struct rpc_clnt *new;
struct rpc_xprt *xprt;
int err = -ENOMEM; int err = -ENOMEM;
new = kmemdup(clnt, sizeof(*new), GFP_KERNEL); new = kmemdup(clnt, sizeof(*new), GFP_KERNEL);
...@@ -499,18 +505,25 @@ rpc_clone_client(struct rpc_clnt *clnt) ...@@ -499,18 +505,25 @@ rpc_clone_client(struct rpc_clnt *clnt)
if (new->cl_principal == NULL) if (new->cl_principal == NULL)
goto out_no_principal; goto out_no_principal;
} }
rcu_read_lock();
xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
rcu_read_unlock();
if (xprt == NULL)
goto out_no_transport;
rcu_assign_pointer(new->cl_xprt, xprt);
atomic_set(&new->cl_count, 1); atomic_set(&new->cl_count, 1);
err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name); err = rpc_setup_pipedir(new, clnt->cl_program->pipe_dir_name);
if (err != 0) if (err != 0)
goto out_no_path; goto out_no_path;
if (new->cl_auth) if (new->cl_auth)
atomic_inc(&new->cl_auth->au_count); atomic_inc(&new->cl_auth->au_count);
xprt_get(clnt->cl_xprt);
atomic_inc(&clnt->cl_count); atomic_inc(&clnt->cl_count);
rpc_register_client(new); rpc_register_client(new);
rpciod_up(); rpciod_up();
return new; return new;
out_no_path: out_no_path:
xprt_put(xprt);
out_no_transport:
kfree(new->cl_principal); kfree(new->cl_principal);
out_no_principal: out_no_principal:
rpc_free_iostats(new->cl_metrics); rpc_free_iostats(new->cl_metrics);
...@@ -590,7 +603,7 @@ rpc_free_client(struct rpc_clnt *clnt) ...@@ -590,7 +603,7 @@ rpc_free_client(struct rpc_clnt *clnt)
rpc_free_iostats(clnt->cl_metrics); rpc_free_iostats(clnt->cl_metrics);
kfree(clnt->cl_principal); kfree(clnt->cl_principal);
clnt->cl_metrics = NULL; clnt->cl_metrics = NULL;
xprt_put(clnt->cl_xprt); xprt_put(rcu_dereference_raw(clnt->cl_xprt));
rpciod_down(); rpciod_down();
kfree(clnt); kfree(clnt);
} }
...@@ -879,13 +892,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start); ...@@ -879,13 +892,18 @@ EXPORT_SYMBOL_GPL(rpc_call_start);
size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize) size_t rpc_peeraddr(struct rpc_clnt *clnt, struct sockaddr *buf, size_t bufsize)
{ {
size_t bytes; size_t bytes;
struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_xprt *xprt;
rcu_read_lock();
xprt = rcu_dereference(clnt->cl_xprt);
bytes = sizeof(xprt->addr); bytes = xprt->addrlen;
if (bytes > bufsize) if (bytes > bufsize)
bytes = bufsize; bytes = bufsize;
memcpy(buf, &clnt->cl_xprt->addr, bytes); memcpy(buf, &xprt->addr, bytes);
return xprt->addrlen; rcu_read_unlock();
return bytes;
} }
EXPORT_SYMBOL_GPL(rpc_peeraddr); EXPORT_SYMBOL_GPL(rpc_peeraddr);
...@@ -894,11 +912,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr); ...@@ -894,11 +912,16 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr);
* @clnt: RPC client structure * @clnt: RPC client structure
* @format: address format * @format: address format
* *
* NB: the lifetime of the memory referenced by the returned pointer is
* the same as the rpc_xprt itself. As long as the caller uses this
* pointer, it must hold the RCU read lock.
*/ */
const char *rpc_peeraddr2str(struct rpc_clnt *clnt, const char *rpc_peeraddr2str(struct rpc_clnt *clnt,
enum rpc_display_format_t format) enum rpc_display_format_t format)
{ {
struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_xprt *xprt;
xprt = rcu_dereference(clnt->cl_xprt);
if (xprt->address_strings[format] != NULL) if (xprt->address_strings[format] != NULL)
return xprt->address_strings[format]; return xprt->address_strings[format];
...@@ -910,14 +933,51 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr2str); ...@@ -910,14 +933,51 @@ EXPORT_SYMBOL_GPL(rpc_peeraddr2str);
void void
rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize) rpc_setbufsize(struct rpc_clnt *clnt, unsigned int sndsize, unsigned int rcvsize)
{ {
struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_xprt *xprt;
rcu_read_lock();
xprt = rcu_dereference(clnt->cl_xprt);
if (xprt->ops->set_buffer_size) if (xprt->ops->set_buffer_size)
xprt->ops->set_buffer_size(xprt, sndsize, rcvsize); xprt->ops->set_buffer_size(xprt, sndsize, rcvsize);
rcu_read_unlock();
} }
EXPORT_SYMBOL_GPL(rpc_setbufsize); EXPORT_SYMBOL_GPL(rpc_setbufsize);
/* /**
* Return size of largest payload RPC client can support, in bytes * rpc_protocol - Get transport protocol number for an RPC client
* @clnt: RPC client to query
*
*/
int rpc_protocol(struct rpc_clnt *clnt)
{
int protocol;
rcu_read_lock();
protocol = rcu_dereference(clnt->cl_xprt)->prot;
rcu_read_unlock();
return protocol;
}
EXPORT_SYMBOL_GPL(rpc_protocol);
/**
* rpc_net_ns - Get the network namespace for this RPC client
* @clnt: RPC client to query
*
*/
struct net *rpc_net_ns(struct rpc_clnt *clnt)
{
struct net *ret;
rcu_read_lock();
ret = rcu_dereference(clnt->cl_xprt)->xprt_net;
rcu_read_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(rpc_net_ns);
/**
* rpc_max_payload - Get maximum payload size for a transport, in bytes
* @clnt: RPC client to query
* *
* For stream transports, this is one RPC record fragment (see RFC * For stream transports, this is one RPC record fragment (see RFC
* 1831), as we don't support multi-record requests yet. For datagram * 1831), as we don't support multi-record requests yet. For datagram
...@@ -926,7 +986,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize); ...@@ -926,7 +986,12 @@ EXPORT_SYMBOL_GPL(rpc_setbufsize);
*/ */
size_t rpc_max_payload(struct rpc_clnt *clnt) size_t rpc_max_payload(struct rpc_clnt *clnt)
{ {
return clnt->cl_xprt->max_payload; size_t ret;
rcu_read_lock();
ret = rcu_dereference(clnt->cl_xprt)->max_payload;
rcu_read_unlock();
return ret;
} }
EXPORT_SYMBOL_GPL(rpc_max_payload); EXPORT_SYMBOL_GPL(rpc_max_payload);
...@@ -937,8 +1002,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload); ...@@ -937,8 +1002,11 @@ EXPORT_SYMBOL_GPL(rpc_max_payload);
*/ */
void rpc_force_rebind(struct rpc_clnt *clnt) void rpc_force_rebind(struct rpc_clnt *clnt)
{ {
if (clnt->cl_autobind) if (clnt->cl_autobind) {
xprt_clear_bound(clnt->cl_xprt); rcu_read_lock();
xprt_clear_bound(rcu_dereference(clnt->cl_xprt));
rcu_read_unlock();
}
} }
EXPORT_SYMBOL_GPL(rpc_force_rebind); EXPORT_SYMBOL_GPL(rpc_force_rebind);
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/namei.h> #include <linux/namei.h>
#include <linux/fsnotify.h> #include <linux/fsnotify.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/rcupdate.h>
#include <asm/ioctls.h> #include <asm/ioctls.h>
#include <linux/poll.h> #include <linux/poll.h>
...@@ -402,12 +403,14 @@ rpc_show_info(struct seq_file *m, void *v) ...@@ -402,12 +403,14 @@ rpc_show_info(struct seq_file *m, void *v)
{ {
struct rpc_clnt *clnt = m->private; struct rpc_clnt *clnt = m->private;
rcu_read_lock();
seq_printf(m, "RPC server: %s\n", clnt->cl_server); seq_printf(m, "RPC server: %s\n", clnt->cl_server);
seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname, seq_printf(m, "service: %s (%d) version %d\n", clnt->cl_protname,
clnt->cl_prog, clnt->cl_vers); clnt->cl_prog, clnt->cl_vers);
seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR)); seq_printf(m, "address: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_ADDR));
seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO)); seq_printf(m, "protocol: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PROTO));
seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT)); seq_printf(m, "port: %s\n", rpc_peeraddr2str(clnt, RPC_DISPLAY_PORT));
rcu_read_unlock();
return 0; return 0;
} }
......
...@@ -620,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi ...@@ -620,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi
static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt) static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)
{ {
struct rpc_clnt *parent = clnt->cl_parent; struct rpc_clnt *parent = clnt->cl_parent;
struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);
while (parent != clnt) { while (parent != clnt) {
if (parent->cl_xprt != clnt->cl_xprt) if (rcu_dereference(parent->cl_xprt) != xprt)
break; break;
if (clnt->cl_autobind) if (clnt->cl_autobind)
break; break;
...@@ -653,8 +654,12 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -653,8 +654,12 @@ void rpcb_getport_async(struct rpc_task *task)
size_t salen; size_t salen;
int status; int status;
clnt = rpcb_find_transport_owner(task->tk_client); rcu_read_lock();
xprt = clnt->cl_xprt; do {
clnt = rpcb_find_transport_owner(task->tk_client);
xprt = xprt_get(rcu_dereference(clnt->cl_xprt));
} while (xprt == NULL);
rcu_read_unlock();
dprintk("RPC: %5u %s(%s, %u, %u, %d)\n", dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",
task->tk_pid, __func__, task->tk_pid, __func__,
...@@ -667,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -667,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task)
if (xprt_test_and_set_binding(xprt)) { if (xprt_test_and_set_binding(xprt)) {
dprintk("RPC: %5u %s: waiting for another binder\n", dprintk("RPC: %5u %s: waiting for another binder\n",
task->tk_pid, __func__); task->tk_pid, __func__);
xprt_put(xprt);
return; return;
} }
...@@ -734,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -734,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task)
switch (bind_version) { switch (bind_version) {
case RPCBVERS_4: case RPCBVERS_4:
case RPCBVERS_3: case RPCBVERS_3:
map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];
map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC); map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);
map->r_owner = ""; map->r_owner = "";
break; break;
...@@ -763,6 +769,7 @@ void rpcb_getport_async(struct rpc_task *task) ...@@ -763,6 +769,7 @@ void rpcb_getport_async(struct rpc_task *task)
bailout_nofree: bailout_nofree:
rpcb_wake_rpcbind_waiters(xprt, status); rpcb_wake_rpcbind_waiters(xprt, status);
task->tk_status = status; task->tk_status = status;
xprt_put(xprt);
} }
EXPORT_SYMBOL_GPL(rpcb_getport_async); EXPORT_SYMBOL_GPL(rpcb_getport_async);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/svcsock.h> #include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/metrics.h> #include <linux/sunrpc/metrics.h>
#include <linux/rcupdate.h>
#include "netns.h" #include "netns.h"
...@@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op, ...@@ -179,7 +180,7 @@ static void _print_name(struct seq_file *seq, unsigned int op,
void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
{ {
struct rpc_iostats *stats = clnt->cl_metrics; struct rpc_iostats *stats = clnt->cl_metrics;
struct rpc_xprt *xprt = clnt->cl_xprt; struct rpc_xprt *xprt;
unsigned int op, maxproc = clnt->cl_maxproc; unsigned int op, maxproc = clnt->cl_maxproc;
if (!stats) if (!stats)
...@@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt) ...@@ -189,8 +190,11 @@ void rpc_print_iostats(struct seq_file *seq, struct rpc_clnt *clnt)
seq_printf(seq, "p/v: %u/%u (%s)\n", seq_printf(seq, "p/v: %u/%u (%s)\n",
clnt->cl_prog, clnt->cl_vers, clnt->cl_protname); clnt->cl_prog, clnt->cl_vers, clnt->cl_protname);
rcu_read_lock();
xprt = rcu_dereference(clnt->cl_xprt);
if (xprt) if (xprt)
xprt->ops->print_stats(xprt, seq); xprt->ops->print_stats(xprt, seq);
rcu_read_unlock();
seq_printf(seq, "\tper-op statistics\n"); seq_printf(seq, "\tper-op statistics\n");
for (op = 0; op < maxproc; op++) { for (op = 0; op < maxproc; op++) {
......
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