diff options
Diffstat (limited to 'net/sunrpc/svc_xprt.c')
-rw-r--r-- | net/sunrpc/svc_xprt.c | 97 |
1 files changed, 46 insertions, 51 deletions
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c index 3f2c5559ca1..ab86b7927f8 100644 --- a/net/sunrpc/svc_xprt.c +++ b/net/sunrpc/svc_xprt.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <linux/sunrpc/stats.h> | 13 | #include <linux/sunrpc/stats.h> |
14 | #include <linux/sunrpc/svc_xprt.h> | 14 | #include <linux/sunrpc/svc_xprt.h> |
15 | #include <linux/sunrpc/svcsock.h> | 15 | #include <linux/sunrpc/svcsock.h> |
16 | #include <linux/sunrpc/xprt.h> | ||
16 | 17 | ||
17 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT | 18 | #define RPCDBG_FACILITY RPCDBG_SVCXPRT |
18 | 19 | ||
@@ -128,6 +129,9 @@ static void svc_xprt_free(struct kref *kref) | |||
128 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) | 129 | if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) |
129 | svcauth_unix_info_release(xprt); | 130 | svcauth_unix_info_release(xprt); |
130 | put_net(xprt->xpt_net); | 131 | put_net(xprt->xpt_net); |
132 | /* See comment on corresponding get in xs_setup_bc_tcp(): */ | ||
133 | if (xprt->xpt_bc_xprt) | ||
134 | xprt_put(xprt->xpt_bc_xprt); | ||
131 | xprt->xpt_ops->xpo_free(xprt); | 135 | xprt->xpt_ops->xpo_free(xprt); |
132 | module_put(owner); | 136 | module_put(owner); |
133 | } | 137 | } |
@@ -303,6 +307,15 @@ static void svc_thread_dequeue(struct svc_pool *pool, struct svc_rqst *rqstp) | |||
303 | list_del(&rqstp->rq_list); | 307 | list_del(&rqstp->rq_list); |
304 | } | 308 | } |
305 | 309 | ||
310 | static bool svc_xprt_has_something_to_do(struct svc_xprt *xprt) | ||
311 | { | ||
312 | if (xprt->xpt_flags & ((1<<XPT_CONN)|(1<<XPT_CLOSE))) | ||
313 | return true; | ||
314 | if (xprt->xpt_flags & ((1<<XPT_DATA)|(1<<XPT_DEFERRED))) | ||
315 | return xprt->xpt_ops->xpo_has_wspace(xprt); | ||
316 | return false; | ||
317 | } | ||
318 | |||
306 | /* | 319 | /* |
307 | * Queue up a transport with data pending. If there are idle nfsd | 320 | * Queue up a transport with data pending. If there are idle nfsd |
308 | * processes, wake 'em up. | 321 | * processes, wake 'em up. |
@@ -315,8 +328,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
315 | struct svc_rqst *rqstp; | 328 | struct svc_rqst *rqstp; |
316 | int cpu; | 329 | int cpu; |
317 | 330 | ||
318 | if (!(xprt->xpt_flags & | 331 | if (!svc_xprt_has_something_to_do(xprt)) |
319 | ((1<<XPT_CONN)|(1<<XPT_DATA)|(1<<XPT_CLOSE)|(1<<XPT_DEFERRED)))) | ||
320 | return; | 332 | return; |
321 | 333 | ||
322 | cpu = get_cpu(); | 334 | cpu = get_cpu(); |
@@ -343,28 +355,7 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
343 | dprintk("svc: transport %p busy, not enqueued\n", xprt); | 355 | dprintk("svc: transport %p busy, not enqueued\n", xprt); |
344 | goto out_unlock; | 356 | goto out_unlock; |
345 | } | 357 | } |
346 | BUG_ON(xprt->xpt_pool != NULL); | ||
347 | xprt->xpt_pool = pool; | ||
348 | |||
349 | /* Handle pending connection */ | ||
350 | if (test_bit(XPT_CONN, &xprt->xpt_flags)) | ||
351 | goto process; | ||
352 | |||
353 | /* Handle close in-progress */ | ||
354 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) | ||
355 | goto process; | ||
356 | |||
357 | /* Check if we have space to reply to a request */ | ||
358 | if (!xprt->xpt_ops->xpo_has_wspace(xprt)) { | ||
359 | /* Don't enqueue while not enough space for reply */ | ||
360 | dprintk("svc: no write space, transport %p not enqueued\n", | ||
361 | xprt); | ||
362 | xprt->xpt_pool = NULL; | ||
363 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | ||
364 | goto out_unlock; | ||
365 | } | ||
366 | 358 | ||
367 | process: | ||
368 | if (!list_empty(&pool->sp_threads)) { | 359 | if (!list_empty(&pool->sp_threads)) { |
369 | rqstp = list_entry(pool->sp_threads.next, | 360 | rqstp = list_entry(pool->sp_threads.next, |
370 | struct svc_rqst, | 361 | struct svc_rqst, |
@@ -381,13 +372,11 @@ void svc_xprt_enqueue(struct svc_xprt *xprt) | |||
381 | rqstp->rq_reserved = serv->sv_max_mesg; | 372 | rqstp->rq_reserved = serv->sv_max_mesg; |
382 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); | 373 | atomic_add(rqstp->rq_reserved, &xprt->xpt_reserved); |
383 | pool->sp_stats.threads_woken++; | 374 | pool->sp_stats.threads_woken++; |
384 | BUG_ON(xprt->xpt_pool != pool); | ||
385 | wake_up(&rqstp->rq_wait); | 375 | wake_up(&rqstp->rq_wait); |
386 | } else { | 376 | } else { |
387 | dprintk("svc: transport %p put into queue\n", xprt); | 377 | dprintk("svc: transport %p put into queue\n", xprt); |
388 | list_add_tail(&xprt->xpt_ready, &pool->sp_sockets); | 378 | list_add_tail(&xprt->xpt_ready, &pool->sp_sockets); |
389 | pool->sp_stats.sockets_queued++; | 379 | pool->sp_stats.sockets_queued++; |
390 | BUG_ON(xprt->xpt_pool != pool); | ||
391 | } | 380 | } |
392 | 381 | ||
393 | out_unlock: | 382 | out_unlock: |
@@ -426,7 +415,6 @@ static struct svc_xprt *svc_xprt_dequeue(struct svc_pool *pool) | |||
426 | void svc_xprt_received(struct svc_xprt *xprt) | 415 | void svc_xprt_received(struct svc_xprt *xprt) |
427 | { | 416 | { |
428 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); | 417 | BUG_ON(!test_bit(XPT_BUSY, &xprt->xpt_flags)); |
429 | xprt->xpt_pool = NULL; | ||
430 | /* As soon as we clear busy, the xprt could be closed and | 418 | /* As soon as we clear busy, the xprt could be closed and |
431 | * 'put', so we need a reference to call svc_xprt_enqueue with: | 419 | * 'put', so we need a reference to call svc_xprt_enqueue with: |
432 | */ | 420 | */ |
@@ -722,7 +710,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
722 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { | 710 | if (test_bit(XPT_CLOSE, &xprt->xpt_flags)) { |
723 | dprintk("svc_recv: found XPT_CLOSE\n"); | 711 | dprintk("svc_recv: found XPT_CLOSE\n"); |
724 | svc_delete_xprt(xprt); | 712 | svc_delete_xprt(xprt); |
725 | } else if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { | 713 | /* Leave XPT_BUSY set on the dead xprt: */ |
714 | goto out; | ||
715 | } | ||
716 | if (test_bit(XPT_LISTENER, &xprt->xpt_flags)) { | ||
726 | struct svc_xprt *newxpt; | 717 | struct svc_xprt *newxpt; |
727 | newxpt = xprt->xpt_ops->xpo_accept(xprt); | 718 | newxpt = xprt->xpt_ops->xpo_accept(xprt); |
728 | if (newxpt) { | 719 | if (newxpt) { |
@@ -747,28 +738,23 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
747 | spin_unlock_bh(&serv->sv_lock); | 738 | spin_unlock_bh(&serv->sv_lock); |
748 | svc_xprt_received(newxpt); | 739 | svc_xprt_received(newxpt); |
749 | } | 740 | } |
750 | svc_xprt_received(xprt); | 741 | } else if (xprt->xpt_ops->xpo_has_wspace(xprt)) { |
751 | } else { | ||
752 | dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", | 742 | dprintk("svc: server %p, pool %u, transport %p, inuse=%d\n", |
753 | rqstp, pool->sp_id, xprt, | 743 | rqstp, pool->sp_id, xprt, |
754 | atomic_read(&xprt->xpt_ref.refcount)); | 744 | atomic_read(&xprt->xpt_ref.refcount)); |
755 | rqstp->rq_deferred = svc_deferred_dequeue(xprt); | 745 | rqstp->rq_deferred = svc_deferred_dequeue(xprt); |
756 | if (rqstp->rq_deferred) { | 746 | if (rqstp->rq_deferred) |
757 | svc_xprt_received(xprt); | ||
758 | len = svc_deferred_recv(rqstp); | 747 | len = svc_deferred_recv(rqstp); |
759 | } else { | 748 | else |
760 | len = xprt->xpt_ops->xpo_recvfrom(rqstp); | 749 | len = xprt->xpt_ops->xpo_recvfrom(rqstp); |
761 | svc_xprt_received(xprt); | ||
762 | } | ||
763 | dprintk("svc: got len=%d\n", len); | 750 | dprintk("svc: got len=%d\n", len); |
764 | } | 751 | } |
752 | svc_xprt_received(xprt); | ||
765 | 753 | ||
766 | /* No data, incomplete (TCP) read, or accept() */ | 754 | /* No data, incomplete (TCP) read, or accept() */ |
767 | if (len == 0 || len == -EAGAIN) { | 755 | if (len == 0 || len == -EAGAIN) |
768 | rqstp->rq_res.len = 0; | 756 | goto out; |
769 | svc_xprt_release(rqstp); | 757 | |
770 | return -EAGAIN; | ||
771 | } | ||
772 | clear_bit(XPT_OLD, &xprt->xpt_flags); | 758 | clear_bit(XPT_OLD, &xprt->xpt_flags); |
773 | 759 | ||
774 | rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp)); | 760 | rqstp->rq_secure = svc_port_is_privileged(svc_addr(rqstp)); |
@@ -777,6 +763,10 @@ int svc_recv(struct svc_rqst *rqstp, long timeout) | |||
777 | if (serv->sv_stats) | 763 | if (serv->sv_stats) |
778 | serv->sv_stats->netcnt++; | 764 | serv->sv_stats->netcnt++; |
779 | return len; | 765 | return len; |
766 | out: | ||
767 | rqstp->rq_res.len = 0; | ||
768 | svc_xprt_release(rqstp); | ||
769 | return -EAGAIN; | ||
780 | } | 770 | } |
781 | EXPORT_SYMBOL_GPL(svc_recv); | 771 | EXPORT_SYMBOL_GPL(svc_recv); |
782 | 772 | ||
@@ -935,7 +925,12 @@ void svc_close_xprt(struct svc_xprt *xprt) | |||
935 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) | 925 | if (test_and_set_bit(XPT_BUSY, &xprt->xpt_flags)) |
936 | /* someone else will have to effect the close */ | 926 | /* someone else will have to effect the close */ |
937 | return; | 927 | return; |
938 | 928 | /* | |
929 | * We expect svc_close_xprt() to work even when no threads are | ||
930 | * running (e.g., while configuring the server before starting | ||
931 | * any threads), so if the transport isn't busy, we delete | ||
932 | * it ourself: | ||
933 | */ | ||
939 | svc_delete_xprt(xprt); | 934 | svc_delete_xprt(xprt); |
940 | } | 935 | } |
941 | EXPORT_SYMBOL_GPL(svc_close_xprt); | 936 | EXPORT_SYMBOL_GPL(svc_close_xprt); |
@@ -945,16 +940,16 @@ void svc_close_all(struct list_head *xprt_list) | |||
945 | struct svc_xprt *xprt; | 940 | struct svc_xprt *xprt; |
946 | struct svc_xprt *tmp; | 941 | struct svc_xprt *tmp; |
947 | 942 | ||
943 | /* | ||
944 | * The server is shutting down, and no more threads are running. | ||
945 | * svc_xprt_enqueue() might still be running, but at worst it | ||
946 | * will re-add the xprt to sp_sockets, which will soon get | ||
947 | * freed. So we don't bother with any more locking, and don't | ||
948 | * leave the close to the (nonexistent) server threads: | ||
949 | */ | ||
948 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { | 950 | list_for_each_entry_safe(xprt, tmp, xprt_list, xpt_list) { |
949 | set_bit(XPT_CLOSE, &xprt->xpt_flags); | 951 | set_bit(XPT_CLOSE, &xprt->xpt_flags); |
950 | if (test_bit(XPT_BUSY, &xprt->xpt_flags)) { | 952 | svc_delete_xprt(xprt); |
951 | /* Waiting to be processed, but no threads left, | ||
952 | * So just remove it from the waiting list | ||
953 | */ | ||
954 | list_del_init(&xprt->xpt_ready); | ||
955 | clear_bit(XPT_BUSY, &xprt->xpt_flags); | ||
956 | } | ||
957 | svc_close_xprt(xprt); | ||
958 | } | 953 | } |
959 | } | 954 | } |
960 | 955 | ||
@@ -1028,6 +1023,7 @@ static struct cache_deferred_req *svc_defer(struct cache_req *req) | |||
1028 | } | 1023 | } |
1029 | svc_xprt_get(rqstp->rq_xprt); | 1024 | svc_xprt_get(rqstp->rq_xprt); |
1030 | dr->xprt = rqstp->rq_xprt; | 1025 | dr->xprt = rqstp->rq_xprt; |
1026 | rqstp->rq_dropme = true; | ||
1031 | 1027 | ||
1032 | dr->handle.revisit = svc_revisit; | 1028 | dr->handle.revisit = svc_revisit; |
1033 | return &dr->handle; | 1029 | return &dr->handle; |
@@ -1065,14 +1061,13 @@ static struct svc_deferred_req *svc_deferred_dequeue(struct svc_xprt *xprt) | |||
1065 | if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags)) | 1061 | if (!test_bit(XPT_DEFERRED, &xprt->xpt_flags)) |
1066 | return NULL; | 1062 | return NULL; |
1067 | spin_lock(&xprt->xpt_lock); | 1063 | spin_lock(&xprt->xpt_lock); |
1068 | clear_bit(XPT_DEFERRED, &xprt->xpt_flags); | ||
1069 | if (!list_empty(&xprt->xpt_deferred)) { | 1064 | if (!list_empty(&xprt->xpt_deferred)) { |
1070 | dr = list_entry(xprt->xpt_deferred.next, | 1065 | dr = list_entry(xprt->xpt_deferred.next, |
1071 | struct svc_deferred_req, | 1066 | struct svc_deferred_req, |
1072 | handle.recent); | 1067 | handle.recent); |
1073 | list_del_init(&dr->handle.recent); | 1068 | list_del_init(&dr->handle.recent); |
1074 | set_bit(XPT_DEFERRED, &xprt->xpt_flags); | 1069 | } else |
1075 | } | 1070 | clear_bit(XPT_DEFERRED, &xprt->xpt_flags); |
1076 | spin_unlock(&xprt->xpt_lock); | 1071 | spin_unlock(&xprt->xpt_lock); |
1077 | return dr; | 1072 | return dr; |
1078 | } | 1073 | } |