summaryrefslogtreecommitdiffstats
path: root/net/rxrpc
diff options
context:
space:
mode:
authorWillem de Bruijn <willemb@google.com>2014-08-31 21:30:27 -0400
committerDavid S. Miller <davem@davemloft.net>2014-09-02 00:49:08 -0400
commit364a9e93243d1785f310c0964af0e24bf1adac03 (patch)
treed94daf2c5c0cf6492708d28c56160f96d9917201 /net/rxrpc
parent8fe2f761cae9da9f9031162f104164a812ce78ab (diff)
sock: deduplicate errqueue dequeue
sk->sk_error_queue is dequeued in four locations. All share the exact same logic. Deduplicate. Also collapse the two critical sections for dequeue (at the top of the recv handler) and signal (at the bottom). This moves signal generation for the next packet forward, which should be harmless. It also changes the behavior if the recv handler exits early with an error. Previously, a signal for follow-up packets on the errqueue would then not be scheduled. The new behavior, to always signal, is arguably a bug fix. For rxrpc, the change causes the same function to be called repeatedly for each queued packet (because the recv handler == sk_error_report). It is likely that all packets will fail for the same reason (e.g., memory exhaustion). This code runs without sk_lock held, so it is not safe to trust that sk->sk_err is immutable inbetween releasing q->lock and the subsequent test. Introduce int err just to avoid this potential race. Signed-off-by: Willem de Bruijn <willemb@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/rxrpc')
-rw-r--r--net/rxrpc/ar-error.c14
1 files changed, 1 insertions, 13 deletions
diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c
index db57458c824c..74c0fcd36838 100644
--- a/net/rxrpc/ar-error.c
+++ b/net/rxrpc/ar-error.c
@@ -37,7 +37,7 @@ void rxrpc_UDP_error_report(struct sock *sk)
37 37
38 _enter("%p{%d}", sk, local->debug_id); 38 _enter("%p{%d}", sk, local->debug_id);
39 39
40 skb = skb_dequeue(&sk->sk_error_queue); 40 skb = sock_dequeue_err_skb(sk);
41 if (!skb) { 41 if (!skb) {
42 _leave("UDP socket errqueue empty"); 42 _leave("UDP socket errqueue empty");
43 return; 43 return;
@@ -111,18 +111,6 @@ void rxrpc_UDP_error_report(struct sock *sk)
111 skb_queue_tail(&trans->error_queue, skb); 111 skb_queue_tail(&trans->error_queue, skb);
112 rxrpc_queue_work(&trans->error_handler); 112 rxrpc_queue_work(&trans->error_handler);
113 113
114 /* reset and regenerate socket error */
115 spin_lock_bh(&sk->sk_error_queue.lock);
116 sk->sk_err = 0;
117 skb = skb_peek(&sk->sk_error_queue);
118 if (skb) {
119 sk->sk_err = SKB_EXT_ERR(skb)->ee.ee_errno;
120 spin_unlock_bh(&sk->sk_error_queue.lock);
121 sk->sk_error_report(sk);
122 } else {
123 spin_unlock_bh(&sk->sk_error_queue.lock);
124 }
125
126 _leave(""); 114 _leave("");
127} 115}
128 116