rxrpc: Allow listen(sock, 0) to be used to disable listening
authorDavid Howells <dhowells@redhat.com>
Thu, 5 Jan 2017 10:38:36 +0000 (10:38 +0000)
committerDavid Howells <dhowells@redhat.com>
Mon, 9 Jan 2017 11:10:02 +0000 (11:10 +0000)
Allow listen() with a backlog of 0 to be used to disable listening on an
AF_RXRPC socket.  This also releases any preallocation, thereby making it
easier for a kernel service to account for all allocated call structures
when shutting down the service.

The socket cannot thereafter have listening reenabled, but must rather be
closed and reopened.

Signed-off-by: David Howells <dhowells@redhat.com>
net/rxrpc/af_rxrpc.c
net/rxrpc/ar-internal.h
net/rxrpc/call_accept.c

index 5f63f6dcaabb6422306895f01ff7dc3f0de8ee60..199b46e93e64ee7786e8a8d441ba5eb5b02bf31f 100644 (file)
@@ -224,6 +224,14 @@ static int rxrpc_listen(struct socket *sock, int backlog)
                else
                        sk->sk_max_ack_backlog = old;
                break;
+       case RXRPC_SERVER_LISTENING:
+               if (backlog == 0) {
+                       rx->sk.sk_state = RXRPC_SERVER_LISTEN_DISABLED;
+                       sk->sk_max_ack_backlog = 0;
+                       rxrpc_discard_prealloc(rx);
+                       ret = 0;
+                       break;
+               }
        default:
                ret = -EBUSY;
                break;
index 84927c7b5fdf0ffa2f67611bab60ab5089d83d7e..12be432be9b2feb5dc9a85716c676888599b5624 100644 (file)
@@ -60,6 +60,7 @@ enum {
        RXRPC_CLIENT_BOUND,             /* client local address bound */
        RXRPC_SERVER_BOUND,             /* server local address bound */
        RXRPC_SERVER_LISTENING,         /* server listening for connections */
+       RXRPC_SERVER_LISTEN_DISABLED,   /* server listening disabled */
        RXRPC_CLOSE,                    /* socket is being closed */
 };
 
index 832d854c2d5c409faa0e487ea9b3bac709d4031b..7c4c64ab8da2e241d63ee16a0ae3521c98dc2e5c 100644 (file)
@@ -349,7 +349,8 @@ struct rxrpc_call *rxrpc_new_incoming_call(struct rxrpc_local *local,
 
 found_service:
        spin_lock(&rx->incoming_lock);
-       if (rx->sk.sk_state == RXRPC_CLOSE) {
+       if (rx->sk.sk_state == RXRPC_SERVER_LISTEN_DISABLED ||
+           rx->sk.sk_state == RXRPC_CLOSE) {
                trace_rxrpc_abort("CLS", sp->hdr.cid, sp->hdr.callNumber,
                                  sp->hdr.seq, RX_INVALID_OPERATION, ESHUTDOWN);
                skb->mark = RXRPC_SKB_MARK_LOCAL_ABORT;