aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2013-08-05 16:04:47 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2013-08-07 17:07:18 -0400
commit786615bc1ce84150ded80daea6bd9f6297f48e73 (patch)
treeb16f44afbdf83df990b762ae3c08b45b88b3e25e
parent00326ed6442c66021cd4b5e19e80f3e2027d5d42 (diff)
SUNRPC: If the rpcbind channel is disconnected, fail the call to unregister
If rpcbind causes our connection to the AF_LOCAL socket to close after we've registered a service, then we want to be careful about reconnecting since the mount namespace may have changed. By simply refusing to reconnect the AF_LOCAL socket in the case of unregister, we avoid the need to somehow save the mount namespace. While this may lead to some services not unregistering properly, it should be safe. Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com> Cc: Nix <nix@esperi.org.uk> Cc: Jeff Layton <jlayton@redhat.com> Cc: stable@vger.kernel.org # 3.9.x
-rw-r--r--include/linux/sunrpc/sched.h1
-rw-r--r--net/sunrpc/clnt.c4
-rw-r--r--net/sunrpc/netns.h1
-rw-r--r--net/sunrpc/rpcb_clnt.c40
4 files changed, 33 insertions, 13 deletions
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 6d870353674a..1821445708d6 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -121,6 +121,7 @@ struct rpc_task_setup {
121#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */ 121#define RPC_TASK_SOFTCONN 0x0400 /* Fail if can't connect */
122#define RPC_TASK_SENT 0x0800 /* message was sent */ 122#define RPC_TASK_SENT 0x0800 /* message was sent */
123#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */ 123#define RPC_TASK_TIMEOUT 0x1000 /* fail with ETIMEDOUT on timeout */
124#define RPC_TASK_NOCONNECT 0x2000 /* return ENOTCONN if not connected */
124 125
125#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC) 126#define RPC_IS_ASYNC(t) ((t)->tk_flags & RPC_TASK_ASYNC)
126#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER) 127#define RPC_IS_SWAPPER(t) ((t)->tk_flags & RPC_TASK_SWAPPER)
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 74f6a704e374..ecbc4e3d83ad 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -1660,6 +1660,10 @@ call_connect(struct rpc_task *task)
1660 task->tk_action = call_connect_status; 1660 task->tk_action = call_connect_status;
1661 if (task->tk_status < 0) 1661 if (task->tk_status < 0)
1662 return; 1662 return;
1663 if (task->tk_flags & RPC_TASK_NOCONNECT) {
1664 rpc_exit(task, -ENOTCONN);
1665 return;
1666 }
1663 xprt_connect(task); 1667 xprt_connect(task);
1664 } 1668 }
1665} 1669}
diff --git a/net/sunrpc/netns.h b/net/sunrpc/netns.h
index 74d948f5d5a1..779742cfc1ff 100644
--- a/net/sunrpc/netns.h
+++ b/net/sunrpc/netns.h
@@ -23,6 +23,7 @@ struct sunrpc_net {
23 struct rpc_clnt *rpcb_local_clnt4; 23 struct rpc_clnt *rpcb_local_clnt4;
24 spinlock_t rpcb_clnt_lock; 24 spinlock_t rpcb_clnt_lock;
25 unsigned int rpcb_users; 25 unsigned int rpcb_users;
26 unsigned int rpcb_is_af_local : 1;
26 27
27 struct mutex gssp_lock; 28 struct mutex gssp_lock;
28 wait_queue_head_t gssp_wq; 29 wait_queue_head_t gssp_wq;
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index b0f723227157..1891a1022c17 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net)
204} 204}
205 205
206static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, 206static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
207 struct rpc_clnt *clnt4) 207 struct rpc_clnt *clnt4,
208 bool is_af_local)
208{ 209{
209 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 210 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
210 211
211 /* Protected by rpcb_create_local_mutex */ 212 /* Protected by rpcb_create_local_mutex */
212 sn->rpcb_local_clnt = clnt; 213 sn->rpcb_local_clnt = clnt;
213 sn->rpcb_local_clnt4 = clnt4; 214 sn->rpcb_local_clnt4 = clnt4;
215 sn->rpcb_is_af_local = is_af_local ? 1 : 0;
214 smp_wmb(); 216 smp_wmb();
215 sn->rpcb_users = 1; 217 sn->rpcb_users = 1;
216 dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: " 218 dprintk("RPC: created new rpcb local clients (rpcb_local_clnt: "
@@ -271,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net)
271 clnt4 = NULL; 273 clnt4 = NULL;
272 } 274 }
273 275
274 rpcb_set_local(net, clnt, clnt4); 276 rpcb_set_local(net, clnt, clnt4, true);
275 277
276out: 278out:
277 return result; 279 return result;
@@ -323,7 +325,7 @@ static int rpcb_create_local_net(struct net *net)
323 clnt4 = NULL; 325 clnt4 = NULL;
324 } 326 }
325 327
326 rpcb_set_local(net, clnt, clnt4); 328 rpcb_set_local(net, clnt, clnt4, false);
327 329
328out: 330out:
329 return result; 331 return result;
@@ -384,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
384 return rpc_create(&args); 386 return rpc_create(&args);
385} 387}
386 388
387static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg) 389static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
388{ 390{
389 int result, error = 0; 391 int flags = RPC_TASK_NOCONNECT;
392 int error, result = 0;
390 393
394 if (is_set || !sn->rpcb_is_af_local)
395 flags = RPC_TASK_SOFTCONN;
391 msg->rpc_resp = &result; 396 msg->rpc_resp = &result;
392 397
393 error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN); 398 error = rpc_call_sync(clnt, msg, flags);
394 if (error < 0) { 399 if (error < 0) {
395 dprintk("RPC: failed to contact local rpcbind " 400 dprintk("RPC: failed to contact local rpcbind "
396 "server (errno %d).\n", -error); 401 "server (errno %d).\n", -error);
@@ -447,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short
447 .rpc_argp = &map, 452 .rpc_argp = &map,
448 }; 453 };
449 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); 454 struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
455 bool is_set = false;
450 456
451 dprintk("RPC: %sregistering (%u, %u, %d, %u) with local " 457 dprintk("RPC: %sregistering (%u, %u, %d, %u) with local "
452 "rpcbind\n", (port ? "" : "un"), 458 "rpcbind\n", (port ? "" : "un"),
453 prog, vers, prot, port); 459 prog, vers, prot, port);
454 460
455 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET]; 461 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
456 if (port) 462 if (port != 0) {
457 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; 463 msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
464 is_set = true;
465 }
458 466
459 return rpcb_register_call(sn->rpcb_local_clnt, &msg); 467 return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set);
460} 468}
461 469
462/* 470/*
@@ -469,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
469 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; 477 const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
470 struct rpcbind_args *map = msg->rpc_argp; 478 struct rpcbind_args *map = msg->rpc_argp;
471 unsigned short port = ntohs(sin->sin_port); 479 unsigned short port = ntohs(sin->sin_port);
480 bool is_set = false;
472 int result; 481 int result;
473 482
474 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); 483 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -479,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
479 map->r_addr, map->r_netid); 488 map->r_addr, map->r_netid);
480 489
481 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; 490 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
482 if (port) 491 if (port != 0) {
483 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; 492 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
493 is_set = true;
494 }
484 495
485 result = rpcb_register_call(sn->rpcb_local_clnt4, msg); 496 result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
486 kfree(map->r_addr); 497 kfree(map->r_addr);
487 return result; 498 return result;
488} 499}
@@ -497,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
497 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; 508 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
498 struct rpcbind_args *map = msg->rpc_argp; 509 struct rpcbind_args *map = msg->rpc_argp;
499 unsigned short port = ntohs(sin6->sin6_port); 510 unsigned short port = ntohs(sin6->sin6_port);
511 bool is_set = false;
500 int result; 512 int result;
501 513
502 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL); 514 map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -507,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
507 map->r_addr, map->r_netid); 519 map->r_addr, map->r_netid);
508 520
509 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; 521 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
510 if (port) 522 if (port != 0) {
511 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; 523 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
524 is_set = true;
525 }
512 526
513 result = rpcb_register_call(sn->rpcb_local_clnt4, msg); 527 result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
514 kfree(map->r_addr); 528 kfree(map->r_addr);
515 return result; 529 return result;
516} 530}
@@ -527,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
527 map->r_addr = ""; 541 map->r_addr = "";
528 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; 542 msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
529 543
530 return rpcb_register_call(sn->rpcb_local_clnt4, msg); 544 return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false);
531} 545}
532 546
533/** 547/**