rxrpc: Copy client call parameters into rxrpc_call earlier
authorDavid Howells <dhowells@redhat.com>
Thu, 20 Oct 2022 20:58:36 +0000 (21:58 +0100)
committerDavid Howells <dhowells@redhat.com>
Thu, 1 Dec 2022 13:36:41 +0000 (13:36 +0000)
Copy client call parameters into rxrpc_call earlier so that that can be
used to convey them to the connection code - which can then be offloaded to
the I/O thread.

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org

include/trace/events/rxrpc.h
net/rxrpc/ar-internal.h
net/rxrpc/call_accept.c
net/rxrpc/call_object.c
net/rxrpc/conn_client.c
net/rxrpc/io_thread.c
net/rxrpc/output.c
net/rxrpc/proc.c
net/rxrpc/recvmsg.c
net/rxrpc/security.c
net/rxrpc/txbuf.c

index 0b12d96..8bd4835 100644 (file)
@@ -52,6 +52,7 @@
 
 #define rxrpc_local_traces \
        EM(rxrpc_local_free,                    "FREE        ") \
+       EM(rxrpc_local_get_call,                "GET call    ") \
        EM(rxrpc_local_get_client_conn,         "GET conn-cln") \
        EM(rxrpc_local_get_for_use,             "GET for-use ") \
        EM(rxrpc_local_get_peer,                "GET peer    ") \
@@ -61,6 +62,7 @@
        EM(rxrpc_local_processing,              "PROCESSING  ") \
        EM(rxrpc_local_put_already_queued,      "PUT alreadyq") \
        EM(rxrpc_local_put_bind,                "PUT bind    ") \
+       EM(rxrpc_local_put_call,                "PUT call    ") \
        EM(rxrpc_local_put_for_use,             "PUT for-use ") \
        EM(rxrpc_local_put_kill_conn,           "PUT conn-kil") \
        EM(rxrpc_local_put_peer,                "PUT peer    ") \
        EM(rxrpc_call_new_client,               "NEW client  ") \
        EM(rxrpc_call_new_prealloc_service,     "NEW prealloc") \
        EM(rxrpc_call_put_discard_prealloc,     "PUT disc-pre") \
+       EM(rxrpc_call_put_discard_error,        "PUT disc-err") \
        EM(rxrpc_call_put_input,                "PUT input   ") \
        EM(rxrpc_call_put_kernel,               "PUT kernel  ") \
        EM(rxrpc_call_put_poke,                 "PUT poke    ") \
index a80655f..3bd6a5e 100644 (file)
@@ -530,6 +530,7 @@ enum rxrpc_call_flag {
        RXRPC_CALL_UPGRADE,             /* Service upgrade was requested for the call */
        RXRPC_CALL_DELAY_ACK_PENDING,   /* DELAY ACK generation is pending */
        RXRPC_CALL_IDLE_ACK_PENDING,    /* IDLE ACK generation is pending */
+       RXRPC_CALL_EXCLUSIVE,           /* The call uses a once-only connection */
 };
 
 /*
@@ -592,10 +593,13 @@ struct rxrpc_call {
        struct rcu_head         rcu;
        struct rxrpc_connection *conn;          /* connection carrying call */
        struct rxrpc_peer       *peer;          /* Peer record for remote address */
+       struct rxrpc_local      *local;         /* Representation of local endpoint */
        struct rxrpc_sock __rcu *socket;        /* socket responsible */
        struct rxrpc_net        *rxnet;         /* Network namespace to which call belongs */
+       struct key              *key;           /* Security details */
        const struct rxrpc_security *security;  /* applied security module */
        struct mutex            user_mutex;     /* User access mutex */
+       struct sockaddr_rxrpc   dest_srx;       /* Destination address */
        unsigned long           delay_ack_at;   /* When DELAY ACK needs to happen */
        unsigned long           ack_lost_at;    /* When ACK is figured as lost */
        unsigned long           resend_at;      /* When next resend needs to happen */
