diff options
-rw-r--r-- | include/linux/sunrpc/svcsock.h | 2 | ||||
-rw-r--r-- | net/sunrpc/svc.c | 4 | ||||
-rw-r--r-- | net/sunrpc/svcsock.c | 52 |
3 files changed, 41 insertions, 17 deletions
diff --git a/include/linux/sunrpc/svcsock.h b/include/linux/sunrpc/svcsock.h index 98b21ad370fd..db312a1e2eeb 100644 --- a/include/linux/sunrpc/svcsock.h +++ b/include/linux/sunrpc/svcsock.h | |||
@@ -63,7 +63,7 @@ struct svc_sock { | |||
63 | * Function prototypes. | 63 | * Function prototypes. |
64 | */ | 64 | */ |
65 | int svc_makesock(struct svc_serv *, int, unsigned short); | 65 | int svc_makesock(struct svc_serv *, int, unsigned short); |
66 | void svc_delete_socket(struct svc_sock *); | 66 | void svc_close_socket(struct svc_sock *); |
67 | int svc_recv(struct svc_rqst *, long); | 67 | int svc_recv(struct svc_rqst *, long); |
68 | int svc_send(struct svc_rqst *); | 68 | int svc_send(struct svc_rqst *); |
69 | void svc_drop(struct svc_rqst *); | 69 | void svc_drop(struct svc_rqst *); |
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c index 4c1611211119..c1f878131ac6 100644 --- a/net/sunrpc/svc.c +++ b/net/sunrpc/svc.c | |||
@@ -386,7 +386,7 @@ svc_destroy(struct svc_serv *serv) | |||
386 | svsk = list_entry(serv->sv_tempsocks.next, | 386 | svsk = list_entry(serv->sv_tempsocks.next, |
387 | struct svc_sock, | 387 | struct svc_sock, |
388 | sk_list); | 388 | sk_list); |
389 | svc_delete_socket(svsk); | 389 | svc_close_socket(svsk); |
390 | } | 390 | } |
391 | if (serv->sv_shutdown) | 391 | if (serv->sv_shutdown) |
392 | serv->sv_shutdown(serv); | 392 | serv->sv_shutdown(serv); |
@@ -395,7 +395,7 @@ svc_destroy(struct svc_serv *serv) | |||
395 | svsk = list_entry(serv->sv_permsocks.next, | 395 | svsk = list_entry(serv->sv_permsocks.next, |
396 | struct svc_sock, | 396 | struct svc_sock, |
397 | sk_list); | 397 | sk_list); |
398 | svc_delete_socket(svsk); | 398 | svc_close_socket(svsk); |
399 | } | 399 | } |
400 | 400 | ||
401 | cache_clean_deferred(serv); | 401 | cache_clean_deferred(serv); |
diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index ff1f8bf680aa..cf93cd1d857b 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c | |||
@@ -62,6 +62,12 @@ | |||
62 | * after a clear, the socket must be read/accepted | 62 | * after a clear, the socket must be read/accepted |
63 | * if this succeeds, it must be set again. | 63 | * if this succeeds, it must be set again. |
64 | * SK_CLOSE can set at any time. It is never cleared. | 64 | * SK_CLOSE can set at any time. It is never cleared. |
65 | * sk_inuse contains a bias of '1' until SK_DEAD is set. | ||
66 | * so when sk_inuse hits zero, we know the socket is dead | ||
67 | * and no-one is using it. | ||
68 | * SK_DEAD can only be set while SK_BUSY is held which ensures | ||
69 | * no other thread will be using the socket or will try to | ||
70 | * set SK_DEAD. | ||
65 | * | 71 | * |
66 | */ | 72 | */ |
67 | 73 | ||
@@ -70,6 +76,7 @@ | |||
70 | 76 | ||
71 | static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, | 77 | static struct svc_sock *svc_setup_socket(struct svc_serv *, struct socket *, |
72 | int *errp, int pmap_reg); | 78 | int *errp, int pmap_reg); |
79 | static void svc_delete_socket(struct svc_sock *svsk); | ||
73 | static void svc_udp_data_ready(struct sock *, int); | 80 | static void svc_udp_data_ready(struct sock *, int); |
74 | static int svc_udp_recvfrom(struct svc_rqst *); | 81 | static int svc_udp_recvfrom(struct svc_rqst *); |
75 | static int svc_udp_sendto(struct svc_rqst *); | 82 | static int svc_udp_sendto(struct svc_rqst *); |
@@ -329,8 +336,9 @@ void svc_reserve(struct svc_rqst *rqstp, int space) | |||
329 | static inline void | 336 | static inline void |
330 | svc_sock_put(struct svc_sock *svsk) | 337 | svc_sock_put(struct svc_sock *svsk) |
331 | { | 338 | { |
332 | if (atomic_dec_and_test(&svsk->sk_inuse) && | 339 | if (atomic_dec_and_test(&svsk->sk_inuse)) { |
333 | test_bit(SK_DEAD, &svsk->sk_flags)) { | 340 | BUG_ON(! test_bit(SK_DEAD, &svsk->sk_flags)); |
341 | |||
334 | dprintk("svc: releasing dead socket\n"); | 342 | dprintk("svc: releasing dead socket\n"); |
335 | if (svsk->sk_sock->file) | 343 | if (svsk->sk_sock->file) |
336 | sockfd_put(svsk->sk_sock); | 344 | sockfd_put(svsk->sk_sock); |
@@ -520,7 +528,7 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) | |||
520 | 528 | ||
521 | if (!serv) | 529 | if (!serv) |
522 | return 0; | 530 | return 0; |
523 | spin_lock(&serv->sv_lock); | 531 | spin_lock_bh(&serv->sv_lock); |
524 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { | 532 | list_for_each_entry(svsk, &serv->sv_permsocks, sk_list) { |
525 | int onelen = one_sock_name(buf+len, svsk); | 533 | int onelen = one_sock_name(buf+len, svsk); |
526 | if (toclose && strcmp(toclose, buf+len) == 0) | 534 | if (toclose && strcmp(toclose, buf+len) == 0) |
@@ -528,12 +536,12 @@ svc_sock_names(char *buf, struct svc_serv *serv, char *toclose) | |||
528 | else | 536 | else |
529 | len += onelen; | 537 | len += onelen; |
530 | } | 538 | } |
531 | spin_unlock(&serv->sv_lock); | 539 | spin_unlock_bh(&serv->sv_lock); |
532 | if (closesk) | 540 | if (closesk) |
533 | /* Should unregister with portmap, but you cannot | 541 | /* Should unregister with portmap, but you cannot |
534 | * unregister just one protocol... | 542 | * unregister just one protocol... |
535 | */ | 543 | */ |
536 | svc_delete_socket(closesk); | 544 | svc_close_socket(closesk); |
537 | else if (toclose) | 545 | else if (toclose) |
538 | return -ENOENT; | 546 | return -ENOENT; |
539 | return len; | 547 | return len; |
@@ -683,6 +691,11 @@ svc_udp_recvfrom(struct svc_rqst *rqstp) | |||
683 | return svc_deferred_recv(rqstp); | 691 | return svc_deferred_recv(rqstp); |
684 | } | 692 | } |
685 | 693 | ||
694 | if (test_bit(SK_CLOSE, &svsk->sk_flags)) { | ||
695 | svc_delete_socket(svsk); | ||
696 | return 0; | ||
697 | } | ||
698 | |||
686 | clear_bit(SK_DATA, &svsk->sk_flags); | 699 | clear_bit(SK_DATA, &svsk->sk_flags); |
687 | while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { | 700 | while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) { |
688 | if (err == -EAGAIN) { | 701 | if (err == -EAGAIN) { |
@@ -1176,7 +1189,8 @@ svc_tcp_sendto(struct svc_rqst *rqstp) | |||
1176 | rqstp->rq_sock->sk_server->sv_name, | 1189 | rqstp->rq_sock->sk_server->sv_name, |
1177 | (sent<0)?"got error":"sent only", | 1190 | (sent<0)?"got error":"sent only", |
1178 | sent, xbufp->len); | 1191 | sent, xbufp->len); |
1179 | svc_delete_socket(rqstp->rq_sock); | 1192 | set_bit(SK_CLOSE, &rqstp->rq_sock->sk_flags); |
1193 | svc_sock_enqueue(rqstp->rq_sock); | ||
1180 | sent = -EAGAIN; | 1194 | sent = -EAGAIN; |
1181 | } | 1195 | } |
1182 | return sent; | 1196 | return sent; |
@@ -1495,7 +1509,7 @@ svc_setup_socket(struct svc_serv *serv, struct socket *sock, | |||
1495 | svsk->sk_odata = inet->sk_data_ready; | 1509 | svsk->sk_odata = inet->sk_data_ready; |
1496 | svsk->sk_owspace = inet->sk_write_space; | 1510 | svsk->sk_owspace = inet->sk_write_space; |
1497 | svsk->sk_server = serv; | 1511 | svsk->sk_server = serv; |
1498 | atomic_set(&svsk->sk_inuse, 0); | 1512 | atomic_set(&svsk->sk_inuse, 1); |
1499 | svsk->sk_lastrecv = get_seconds(); | 1513 | svsk->sk_lastrecv = get_seconds(); |
1500 | spin_lock_init(&svsk->sk_defer_lock); | 1514 | spin_lock_init(&svsk->sk_defer_lock); |
1501 | INIT_LIST_HEAD(&svsk->sk_deferred); | 1515 | INIT_LIST_HEAD(&svsk->sk_deferred); |
@@ -1618,7 +1632,7 @@ bummer: | |||
1618 | /* | 1632 | /* |
1619 | * Remove a dead socket | 1633 | * Remove a dead socket |
1620 | */ | 1634 | */ |
1621 | void | 1635 | static void |
1622 | svc_delete_socket(struct svc_sock *svsk) | 1636 | svc_delete_socket(struct svc_sock *svsk) |
1623 | { | 1637 | { |
1624 | struct svc_serv *serv; | 1638 | struct svc_serv *serv; |
@@ -1644,16 +1658,26 @@ svc_delete_socket(struct svc_sock *svsk) | |||
1644 | * while still attached to a queue, the queue itself | 1658 | * while still attached to a queue, the queue itself |
1645 | * is about to be destroyed (in svc_destroy). | 1659 | * is about to be destroyed (in svc_destroy). |
1646 | */ | 1660 | */ |
1647 | if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) | 1661 | if (!test_and_set_bit(SK_DEAD, &svsk->sk_flags)) { |
1662 | BUG_ON(atomic_read(&svsk->sk_inuse)<2); | ||
1663 | atomic_dec(&svsk->sk_inuse); | ||
1648 | if (test_bit(SK_TEMP, &svsk->sk_flags)) | 1664 | if (test_bit(SK_TEMP, &svsk->sk_flags)) |
1649 | serv->sv_tmpcnt--; | 1665 | serv->sv_tmpcnt--; |
1666 | } | ||
1650 | 1667 | ||
1651 | /* This atomic_inc should be needed - svc_delete_socket | ||
1652 | * should have the semantic of dropping a reference. | ||
1653 | * But it doesn't yet.... | ||
1654 | */ | ||
1655 | atomic_inc(&svsk->sk_inuse); | ||
1656 | spin_unlock_bh(&serv->sv_lock); | 1668 | spin_unlock_bh(&serv->sv_lock); |
1669 | } | ||
1670 | |||
1671 | void svc_close_socket(struct svc_sock *svsk) | ||
1672 | { | ||
1673 | set_bit(SK_CLOSE, &svsk->sk_flags); | ||
1674 | if (test_and_set_bit(SK_BUSY, &svsk->sk_flags)) | ||
1675 | /* someone else will have to effect the close */ | ||
1676 | return; | ||
1677 | |||
1678 | atomic_inc(&svsk->sk_inuse); | ||
1679 | svc_delete_socket(svsk); | ||
1680 | clear_bit(SK_BUSY, &svsk->sk_flags); | ||
1657 | svc_sock_put(svsk); | 1681 | svc_sock_put(svsk); |
1658 | } | 1682 | } |
1659 | 1683 | ||