Merge tag 'for-linus-4.15-ofs1' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / net / rxrpc / af_rxrpc.c
index 4b0a8288c98a65195519f60f5162422b6040e9c6..9b5c46b052fd07cb9ee82cea6fef0be3e32ffb4e 100644 (file)
@@ -246,6 +246,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
                        ret = 0;
                        break;
                }
+               /* Fall through */
        default:
                ret = -EBUSY;
                break;
@@ -265,6 +266,7 @@ static int rxrpc_listen(struct socket *sock, int backlog)
  * @tx_total_len: Total length of data to transmit during the call (or -1)
  * @gfp: The allocation constraints
  * @notify_rx: Where to send notifications instead of socket queue
+ * @upgrade: Request service upgrade for call
  *
  * Allow a kernel service to begin a call on the nominated socket.  This just
  * sets up all the internal tracking structures and allocates connection and
@@ -279,7 +281,8 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
                                           unsigned long user_call_ID,
                                           s64 tx_total_len,
                                           gfp_t gfp,
-                                          rxrpc_notify_rx_t notify_rx)
+                                          rxrpc_notify_rx_t notify_rx,
+                                          bool upgrade)
 {
        struct rxrpc_conn_parameters cp;
        struct rxrpc_call *call;
@@ -304,6 +307,7 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
        cp.key                  = key;
        cp.security_level       = 0;
        cp.exclusive            = false;
+       cp.upgrade              = upgrade;
        cp.service_id           = srx->srx_service;
        call = rxrpc_new_client_call(rx, &cp, srx, user_call_ID, tx_total_len,
                                     gfp);
@@ -318,6 +322,14 @@ struct rxrpc_call *rxrpc_kernel_begin_call(struct socket *sock,
 }
 EXPORT_SYMBOL(rxrpc_kernel_begin_call);
 
+/*
+ * Dummy function used to stop the notifier talking to recvmsg().
+ */
+static void rxrpc_dummy_notify_rx(struct sock *sk, struct rxrpc_call *rxcall,
+                                 unsigned long call_user_ID)
+{
+}
+
 /**
  * rxrpc_kernel_end_call - Allow a kernel service to end a call it was using
  * @sock: The socket the call is on
@@ -332,11 +344,38 @@ void rxrpc_kernel_end_call(struct socket *sock, struct rxrpc_call *call)
 
        mutex_lock(&call->user_mutex);
        rxrpc_release_call(rxrpc_sk(sock->sk), call);
+
+       /* Make sure we're not going to call back into a kernel service */
+       if (call->notify_rx) {
+               spin_lock_bh(&call->notify_lock);
+               call->notify_rx = rxrpc_dummy_notify_rx;
+               spin_unlock_bh(&call->notify_lock);
+       }
+
        mutex_unlock(&call->user_mutex);
        rxrpc_put_call(call, rxrpc_call_put_kernel);
 }
 EXPORT_SYMBOL(rxrpc_kernel_end_call);
 
+/**
+ * rxrpc_kernel_check_life - Check to see whether a call is still alive
+ * @sock: The socket the call is on
+ * @call: The call to check
+ *
+ * Allow a kernel service to find out whether a call is still alive - ie. we're
+ * getting ACKs from the server.  Returns a number representing the life state
+ * which can be compared to that returned by a previous call.
+ *
+ * If this is a client call, ping ACKs will be sent to the server to find out
+ * whether it's still responsive and whether the call is still alive on the
+ * server.
+ */
+u32 rxrpc_kernel_check_life(struct socket *sock, struct rxrpc_call *call)
+{
+       return call->acks_latest;
+}
+EXPORT_SYMBOL(rxrpc_kernel_check_life);
+
 /**
  * rxrpc_kernel_check_call - Check a call's state
  * @sock: The socket the call is on
@@ -538,6 +577,7 @@ static int rxrpc_sendmsg(struct socket *sock, struct msghdr *m, size_t len)
                        m->msg_name = &rx->connect_srx;
                        m->msg_namelen = sizeof(rx->connect_srx);
                }
+               /* Fall through */
        case RXRPC_SERVER_BOUND:
        case RXRPC_SERVER_LISTENING:
                ret = rxrpc_do_sendmsg(rx, m, len);