diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
-rw-r--r-- | net/sunrpc/rpcb_clnt.c | 188 |
1 files changed, 102 insertions, 86 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 8761bf8e36fc..207a74696c9f 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -23,12 +23,15 @@ #include <linux/errno.h> #include <linux/mutex.h> #include <linux/slab.h> +#include <linux/nsproxy.h> #include <net/ipv6.h> #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/sched.h> #include <linux/sunrpc/xprtsock.h> +#include "netns.h" + #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_BIND #endif @@ -109,13 +112,7 @@ enum { static void rpcb_getport_done(struct rpc_task *, void *); static void rpcb_map_release(void *data); -static struct rpc_program rpcb_program; - -static struct rpc_clnt * rpcb_local_clnt; -static struct rpc_clnt * rpcb_local_clnt4; - -DEFINE_SPINLOCK(rpcb_clnt_lock); -unsigned int rpcb_users; +static const struct rpc_program rpcb_program; struct rpcbind_args { struct rpc_xprt * r_xprt; @@ -140,8 +137,8 @@ struct rpcb_info { struct rpc_procinfo * rpc_proc; }; -static struct rpcb_info rpcb_next_version[]; -static struct rpcb_info rpcb_next_version6[]; +static const struct rpcb_info rpcb_next_version[]; +static const struct rpcb_info rpcb_next_version6[]; static const struct rpc_call_ops rpcb_getport_ops = { .rpc_call_done = rpcb_getport_done, @@ -164,32 +161,34 @@ static void rpcb_map_release(void *data) kfree(map); } -static int rpcb_get_local(void) +static int rpcb_get_local(struct net *net) { int cnt; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); - spin_lock(&rpcb_clnt_lock); - if (rpcb_users) - rpcb_users++; - cnt = rpcb_users; - spin_unlock(&rpcb_clnt_lock); + spin_lock(&sn->rpcb_clnt_lock); + if (sn->rpcb_users) + sn->rpcb_users++; + cnt = sn->rpcb_users; + spin_unlock(&sn->rpcb_clnt_lock); return cnt; } -void rpcb_put_local(void) +void rpcb_put_local(struct net *net) { - struct rpc_clnt *clnt = rpcb_local_clnt; - struct rpc_clnt *clnt4 = rpcb_local_clnt4; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + struct rpc_clnt *clnt = sn->rpcb_local_clnt; + struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4; int shutdown; - spin_lock(&rpcb_clnt_lock); - if (--rpcb_users == 0) { - rpcb_local_clnt = NULL; - rpcb_local_clnt4 = NULL; + spin_lock(&sn->rpcb_clnt_lock); + if (--sn->rpcb_users == 0) { + sn->rpcb_local_clnt = NULL; + sn->rpcb_local_clnt4 = NULL; } - shutdown = !rpcb_users; - spin_unlock(&rpcb_clnt_lock); + shutdown = !sn->rpcb_users; + spin_unlock(&sn->rpcb_clnt_lock); if (shutdown) { /* @@ -202,30 +201,34 @@ void rpcb_put_local(void) } } -static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) +static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, + struct rpc_clnt *clnt4) { + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); + /* Protected by rpcb_create_local_mutex */ - rpcb_local_clnt = clnt; - rpcb_local_clnt4 = clnt4; + sn->rpcb_local_clnt = clnt; + sn->rpcb_local_clnt4 = clnt4; smp_wmb(); - rpcb_users = 1; + sn->rpcb_users = 1; dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " - "%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt, - rpcb_local_clnt4); + "%p, rpcb_local_clnt4: %p) for net %p%s\n", + sn->rpcb_local_clnt, sn->rpcb_local_clnt4, + net, (net == &init_net) ? " (init_net)" : ""); } /* * Returns zero on success, otherwise a negative errno value * is returned. */ -static int rpcb_create_local_unix(void) +static int rpcb_create_local_unix(struct net *net) { static const struct sockaddr_un rpcb_localaddr_rpcbind = { .sun_family = AF_LOCAL, .sun_path = RPCBIND_SOCK_PATHNAME, }; struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = XPRT_TRANSPORT_LOCAL, .address = (struct sockaddr *)&rpcb_localaddr_rpcbind, .addrsize = sizeof(rpcb_localaddr_rpcbind), @@ -258,7 +261,7 @@ static int rpcb_create_local_unix(void) clnt4 = NULL; } - rpcb_set_local(clnt, clnt4); + rpcb_set_local(net, clnt, clnt4); out: return result; @@ -268,7 +271,7 @@ out: * Returns zero on success, otherwise a negative errno value * is returned. */ -static int rpcb_create_local_net(void) +static int rpcb_create_local_net(struct net *net) { static const struct sockaddr_in rpcb_inaddr_loopback = { .sin_family = AF_INET, @@ -276,7 +279,7 @@ static int rpcb_create_local_net(void) .sin_port = htons(RPCBIND_PORT), }; struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = XPRT_TRANSPORT_TCP, .address = (struct sockaddr *)&rpcb_inaddr_loopback, .addrsize = sizeof(rpcb_inaddr_loopback), @@ -310,7 +313,7 @@ static int rpcb_create_local_net(void) clnt4 = NULL; } - rpcb_set_local(clnt, clnt4); + rpcb_set_local(net, clnt, clnt4); out: return result; @@ -320,31 +323,32 @@ out: * Returns zero on success, otherwise a negative errno value * is returned. */ -int rpcb_create_local(void) +int rpcb_create_local(struct net *net) { static DEFINE_MUTEX(rpcb_create_local_mutex); int result = 0; - if (rpcb_get_local()) + if (rpcb_get_local(net)) return result; mutex_lock(&rpcb_create_local_mutex); - if (rpcb_get_local()) + if (rpcb_get_local(net)) goto out; - if (rpcb_create_local_unix() != 0) - result = rpcb_create_local_net(); + if (rpcb_create_local_unix(net) != 0) + result = rpcb_create_local_net(net); out: mutex_unlock(&rpcb_create_local_mutex); return result; } -static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, - size_t salen, int proto, u32 version) +static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, + struct sockaddr *srvaddr, size_t salen, + int proto, u32 version) { struct rpc_create_args args = { - .net = &init_net, + .net = net, .protocol = proto, .address = srvaddr, .addrsize = salen, @@ -420,7 +424,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6 * addresses). */ -int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) +int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port) { struct rpcbind_args map = { .r_prog = prog, @@ -431,6 +435,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) struct rpc_message msg = { .rpc_argp = &map, }; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " "rpcbind\n", (port ? "" : "un"), @@ -440,13 +445,14 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) if (port) msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; - return rpcb_register_call(rpcb_local_clnt, &msg); + return rpcb_register_call(sn->rpcb_local_clnt, &msg); } /* * Fill in AF_INET family-specific arguments to register */ -static int rpcb_register_inet4(const struct sockaddr *sap, +static int rpcb_register_inet4(struct sunrpc_net *sn, + const struct sockaddr *sap, struct rpc_message *msg) { const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; @@ -465,7 +471,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(rpcb_local_clnt4, msg); + result = rpcb_register_call(sn->rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } @@ -473,7 +479,8 @@ static int rpcb_register_inet4(const struct sockaddr *sap, /* * Fill in AF_INET6 family-specific arguments to register */ -static int rpcb_register_inet6(const struct sockaddr *sap, +static int rpcb_register_inet6(struct sunrpc_net *sn, + const struct sockaddr *sap, struct rpc_message *msg) { const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; @@ -492,12 +499,13 @@ static int rpcb_register_inet6(const struct sockaddr *sap, if (port) msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; - result = rpcb_register_call(rpcb_local_clnt4, msg); + result = rpcb_register_call(sn->rpcb_local_clnt4, msg); kfree(map->r_addr); return result; } -static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) +static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, + struct rpc_message *msg) { struct rpcbind_args *map = msg->rpc_argp; @@ -508,7 +516,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) map->r_addr = ""; msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; - return rpcb_register_call(rpcb_local_clnt4, msg); + return rpcb_register_call(sn->rpcb_local_clnt4, msg); } /** @@ -554,7 +562,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) * service on any IPv4 address, but not on IPv6. The latter * advertises the service on all IPv4 and IPv6 addresses. */ -int rpcb_v4_register(const u32 program, const u32 version, +int rpcb_v4_register(struct net *net, const u32 program, const u32 version, const struct sockaddr *address, const char *netid) { struct rpcbind_args map = { @@ -566,18 +574,19 @@ int rpcb_v4_register(const u32 program, const u32 version, struct rpc_message msg = { .rpc_argp = &map, }; + struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); - if (rpcb_local_clnt4 == NULL) + if (sn->rpcb_local_clnt4 == NULL) return -EPROTONOSUPPORT; if (address == NULL) - return rpcb_unregister_all_protofamilies(&msg); + return rpcb_unregister_all_protofamilies(sn, &msg); switch (address->sa_family) { case AF_INET: - return rpcb_register_inet4(address, &msg); + return rpcb_register_inet4(sn, address, &msg); case AF_INET6: - return rpcb_register_inet6(address, &msg); + return rpcb_register_inet6(sn, address, &msg); } return -EAFNOSUPPORT; @@ -611,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) { struct rpc_clnt *parent = clnt->cl_parent; + struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt); while (parent != clnt) { - if (parent->cl_xprt != clnt->cl_xprt) + if (rcu_dereference(parent->cl_xprt) != xprt) break; if (clnt->cl_autobind) break; @@ -644,12 +654,16 @@ void rpcb_getport_async(struct rpc_task *task) size_t salen; int status; - clnt = rpcb_find_transport_owner(task->tk_client); - xprt = clnt->cl_xprt; + rcu_read_lock(); + 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", task->tk_pid, __func__, - clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); + xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot); /* Put self on the wait queue to ensure we get notified if * some other task is already attempting to bind the port */ @@ -658,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task) if (xprt_test_and_set_binding(xprt)) { dprintk("RPC: %5u %s: waiting for another binder\n", task->tk_pid, __func__); + xprt_put(xprt); return; } @@ -699,8 +714,8 @@ void rpcb_getport_async(struct rpc_task *task) dprintk("RPC: %5u %s: trying rpcbind version %u\n", task->tk_pid, __func__, bind_version); - rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, - bind_version); + rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen, + xprt->prot, bind_version); if (IS_ERR(rpcb_clnt)) { status = PTR_ERR(rpcb_clnt); dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", @@ -725,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task) switch (bind_version) { case RPCBVERS_4: 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_owner = ""; break; @@ -754,6 +769,7 @@ bailout_release_client: bailout_nofree: rpcb_wake_rpcbind_waiters(xprt, status); task->tk_status = status; + xprt_put(xprt); } EXPORT_SYMBOL_GPL(rpcb_getport_async); @@ -801,11 +817,11 @@ static void rpcb_getport_done(struct rpc_task *child, void *data) static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, const struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; __be32 *p; dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port); p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); @@ -818,7 +834,6 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr, static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; unsigned long port; __be32 *p; @@ -829,8 +844,8 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, return -EIO; port = be32_to_cpup(p); - dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid, - task->tk_msg.rpc_proc->p_name, port); + dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, port); if (unlikely(port > USHRT_MAX)) return -EIO; @@ -841,7 +856,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr, static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, unsigned int *boolp) { - struct rpc_task *task = req->rq_task; __be32 *p; p = xdr_inline_decode(xdr, 4); @@ -853,7 +867,8 @@ static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr, *boolp = 1; dprintk("RPC: %5u RPCB_%s call %s\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, (*boolp ? "succeeded" : "failed")); return 0; } @@ -873,11 +888,11 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string, static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, const struct rpcbind_args *rpcb) { - struct rpc_task *task = req->rq_task; __be32 *p; dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name, + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, rpcb->r_prog, rpcb->r_vers, rpcb->r_netid, rpcb->r_addr); @@ -895,7 +910,6 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, { struct sockaddr_storage address; struct sockaddr *sap = (struct sockaddr *)&address; - struct rpc_task *task = req->rq_task; __be32 *p; u32 len; @@ -912,7 +926,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, */ if (len == 0) { dprintk("RPC: %5u RPCB reply: program not registered\n", - task->tk_pid); + req->rq_task->tk_pid); return 0; } @@ -922,10 +936,11 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, p = xdr_inline_decode(xdr, len); if (unlikely(p == NULL)) goto out_fail; - dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, - task->tk_msg.rpc_proc->p_name, (char *)p); + dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name, (char *)p); - if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0) + if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, + sap, sizeof(address)) == 0) goto out_fail; rpcb->r_port = rpc_get_port(sap); @@ -933,7 +948,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr, out_fail: dprintk("RPC: %5u malformed RPCB_%s reply\n", - task->tk_pid, task->tk_msg.rpc_proc->p_name); + req->rq_task->tk_pid, + req->rq_task->tk_msg.rpc_proc->p_name); return -EIO; } @@ -1041,7 +1057,7 @@ static struct rpc_procinfo rpcb_procedures4[] = { }, }; -static struct rpcb_info rpcb_next_version[] = { +static const struct rpcb_info rpcb_next_version[] = { { .rpc_vers = RPCBVERS_2, .rpc_proc = &rpcb_procedures2[RPCBPROC_GETPORT], @@ -1051,7 +1067,7 @@ static struct rpcb_info rpcb_next_version[] = { }, }; -static struct rpcb_info rpcb_next_version6[] = { +static const struct rpcb_info rpcb_next_version6[] = { { .rpc_vers = RPCBVERS_4, .rpc_proc = &rpcb_procedures4[RPCBPROC_GETADDR], @@ -1065,25 +1081,25 @@ static struct rpcb_info rpcb_next_version6[] = { }, }; -static struct rpc_version rpcb_version2 = { +static const struct rpc_version rpcb_version2 = { .number = RPCBVERS_2, .nrprocs = ARRAY_SIZE(rpcb_procedures2), .procs = rpcb_procedures2 }; -static struct rpc_version rpcb_version3 = { +static const struct rpc_version rpcb_version3 = { .number = RPCBVERS_3, .nrprocs = ARRAY_SIZE(rpcb_procedures3), .procs = rpcb_procedures3 }; -static struct rpc_version rpcb_version4 = { +static const struct rpc_version rpcb_version4 = { .number = RPCBVERS_4, .nrprocs = ARRAY_SIZE(rpcb_procedures4), .procs = rpcb_procedures4 }; -static struct rpc_version *rpcb_version[] = { +static const struct rpc_version *rpcb_version[] = { NULL, NULL, &rpcb_version2, @@ -1093,7 +1109,7 @@ static struct rpc_version *rpcb_version[] = { static struct rpc_stat rpcb_stats; -static struct rpc_program rpcb_program = { +static const struct rpc_program rpcb_program = { .name = "rpcbind", .number = RPCBIND_PROGRAM, .nrvers = ARRAY_SIZE(rpcb_version), |