Commit ff734825 authored by David Howells's avatar David Howells

rxrpc: Move error processing into the local endpoint I/O thread

Move the processing of error packets into the local endpoint I/O thread,
leaving the handover from UDP to merely transfer them into the local
endpoint queue.
Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
cc: Marc Dionne <marc.dionne@auristor.com>
cc: linux-afs@lists.infradead.org
parent 446b3e14
...@@ -37,6 +37,7 @@ struct rxrpc_txbuf; ...@@ -37,6 +37,7 @@ struct rxrpc_txbuf;
*/ */
enum rxrpc_skb_mark { enum rxrpc_skb_mark {
RXRPC_SKB_MARK_PACKET, /* Received packet */ RXRPC_SKB_MARK_PACKET, /* Received packet */
RXRPC_SKB_MARK_ERROR, /* Error notification */
RXRPC_SKB_MARK_REJECT_BUSY, /* Reject with BUSY */ RXRPC_SKB_MARK_REJECT_BUSY, /* Reject with BUSY */
RXRPC_SKB_MARK_REJECT_ABORT, /* Reject with ABORT (code in skb->priority) */ RXRPC_SKB_MARK_REJECT_ABORT, /* Reject with ABORT (code in skb->priority) */
}; };
...@@ -959,6 +960,7 @@ void rxrpc_input_implicit_end_call(struct rxrpc_sock *, struct rxrpc_connection ...@@ -959,6 +960,7 @@ void rxrpc_input_implicit_end_call(struct rxrpc_sock *, struct rxrpc_connection
* io_thread.c * io_thread.c
*/ */
int rxrpc_encap_rcv(struct sock *, struct sk_buff *); int rxrpc_encap_rcv(struct sock *, struct sk_buff *);
void rxrpc_error_report(struct sock *);
int rxrpc_io_thread(void *data); int rxrpc_io_thread(void *data);
static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local) static inline void rxrpc_wake_up_io_thread(struct rxrpc_local *local)
{ {
...@@ -1063,7 +1065,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *); ...@@ -1063,7 +1065,7 @@ void rxrpc_send_keepalive(struct rxrpc_peer *);
/* /*
* peer_event.c * peer_event.c
*/ */
void rxrpc_error_report(struct sock *); void rxrpc_input_error(struct rxrpc_local *, struct sk_buff *);
void rxrpc_peer_keepalive_worker(struct work_struct *); void rxrpc_peer_keepalive_worker(struct work_struct *);
/* /*
......
...@@ -37,6 +37,31 @@ int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb) ...@@ -37,6 +37,31 @@ int rxrpc_encap_rcv(struct sock *udp_sk, struct sk_buff *skb)
return 0; return 0;
} }
/*
* Handle an error received on the local endpoint.
*/
void rxrpc_error_report(struct sock *sk)
{
struct rxrpc_local *local;
struct sk_buff *skb;
rcu_read_lock();
local = rcu_dereference_sk_user_data(sk);
if (unlikely(!local)) {
rcu_read_unlock();
return;
}
while ((skb = skb_dequeue(&sk->sk_error_queue))) {
skb->mark = RXRPC_SKB_MARK_ERROR;
rxrpc_new_skb(skb, rxrpc_skb_new_error_report);
skb_queue_tail(&local->rx_queue, skb);
}
rxrpc_wake_up_io_thread(local);
rcu_read_unlock();
}
/* /*
* post connection-level events to the connection * post connection-level events to the connection
* - this includes challenges, responses, some aborts and call terminal packet * - this includes challenges, responses, some aborts and call terminal packet
...@@ -405,6 +430,10 @@ int rxrpc_io_thread(void *data) ...@@ -405,6 +430,10 @@ int rxrpc_io_thread(void *data)
rxrpc_input_packet(local, skb); rxrpc_input_packet(local, skb);
rcu_read_unlock(); rcu_read_unlock();
break; break;
case RXRPC_SKB_MARK_ERROR:
rxrpc_input_error(local, skb);
rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
break;
default: default:
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
rxrpc_free_skb(skb, rxrpc_skb_put_unknown); rxrpc_free_skb(skb, rxrpc_skb_put_unknown);
......
...@@ -131,51 +131,26 @@ static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, unsigned int mtu) ...@@ -131,51 +131,26 @@ static void rxrpc_adjust_mtu(struct rxrpc_peer *peer, unsigned int mtu)
/* /*
* Handle an error received on the local endpoint. * Handle an error received on the local endpoint.
*/ */
void rxrpc_error_report(struct sock *sk) void rxrpc_input_error(struct rxrpc_local *local, struct sk_buff *skb)
{ {
struct sock_exterr_skb *serr; struct sock_exterr_skb *serr = SKB_EXT_ERR(skb);
struct sockaddr_rxrpc srx; struct sockaddr_rxrpc srx;
struct rxrpc_local *local;
struct rxrpc_peer *peer = NULL; struct rxrpc_peer *peer = NULL;
struct sk_buff *skb;
rcu_read_lock(); _enter("L=%x", local->debug_id);
local = rcu_dereference_sk_user_data(sk);
if (unlikely(!local)) {
rcu_read_unlock();
return;
}
_enter("%p{%d}", sk, local->debug_id);
/* Clear the outstanding error value on the socket so that it doesn't
* cause kernel_sendmsg() to return it later.
*/
sock_error(sk);
skb = sock_dequeue_err_skb(sk);
if (!skb) {
rcu_read_unlock();
_leave("UDP socket errqueue empty");
return;
}
rxrpc_new_skb(skb, rxrpc_skb_new_error_report);
serr = SKB_EXT_ERR(skb);
if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) { if (!skb->len && serr->ee.ee_origin == SO_EE_ORIGIN_TIMESTAMPING) {
_leave("UDP empty message"); _leave("UDP empty message");
rcu_read_unlock();
rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
return; return;
} }
rcu_read_lock();
peer = rxrpc_lookup_peer_local_rcu(local, skb, &srx); peer = rxrpc_lookup_peer_local_rcu(local, skb, &srx);
if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_input_error)) if (peer && !rxrpc_get_peer_maybe(peer, rxrpc_peer_get_input_error))
peer = NULL; peer = NULL;
if (!peer) { rcu_read_unlock();
rcu_read_unlock(); if (!peer)
rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
_leave(" [no peer]");
return; return;
}
trace_rxrpc_rx_icmp(peer, &serr->ee, &srx); trace_rxrpc_rx_icmp(peer, &serr->ee, &srx);
...@@ -188,11 +163,7 @@ void rxrpc_error_report(struct sock *sk) ...@@ -188,11 +163,7 @@ void rxrpc_error_report(struct sock *sk)
rxrpc_store_error(peer, serr); rxrpc_store_error(peer, serr);
out: out:
rcu_read_unlock();
rxrpc_free_skb(skb, rxrpc_skb_put_error_report);
rxrpc_put_peer(peer, rxrpc_peer_put_input_error); rxrpc_put_peer(peer, rxrpc_peer_put_input_error);
_leave("");
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment