aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc
diff options
context:
space:
mode:
authorTrond Myklebust <trond.myklebust@primarydata.com>2015-02-08 18:19:25 -0500
committerTrond Myklebust <trond.myklebust@primarydata.com>2015-02-08 21:47:29 -0500
commit718ba5b87343df303017585200ee182e937eabfc (patch)
tree445d5bbb8aa4173b00527852b76d1e210fbb78c5 /net/sunrpc
parent6cc7e908362a9dfec3c821f77ec98b6758592060 (diff)
SUNRPC: Add helpers to prevent socket create from racing
The socket lock is currently held by the task that is requesting the connection be established. While that is efficient in the case where the connection happens quickly, it is racy in the case where it doesn't. What we really want is for the connect helper to be able to block access to the socket while it is being set up. This patch does so by arranging to transfer the socket lock from the task that is requesting the connect attempt, and then releasing that lock once everything is done. This scheme also gives us automatic protection against collisions with the RPC close code, so we can kill the cancel_delayed_work_sync() call in xs_close(). Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Diffstat (limited to 'net/sunrpc')
-rw-r--r--net/sunrpc/xprt.c37
-rw-r--r--net/sunrpc/xprtsock.c7
2 files changed, 38 insertions, 6 deletions
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index ebbefad21a37..ff3574df8344 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -690,6 +690,37 @@ out_abort:
690 spin_unlock(&xprt->transport_lock); 690 spin_unlock(&xprt->transport_lock);
691} 691}
692 692
693bool xprt_lock_connect(struct rpc_xprt *xprt,
694 struct rpc_task *task,
695 void *cookie)
696{
697 bool ret = false;
698
699 spin_lock_bh(&xprt->transport_lock);
700 if (!test_bit(XPRT_LOCKED, &xprt->state))
701 goto out;
702 if (xprt->snd_task != task)
703 goto out;
704 xprt->snd_task = cookie;
705 ret = true;
706out:
707 spin_unlock_bh(&xprt->transport_lock);
708 return ret;
709}
710
711void xprt_unlock_connect(struct rpc_xprt *xprt, void *cookie)
712{
713 spin_lock_bh(&xprt->transport_lock);
714 if (xprt->snd_task != cookie)
715 goto out;
716 if (!test_bit(XPRT_LOCKED, &xprt->state))
717 goto out;
718 xprt->snd_task =NULL;
719 xprt->ops->release_xprt(xprt, NULL);
720out:
721 spin_unlock_bh(&xprt->transport_lock);
722}
723
693/** 724/**
694 * xprt_connect - schedule a transport connect operation 725 * xprt_connect - schedule a transport connect operation
695 * @task: RPC task that is requesting the connect 726 * @task: RPC task that is requesting the connect
@@ -712,9 +743,7 @@ void xprt_connect(struct rpc_task *task)
712 if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state)) 743 if (test_and_clear_bit(XPRT_CLOSE_WAIT, &xprt->state))
713 xprt->ops->close(xprt); 744 xprt->ops->close(xprt);
714 745
715 if (xprt_connected(xprt)) 746 if (!xprt_connected(xprt)) {
716 xprt_release_write(xprt, task);
717 else {
718 task->tk_rqstp->rq_bytes_sent = 0; 747 task->tk_rqstp->rq_bytes_sent = 0;
719 task->tk_timeout = task->tk_rqstp->rq_timeout; 748 task->tk_timeout = task->tk_rqstp->rq_timeout;
720 rpc_sleep_on(&xprt->pending, task, xprt_connect_status); 749 rpc_sleep_on(&xprt->pending, task, xprt_connect_status);
@@ -726,6 +755,7 @@ void xprt_connect(struct rpc_task *task)
726 xprt->stat.connect_start = jiffies; 755 xprt->stat.connect_start = jiffies;
727 xprt->ops->connect(xprt, task); 756 xprt->ops->connect(xprt, task);
728 } 757 }
758 xprt_release_write(xprt, task);
729} 759}
730 760
731static void xprt_connect_status(struct rpc_task *task) 761static void xprt_connect_status(struct rpc_task *task)
@@ -758,7 +788,6 @@ static void xprt_connect_status(struct rpc_task *task)
758 dprintk("RPC: %5u xprt_connect_status: error %d connecting to " 788 dprintk("RPC: %5u xprt_connect_status: error %d connecting to "
759 "server %s\n", task->tk_pid, -task->tk_status, 789 "server %s\n", task->tk_pid, -task->tk_status,
760 xprt->servername); 790 xprt->servername);
761 xprt_release_write(xprt, task);
762 task->tk_status = -EIO; 791 task->tk_status = -EIO;
763 } 792 }
764} 793}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 0fa7ed93dc20..e57d8ed2c4d8 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -852,8 +852,6 @@ static void xs_close(struct rpc_xprt *xprt)
852 852
853 dprintk("RPC: xs_close xprt %p\n", xprt); 853 dprintk("RPC: xs_close xprt %p\n", xprt);
854 854
855 cancel_delayed_work_sync(&transport->connect_worker);
856
857 xs_reset_transport(transport); 855 xs_reset_transport(transport);
858 xprt->reestablish_timeout = 0; 856 xprt->reestablish_timeout = 0;
859 857
@@ -2101,6 +2099,7 @@ static void xs_udp_setup_socket(struct work_struct *work)
2101 trace_rpc_socket_connect(xprt, sock, 0); 2099 trace_rpc_socket_connect(xprt, sock, 0);
2102 status = 0; 2100 status = 0;
2103out: 2101out:
2102 xprt_unlock_connect(xprt, transport);
2104 xprt_clear_connecting(xprt); 2103 xprt_clear_connecting(xprt);
2105 xprt_wake_pending_tasks(xprt, status); 2104 xprt_wake_pending_tasks(xprt, status);
2106} 2105}
@@ -2286,6 +2285,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
2286 case 0: 2285 case 0:
2287 case -EINPROGRESS: 2286 case -EINPROGRESS:
2288 case -EALREADY: 2287 case -EALREADY:
2288 xprt_unlock_connect(xprt, transport);
2289 xprt_clear_connecting(xprt); 2289 xprt_clear_connecting(xprt);
2290 return; 2290 return;
2291 case -EINVAL: 2291 case -EINVAL:
@@ -2303,6 +2303,7 @@ static void xs_tcp_setup_socket(struct work_struct *work)
2303out_eagain: 2303out_eagain:
2304 status = -EAGAIN; 2304 status = -EAGAIN;
2305out: 2305out:
2306 xprt_unlock_connect(xprt, transport);
2306 xprt_clear_connecting(xprt); 2307 xprt_clear_connecting(xprt);
2307 xprt_wake_pending_tasks(xprt, status); 2308 xprt_wake_pending_tasks(xprt, status);
2308} 2309}
@@ -2325,6 +2326,8 @@ static void xs_connect(struct rpc_xprt *xprt, struct rpc_task *task)
2325{ 2326{
2326 struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); 2327 struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt);
2327 2328
2329 WARN_ON_ONCE(!xprt_lock_connect(xprt, task, transport));
2330
2328 if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) { 2331 if (transport->sock != NULL && !RPC_IS_SOFTCONN(task)) {
2329 dprintk("RPC: xs_connect delayed xprt %p for %lu " 2332 dprintk("RPC: xs_connect delayed xprt %p for %lu "
2330 "seconds\n", 2333 "seconds\n",