diff options
author | Trond Myklebust <trond.myklebust@primarydata.com> | 2014-07-24 23:59:31 -0400 |
---|---|---|
committer | J. Bruce Fields <bfields@redhat.com> | 2014-07-29 16:10:15 -0400 |
commit | 0971374e2818eef6ebdbd7a37acf6ab7e98ac06c (patch) | |
tree | 87ca80081f794d3b18bc301dc570b9403f39ee4f /net | |
parent | 650ecc8f8ff29a7f0990704f09df232b505b200d (diff) |
SUNRPC: Reduce contention in svc_xprt_enqueue()
Ensure that all calls to svc_xprt_enqueue() except svc_xprt_received()
check the value of XPT_BUSY, before attempting to grab spinlocks etc.
This is to avoid situations such as the following "perf" trace,
which shows heavy contention on the pool spinlock:
54.15% nfsd [kernel.kallsyms] [k] _raw_spin_lock_bh
|
--- _raw_spin_lock_bh
|
|--71.43%-- svc_xprt_enqueue
| |
| |--50.31%-- svc_reserve
| |
| |--31.35%-- svc_xprt_received
| |
| |--18.34%-- svc_tcp_data_ready
...
Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index b4737fbdec13..9cfa391e2bd0 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -23,6 +23,7 @@ static int svc_deferred_recv(struct svc_rqst *rqstp); | |||
23 | static struct cache_deferred_req *svc_defer(struct cache_req *req); | 23 | static struct cache_deferred_req *svc_defer(struct cache_req *req); |
24 | static void svc_age_temp_xprts(unsigned long closure); | 24 | static void svc_age_temp_xprts(unsigned long closure); |
25 | static void svc_delete_xprt(struct svc_xprt *xprt); | 25 | static void svc_delete_xprt(struct svc_xprt *xprt); |
26 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt); | ||
26 | 27 | ||
27 | /* apparently the "standard" is that clients close | 28 | /* apparently the "standard" is that clients close |
28 | * idle connections after 5 minutes, servers after | 29 | * idle connections after 5 minutes, servers after |
@@ -222,11 +223,12 @@ static void svc_xprt_received(struct svc_xprt *xprt) | |||
222 | if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) | 223 | if (!test_bit(XPT_BUSY, &xprt->xpt_flags)) |
223 | return; | 224 | return; |
224 | /* As soon as we clear busy, the xprt could be closed and | 225 | /* As soon as we clear busy, the xprt could be closed and |
225 | * 'put', so we need a reference to call svc_xprt_enqueue with: | 226 | * 'put', so we need a reference to call svc_xprt_do_enqueue with: |
226 | */ | 227 | */ |
227 | svc_xprt_get(xprt); | 228 | svc_xprt_get(xprt); |
229 | smp_mb__before_atomic(); | ||
228 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | 230 | clear_bit(XPT_BUSY, &xprt->xpt_flags); |
229 | svc_xprt_enqueue(xprt); | 231 | svc_xprt_do_enqueue(xprt); |
230 | svc_xprt_put(xprt); | 232 | svc_xprt_put(xprt); |
231 | } | 233 | } |
232 | 234 | ||
@@ -335,12 +337,7 @@ static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) | |||
335 | return false; | 337 | return false; |
336 | } | 338 | } |
337 | 339 | ||
338 | /* | 340 | static void svc_xprt_do_enqueue(struct svc_xprt *xprt) |
339 | * Queue up a transport with data pending. If there are idle nfsd | ||
340 | * processes, wake 'em up. | ||
341 | * | ||
342 | */ | ||
343 | void svc_xprt_enqueue(struct svc_xprt *xprt) | ||
344 | { | 341 | { |
345 | struct svc_pool *pool; | 342 | struct svc_pool *pool; |
346 | struct svc_rqst *rqstp; | 343 | struct svc_rqst *rqstp; |
@@ -398,6 +395,18 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
398 | out_unlock: | 395 | out_unlock: |
399 | spin_unlock_bh(&pool->sp_lock); | 396 | spin_unlock_bh(&pool->sp_lock); |
400 | } | 397 | } |
398 | |||
399 | /* | ||
400 | * Queue up a transport with data pending. If there are idle nfsd | ||
401 | * processes, wake 'em up. | ||
402 | * | ||
403 | */ | ||
404 | void svc_xprt_enqueue(struct svc_xprt *xprt) | ||
405 | { | ||
406 | if (test_bit(XPT_BUSY, &xprt->xpt_flags)) | ||
407 | return; | ||
408 | svc_xprt_do_enqueue(xprt); | ||
409 | } | ||
401 | EXPORT_SYMBOL_GPL(svc_xprt_enqueue); | 410 | EXPORT_SYMBOL_GPL(svc_xprt_enqueue); |
402 | 411 | ||
403 | /* | 412 | /* |