aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/sunrpc/xprt.h1
-rw-r--r--net/sunrpc/xprt.c33
-rw-r--r--net/sunrpc/xprtsock.c12
3 files changed, 27 insertions, 19 deletions
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index dd860128ceda..6ef99b14ff09 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -254,6 +254,7 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
254#define XPRT_LOCKED (0) 254#define XPRT_LOCKED (0)
255#define XPRT_CONNECTED (1) 255#define XPRT_CONNECTED (1)
256#define XPRT_CONNECTING (2) 256#define XPRT_CONNECTING (2)
257#define XPRT_CLOSE_WAIT (3)
257 258
258static inline void xprt_set_connected(struct rpc_xprt *xprt) 259static inline void xprt_set_connected(struct rpc_xprt *xprt)
259{ 260{
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 069a6cbd49ea..8bc0d5acf0da 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -119,6 +119,17 @@ out_sleep:
119 return 0; 119 return 0;
120} 120}
121 121
122static void xprt_clear_locked(struct rpc_xprt *xprt)
123{
124 xprt->snd_task = NULL;
125 if (!test_bit(XPRT_CLOSE_WAIT, &xprt->state) || xprt->shutdown) {
126 smp_mb__before_clear_bit();
127 clear_bit(XPRT_LOCKED, &xprt->state);
128 smp_mb__after_clear_bit();
129 } else
130 schedule_work(&xprt->task_cleanup);
131}
132
122/* 133/*
123 * xprt_reserve_xprt_cong - serialize write access to transports 134 * xprt_reserve_xprt_cong - serialize write access to transports
124 * @task: task that is requesting access to the transport 135 * @task: task that is requesting access to the transport
@@ -145,9 +156,7 @@ int xprt_reserve_xprt_cong(struct rpc_task *task)
145 } 156 }
146 return 1; 157 return 1;
147 } 158 }
148 smp_mb__before_clear_bit(); 159 xprt_clear_locked(xprt);
149 clear_bit(XPRT_LOCKED, &xprt->state);
150 smp_mb__after_clear_bit();
151out_sleep: 160out_sleep:
152 dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt); 161 dprintk("RPC: %4d failed to lock transport %p\n", task->tk_pid, xprt);
153 task->tk_timeout = 0; 162 task->tk_timeout = 0;
@@ -193,9 +202,7 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt)
193 return; 202 return;
194 203
195out_unlock: 204out_unlock:
196 smp_mb__before_clear_bit(); 205 xprt_clear_locked(xprt);
197 clear_bit(XPRT_LOCKED, &xprt->state);
198 smp_mb__after_clear_bit();
199} 206}
200 207
201static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) 208static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
@@ -222,9 +229,7 @@ static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt)
222 return; 229 return;
223 } 230 }
224out_unlock: 231out_unlock:
225 smp_mb__before_clear_bit(); 232 xprt_clear_locked(xprt);
226 clear_bit(XPRT_LOCKED, &xprt->state);
227 smp_mb__after_clear_bit();
228} 233}
229 234
230/** 235/**
@@ -237,10 +242,7 @@ out_unlock:
237void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) 242void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
238{ 243{
239 if (xprt->snd_task == task) { 244 if (xprt->snd_task == task) {
240 xprt->snd_task = NULL; 245 xprt_clear_locked(xprt);
241 smp_mb__before_clear_bit();
242 clear_bit(XPRT_LOCKED, &xprt->state);
243 smp_mb__after_clear_bit();
244 __xprt_lock_write_next(xprt); 246 __xprt_lock_write_next(xprt);
245 } 247 }
246} 248}
@@ -256,10 +258,7 @@ void xprt_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task)
256void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) 258void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task)
257{ 259{
258 if (xprt->snd_task == task) { 260 if (xprt->snd_task == task) {
259 xprt->snd_task = NULL; 261 xprt_clear_locked(xprt);
260 smp_mb__before_clear_bit();
261 clear_bit(XPRT_LOCKED, &xprt->state);
262 smp_mb__after_clear_bit();
263 __xprt_lock_write_next_cong(xprt); 262 __xprt_lock_write_next_cong(xprt);
264 } 263 }
265} 264}
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 3e8893001479..c458f8d1d6d1 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -425,7 +425,7 @@ static void xs_close(struct rpc_xprt *xprt)
425 struct sock *sk = xprt->inet; 425 struct sock *sk = xprt->inet;
426 426
427 if (!sk) 427 if (!sk)
428 return; 428 goto clear_close_wait;
429 429
430 dprintk("RPC: xs_close xprt %p\n", xprt); 430 dprintk("RPC: xs_close xprt %p\n", xprt);
431 431
@@ -442,6 +442,10 @@ static void xs_close(struct rpc_xprt *xprt)
442 sk->sk_no_check = 0; 442 sk->sk_no_check = 0;
443 443
444 sock_release(sock); 444 sock_release(sock);
445clear_close_wait:
446 smp_mb__before_clear_bit();
447 clear_bit(XPRT_CLOSE_WAIT, &xprt->state);
448 smp_mb__after_clear_bit();
445} 449}
446 450
447/** 451/**
@@ -801,9 +805,13 @@ static void xs_tcp_state_change(struct sock *sk)
801 case TCP_SYN_SENT: 805 case TCP_SYN_SENT:
802 case TCP_SYN_RECV: 806 case TCP_SYN_RECV:
803 break; 807 break;
808 case TCP_CLOSE_WAIT:
809 /* Try to schedule an autoclose RPC calls */
810 set_bit(XPRT_CLOSE_WAIT, &xprt->state);
811 if (test_and_set_bit(XPRT_LOCKED, &xprt->state) == 0)
812 schedule_work(&xprt->task_cleanup);
804 default: 813 default:
805 xprt_disconnect(xprt); 814 xprt_disconnect(xprt);
806 break;
807 } 815 }
808 out: 816 out:
809 read_unlock(&sk->sk_callback_lock); 817 read_unlock(&sk->sk_callback_lock);