@@ -631,11 +635,11 @@ struct rxrpc_call {
        enum rxrpc_call_state   state;          /* current state of call */
        enum rxrpc_call_completion completion;  /* Call completion condition */
        refcount_t              ref;
-       u16                     service_id;     /* service ID */
        u8                      security_ix;    /* Security type */
        enum rxrpc_interruptibility interruptibility; /* At what point call may be interrupted */
        u32                     call_id;        /* call ID on connection  */
        u32                     cid;            /* connection ID plus channel index */
+       u32                     security_level; /* Security level selected */
        int                     debug_id;       /* debug ID for printks */
        unsigned short          rx_pkt_offset;  /* Current recvmsg packet offset */
        unsigned short          rx_pkt_len;     /* Current recvmsg packet len */
@@ -1147,6 +1151,7 @@ extern const struct rxrpc_security rxkad;
 int __init rxrpc_init_security(void);
 const struct rxrpc_security *rxrpc_security_lookup(u8);
 void rxrpc_exit_security(void);
+int rxrpc_init_client_call_security(struct rxrpc_call *);
 int rxrpc_init_client_conn_security(struct rxrpc_connection *);
 const struct rxrpc_security *rxrpc_get_incoming_security(struct rxrpc_sock *,
                                                         struct sk_buff *);
index 8d106b6..8bc327a 100644 (file)
@@ -318,10 +318,12 @@ static struct rxrpc_call *rxrpc_alloc_incoming_call(struct rxrpc_sock *rx,
                          (call_tail + 1) & (RXRPC_BACKLOG_MAX - 1));
 
        rxrpc_see_call(call, rxrpc_call_see_accept);
+       call->local = rxrpc_get_local(conn->local, rxrpc_local_get_call);
        call->conn = conn;
        call->security = conn->security;
        call->security_ix = conn->security_ix;
        call->peer = rxrpc_get_peer(conn->peer, rxrpc_peer_get_accept);
+       call->dest_srx = peer->srx;
        call->cong_ssthresh = call->peer->cong_ssthresh;
        call->tx_last_sent = ktime_get_real();
        return call;
index 997641e..2622d06 100644 (file)
@@ -47,14 +47,9 @@ static struct semaphore rxrpc_kernel_call_limiter =
 
 void rxrpc_poke_call(struct rxrpc_call *call, enum rxrpc_call_poke_trace what)
 {
-       struct rxrpc_local *local;
-       struct rxrpc_peer *peer = call->peer;
+       struct rxrpc_local *local = call->local;
        bool busy;
 
-       if (WARN_ON_ONCE(!peer))
-               return;
-       local = peer->local;
-
        if (call->state < RXRPC_CALL_COMPLETE) {
                spin_lock_bh(&local->lock);
                busy = !list_empty(&call->attend_link);
@@ -200,22 +195,45 @@ struct rxrpc_call *rxrpc_alloc_call(struct rxrpc_sock *rx, gfp_t gfp,
  */
 static struct rxrpc_call *rxrpc_alloc_client_call(struct rxrpc_sock *rx,
                                                  struct sockaddr_rxrpc *srx,
+                                                 struct rxrpc_conn_parameters *cp,
+                                                 struct rxrpc_call_params *p,
                                                  gfp_t gfp,
                                                  unsigned int debug_id)
 {
        struct rxrpc_call *call;
        ktime_t now;
+       int ret;
 
        _enter("");
 
        call = rxrpc_alloc_call(rx, gfp, debug_id);
        if (!call)
                return ERR_PTR(-ENOMEM);
-       call->state = RXRPC_CALL_CLIENT_AWAIT_CONN;
-       call->service_id = srx->srx_service;
        now = ktime_get_real();
-       call->acks_latest_ts = now;
-       call->cong_tstamp = now;
+       call->acks_latest_ts    = now;
+       call->cong_tstamp       = now;
+       call->state             = RXRPC_CALL_CLIENT_AWAIT_CONN;
+       call->dest_srx          = *srx;
+       call->interruptibility  = p->interruptibility;
+       call->tx_total_len      = p->tx_total_len;
+       call->key               = key_get(cp->key);
+       call->local             = rxrpc_get_local(cp->local, rxrpc_local_get_call);
+       if (p->kernel)
+               __set_bit(RXRPC_CALL_KERNEL, &call->flags);
+       if (cp->upgrade)
+               __set_bit(RXRPC_CALL_UPGRADE, &call->flags);
+       if (cp->exclusive)
+               __set_bit(RXRPC_CALL_EXCLUSIVE, &call->flags);
+
+       ret = rxrpc_init_client_call_security(call);
+       if (ret < 0) {
+               __rxrpc_set_call_completion(call, RXRPC_CALL_LOCAL_ERROR, 0, ret);
+               rxrpc_put_call(call, rxrpc_call_put_discard_error);
+               return ERR_PTR(ret);
+       }
+
+       trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
+                        p->user_call_ID, rxrpc_call_new_client);
 
        _leave(" = %p", call);
        return call;
@@ -295,7 +313,7 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
                return ERR_PTR(-ERESTARTSYS);
        }
 
-       call = rxrpc_alloc_client_call(rx, srx, gfp, debug_id);
+       call = rxrpc_alloc_client_call(rx, srx, cp, p, gfp, debug_id);
        if (IS_ERR(call)) {
                release_sock(&rx->sk);
                up(limiter);
@@ -303,13 +321,6 @@ struct rxrpc_call *rxrpc_new_client_call(struct rxrpc_sock *rx,
                return call;
        }
 
-       call->interruptibility = p->interruptibility;
-       call->tx_total_len = p->tx_total_len;
-       trace_rxrpc_call(call->debug_id, refcount_read(&call->ref),
-                        p->user_call_ID, rxrpc_call_new_client);
-       if (p->kernel)
-               __set_bit(RXRPC_CALL_KERNEL, &call->flags);
-
        /* We need to protect a partially set up call against the user as we
         * will be acting outside the socket lock.
         */
@@ -413,7 +424,7 @@ void rxrpc_incoming_call(struct rxrpc_sock *rx,
 
        rcu_assign_pointer(call->socket, rx);
        call->call_id           = sp->hdr.callNumber;
-       call->service_id        = sp->hdr.serviceId;
+       call->dest_srx.srx_service = sp->hdr.serviceId;
        call->cid               = sp->hdr.cid;
        call->state             = RXRPC_CALL_SERVER_SECURING;
        call->cong_tstamp       = skb->tstamp;
@@ -639,6 +650,7 @@ static void rxrpc_destroy_call(struct work_struct *work)
        rxrpc_free_skb(call->acks_soft_tbl, rxrpc_skb_put_ack);
        rxrpc_put_connection(call->conn, rxrpc_conn_put_call);
        rxrpc_put_peer(call->peer, rxrpc_peer_put_call);
+       rxrpc_put_local(call->local, rxrpc_local_put_call);
        call_rcu(&call->rcu, rxrpc_rcu_free_call);
 }
 
index 9485a3d..ab3dd22 100644 (file)
@@ -553,7 +553,7 @@ static void rxrpc_activate_one_channel(struct rxrpc_connection *conn,
        call->call_id   = call_id;
        call->security  = conn->security;
        call->security_ix = conn->security_ix;
-       call->service_id = conn->service_id;
+       call->dest_srx.srx_service = conn->service_id;
 
        trace_rxrpc_connect_call(call);
 
index cc249bc..2119941 100644 (file)
@@ -343,8 +343,8 @@ static int rxrpc_input_packet(struct rxrpc_local *local, struct sk_buff *skb)
                }
 
                if (call) {
-                       if (sp->hdr.serviceId != call->service_id)
-                               call->service_id = sp->hdr.serviceId;
+                       if (sp->hdr.serviceId != call->dest_srx.srx_service)
+                               call->dest_srx.srx_service = sp->hdr.serviceId;
                        if ((int)sp->hdr.serial - (int)call->rx_serial > 0)
                                call->rx_serial = sp->hdr.serial;
                        if (!test_bit(RXRPC_CALL_RX_HEARD, &call->flags))
index 131c7a7..e2ce7da 100644 (file)
@@ -357,7 +357,7 @@ int rxrpc_send_abort_packet(struct rxrpc_call *call)
        pkt.whdr.userStatus     = 0;
        pkt.whdr.securityIndex  = call->security_ix;
        pkt.whdr._rsvd          = 0;
-       pkt.whdr.serviceId      = htons(call->service_id);
+       pkt.whdr.serviceId      = htons(call->dest_srx.srx_service);
        pkt.abort_code          = htonl(call->abort_code);
 
        iov[0].iov_base = &pkt;
index 35d5b43..5af7c8e 100644 (file)
@@ -49,8 +49,6 @@ static void rxrpc_call_seq_stop(struct seq_file *seq, void *v)
 static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
 {
        struct rxrpc_local *local;
-       struct rxrpc_sock *rx;
-       struct rxrpc_peer *peer;
        struct rxrpc_call *call;
        struct rxrpc_net *rxnet = rxrpc_net(seq_file_net(seq));
        unsigned long timeout = 0;
@@ -69,22 +67,13 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
 
        call = list_entry(v, struct rxrpc_call, link);
 
-       rx = rcu_dereference(call->socket);
-       if (rx) {
-               local = READ_ONCE(rx->local);
-               if (local)
-                       sprintf(lbuff, "%pISpc", &local->srx.transport);
-               else
-                       strcpy(lbuff, "no_local");
-       } else {
-               strcpy(lbuff, "no_socket");
-       }
-
-       peer = call->peer;
-       if (peer)
-               sprintf(rbuff, "%pISpc", &peer->srx.transport);
+       local = call->local;
+       if (local)
+               sprintf(lbuff, "%pISpc", &local->srx.transport);
        else
-               strcpy(rbuff, "no_connection");
+               strcpy(lbuff, "no_local");
+
+       sprintf(rbuff, "%pISpc", &call->dest_srx.transport);
 
        if (call->state != RXRPC_CALL_SERVER_PREALLOC) {
                timeout = READ_ONCE(call->expect_rx_by);
@@ -98,7 +87,7 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v)
                   " %-8.8s %08x %08x %08x %02x %08x %02x %08x %06lx\n",
                   lbuff,
                   rbuff,
-                  call->service_id,
+                  call->dest_srx.srx_service,
                   call->cid,
                   call->call_id,
                   rxrpc_is_service_call(call) ? "Svc" : "Clt",
index bfac9e0..5df7f46 100644 (file)
@@ -490,11 +490,9 @@ try_again:
        }
 
        if (msg->msg_name && call->peer) {
-               struct sockaddr_rxrpc *srx = msg->msg_name;
-               size_t len = sizeof(call->peer->srx);
+               size_t len = sizeof(call->dest_srx);
 
-               memcpy(msg->msg_name, &call->peer->srx, len);
-               srx->srx_service = call->service_id;
+               memcpy(msg->msg_name, &call->dest_srx, len);
                msg->msg_namelen = len;
        }
 
@@ -639,7 +637,7 @@ read_phase_complete:
 out:
        rxrpc_transmit_ack_packets(call->peer->local);
        if (_service)
-               *_service = call->service_id;
+               *_service = call->dest_srx.srx_service;
        mutex_unlock(&call->user_mutex);
        _leave(" = %d [%zu,%d]", ret, iov_iter_count(iter), *_abort);
        return ret;
index e6ddac9..209f2c2 100644 (file)
@@ -62,6 +62,36 @@ const struct rxrpc_security *rxrpc_security_lookup(u8 security_index)
        return rxrpc_security_types[security_index];
 }
 
+/*
+ * Initialise the security on a client call.
+ */
+int rxrpc_init_client_call_security(struct rxrpc_call *call)
+{
+       const struct rxrpc_security *sec;
+       struct rxrpc_key_token *token;
+       struct key *key = call->key;
+       int ret;
+
+       if (!key)
+               return 0;
+
+       ret = key_validate(key);
+       if (ret < 0)
+               return ret;
+
+       for (token = key->payload.data[0]; token; token = token->next) {
+               sec = rxrpc_security_lookup(token->security_index);
+               if (sec)
+                       goto found;
+       }
+       return -EKEYREJECTED;
+
+found:
+       call->security = sec;
+       _leave(" = 0");
+       return 0;
+}
+
 /*
  * initialise the security on a client connection
  */
index f93dc66..90ff00c 100644 (file)
@@ -44,7 +44,7 @@ struct rxrpc_txbuf *rxrpc_alloc_txbuf(struct rxrpc_call *call, u8 packet_type,
                txb->wire.userStatus    = 0;
                txb->wire.securityIndex = call->security_ix;
                txb->wire._rsvd         = 0;
-               txb->wire.serviceId     = htons(call->service_id);
+               txb->wire.serviceId     = htons(call->dest_srx.srx_service);
 
                trace_rxrpc_txbuf(txb->debug_id,
                                  txb->call_debug_id, txb->seq, 1,