aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/net/sock.h1
-rw-r--r--net/core/skbuff.c20
-rw-r--r--net/core/sock.c14
-rw-r--r--net/ipv4/ip_sockglue.c15
-rw-r--r--net/ipv6/datagram.c15
-rw-r--r--net/rxrpc/ar-error.c14
6 files changed, 28 insertions, 51 deletions
diff --git a/include/net/sock.h b/include/net/sock.h
index 7f2ab72f321a..3fde6130789d 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -2041,6 +2041,7 @@ void sk_stop_timer(struct sock *sk, struct timer_list *timer);
2041int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb); 2041int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
2042 2042
2043int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb); 2043int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
2044struct sk_buff *sock_dequeue_err_skb(struct sock *sk);
2044 2045
2045/* 2046/*
2046 * Recover an error report and clear atomically 2047 * Recover an error report and clear atomically
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 163b673f9e62..53ce536e3d6e 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3491,6 +3491,26 @@ int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb)
3491} 3491}
3492EXPORT_SYMBOL(sock_queue_err_skb); 3492EXPORT_SYMBOL(sock_queue_err_skb);
3493 3493
3494struct sk_buff *sock_dequeue_err_skb(struct sock *sk)
3495{
3496 struct sk_buff_head *q = &sk->sk_error_queue;
3497 struct sk_buff *skb, *skb_next;
3498 int err = 0;
3499
3500 spin_lock_bh(&q->lock);
3501 skb = __skb_dequeue(q);
3502 if (skb && (skb_next = skb_peek(q)))
3503 err = SKB_EXT_ERR(skb_next)->ee.ee_errno;
3504 spin_unlock_bh(&q->lock);
3505
3506 sk->sk_err = err;
3507 if (err)
3508 sk->sk_error_report(sk);
3509
3510 return skb;
3511}
3512EXPORT_SYMBOL(sock_dequeue_err_skb);
3513
3494void __skb_tstamp_tx(struct sk_buff *orig_skb, 3514void __skb_tstamp_tx(struct sk_buff *orig_skb,
3495 struct skb_shared_hwtstamps *hwtstamps, 3515 struct skb_shared_hwtstamps *hwtstamps,
3496 struct sock *sk, int tstype) 3516 struct sock *sk, int tstype)
diff --git a/net/core/sock.c b/net/core/sock.c
index f7f2352200ad..f1a638ee93d9 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2488,11 +2488,11 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
2488 int level, int type) 2488 int level, int type)
2489{ 2489{
2490 struct sock_exterr_skb *serr; 2490 struct sock_exterr_skb *serr;
2491 struct sk_buff *skb, *skb2; 2491 struct sk_buff *skb;
2492 int copied, err; 2492 int copied, err;
2493 2493
2494 err = -EAGAIN; 2494 err = -EAGAIN;
2495 skb = skb_dequeue(&sk->sk_error_queue); 2495 skb = sock_dequeue_err_skb(sk);
2496 if (skb == NULL) 2496 if (skb == NULL)
2497 goto out; 2497 goto out;
2498 2498
@@ -2513,16 +2513,6 @@ int sock_recv_errqueue(struct sock *sk, struct msghdr *msg, int len,
2513 msg->msg_flags |= MSG_ERRQUEUE; 2513 msg->msg_flags |= MSG_ERRQUEUE;
2514 err = copied; 2514 err = copied;
2515 2515
2516 /* Reset and regenerate socket error */
2517 spin_lock_bh(&sk->sk_error_queue.lock);
2518 sk->sk_err = 0;
2519 if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
2520 sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
2521 spin_unlock_bh(&sk->sk_error_queue.lock);
2522 sk->sk_error_report(sk);
2523 } else
2524 spin_unlock_bh(&sk->sk_error_queue.lock);
2525
2526out_free_skb: 2516out_free_skb:
2527 kfree_skb(skb); 2517 kfree_skb(skb);
2528out: 2518out:
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index 5cb830c78990..455e75bcb167 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -405,7 +405,7 @@ void ip_local_error(struct sock *sk, int err, __be32 daddr, __be16 port, u32 inf
405int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len) 405int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
406{ 406{
407 struct sock_exterr_skb *serr; 407 struct sock_exterr_skb *serr;
408 struct sk_buff *skb, *skb2; 408 struct sk_buff *skb;
409 DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name); 409 DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
410 struct { 410 struct {
411 struct sock_extended_err ee; 411 struct sock_extended_err ee;
@@ -415,7 +415,7 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
415 int copied; 415 int copied;
416 416
417 err = -EAGAIN; 417 err = -EAGAIN;
418 skb = skb_dequeue(&sk->sk_error_queue); 418 skb = sock_dequeue_err_skb(sk);
419 if (skb == NULL) 419 if (skb == NULL)
420 goto out; 420 goto out;
421 421
@@ -462,17 +462,6 @@ int ip_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
462 msg->msg_flags |= MSG_ERRQUEUE; 462 msg->msg_flags |= MSG_ERRQUEUE;
463 err = copied; 463 err = copied;
464 464
465 /* Reset and regenerate socket error */
466 spin_lock_bh(&sk->sk_error_queue.lock);
467 sk->sk_err = 0;
468 skb2 = skb_peek(&sk->sk_error_queue);
469 if (skb2 != NULL) {
470 sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
471 spin_unlock_bh(&sk->sk_error_queue.lock);
472 sk->sk_error_report(sk);
473 } else
474 spin_unlock_bh(&sk->sk_error_queue.lock);
475
476out_free_skb: 465out_free_skb:
477 kfree_skb(skb); 466 kfree_skb(skb);
478out: 467out:
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index 1844e874a350..2cdc38338be3 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -332,7 +332,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
332{ 332{
333 struct ipv6_pinfo *np = inet6_sk(sk); 333 struct ipv6_pinfo *np = inet6_sk(sk);
334 struct sock_exterr_skb *serr; 334 struct sock_exterr_skb *serr;
335 struct sk_buff *skb, *skb2; 335 struct sk_buff *skb;
336 DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name); 336 DECLARE_SOCKADDR(struct sockaddr_in6 *, sin, msg->msg_name);
337 struct { 337 struct {
338 struct sock_extended_err ee; 338 struct sock_extended_err ee;
@@ -342,7 +342,7 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
342 int copied; 342 int copied;
343 343
344 err = -EAGAIN; 344 err = -EAGAIN;
345 skb = skb_dequeue(&sk->sk_error_queue); 345 skb = sock_dequeue_err_skb(sk);
346 if (skb == NULL) 346 if (skb == NULL)
347 goto out; 347 goto out;
348 348
@@ -415,17 +415,6 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len, int *addr_len)
415 msg->msg_flags |= MSG_ERRQUEUE; 415 msg->msg_flags |= MSG_ERRQUEUE;
416 err = copied; 416 err = copied;
417 417
418 /* Reset and regenerate socket error */
419 spin_lock_bh(&sk->sk_error_queue.lock);
420 sk->sk_err = 0;
421 if ((skb2 = skb_peek(&sk->sk_error_queue)) != NULL) {
422 sk->sk_err = SKB_EXT_ERR(skb2)->ee.ee_errno;
423 spin_unlock_bh(&sk->sk_error_queue.lock);
424 sk->sk_error_report(sk);
425 } else {
426 spin_unlock_bh(&sk->sk_error_queue.lock);
427 }
428
429out_free_skb: 418out_free_skb:
430 kfree_skb(skb); 419 kfree_skb(skb);
431out: 420out:
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