aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2009-10-12 16:26:31 -0400
committerDavid S. Miller <davem@davemloft.net>2009-10-12 16:26:31 -0400
commit3b885787ea4112eaa80945999ea0901bf742707f (patch)
tree06fc15f8e8083d5652ccb4d06653d9812dce9c0b /net
parentd5e63bded6e819ca77ee1a1d97c783a31f6caf30 (diff)
net: Generalize socket rx gap / receive queue overflow cmsg
Create a new socket level option to report number of queue overflows Recently I augmented the AF_PACKET protocol to report the number of frames lost on the socket receive queue between any two enqueued frames. This value was exported via a SOL_PACKET level cmsg. AFter I completed that work it was requested that this feature be generalized so that any datagram oriented socket could make use of this option. As such I've created this patch, It creates a new SOL_SOCKET level option called SO_RXQ_OVFL, which when enabled exports a SOL_SOCKET level cmsg that reports the nubmer of times the sk_receive_queue overflowed between any two given frames. It also augments the AF_PACKET protocol to take advantage of this new feature (as it previously did not touch sk->sk_drops, which this patch uses to record the overflow count). Tested successfully by me. Notes: 1) Unlike my previous patch, this patch simply records the sk_drops value, which is not a number of drops between packets, but rather a total number of drops. Deltas must be computed in user space. 2) While this patch currently works with datagram oriented protocols, it will also be accepted by non-datagram oriented protocols. I'm not sure if thats agreeable to everyone, but my argument in favor of doing so is that, for those protocols which aren't applicable to this option, sk_drops will always be zero, and reporting no drops on a receive queue that isn't used for those non-participating protocols seems reasonable to me. This also saves us having to code in a per-protocol opt in mechanism. 3) This applies cleanly to net-next assuming that commit 977750076d98c7ff6cbda51858bb5a5894a9d9ab (my af packet cmsg patch) is reverted Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/atm/common.c2
-rw-r--r--net/bluetooth/af_bluetooth.c2
-rw-r--r--net/bluetooth/rfcomm/sock.c2
-rw-r--r--net/can/bcm.c2
-rw-r--r--net/can/raw.c2
-rw-r--r--net/core/sock.c17
-rw-r--r--net/ieee802154/dgram.c2
-rw-r--r--net/ieee802154/raw.c2
-rw-r--r--net/ipv4/raw.c2
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv6/raw.c2
-rw-r--r--net/ipv6/udp.c2
-rw-r--r--net/key/af_key.c2
-rw-r--r--net/packet/af_packet.c7
-rw-r--r--net/rxrpc/ar-recvmsg.c2
-rw-r--r--net/sctp/socket.c2
-rw-r--r--net/socket.c15
17 files changed, 48 insertions, 19 deletions
diff --git a/net/atm/common.c b/net/atm/common.c
index 950bd16d2383..d61e051e0a3f 100644
--- a/net/atm/common.c
+++ b/net/atm/common.c
@@ -496,7 +496,7 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
496 error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 496 error = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
497 if (error) 497 if (error)
498 return error; 498 return error;
499 sock_recv_timestamp(msg, sk, skb); 499 sock_recv_ts_and_drops(msg, sk, skb);
500 pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize); 500 pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
501 atm_return(vcc, skb->truesize); 501 atm_return(vcc, skb->truesize);
502 skb_free_datagram(sk, skb); 502 skb_free_datagram(sk, skb);
diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c
index 1f6e49c1cde8..399e59c9c6cb 100644
--- a/net/bluetooth/af_bluetooth.c
+++ b/net/bluetooth/af_bluetooth.c
@@ -257,7 +257,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
257 skb_reset_transport_header(skb); 257 skb_reset_transport_header(skb);
258 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 258 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
259 if (err == 0) 259 if (err == 0)
260 sock_recv_timestamp(msg, sk, skb); 260 sock_recv_ts_and_drops(msg, sk, skb);
261 261
262 skb_free_datagram(sk, skb); 262 skb_free_datagram(sk, skb);
263 263
diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c
index c70786503850..d3bfc1b0afb1 100644
--- a/net/bluetooth/rfcomm/sock.c
+++ b/net/bluetooth/rfcomm/sock.c
@@ -703,7 +703,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
703 copied += chunk; 703 copied += chunk;
704 size -= chunk; 704 size -= chunk;
705 705
706 sock_recv_timestamp(msg, sk, skb); 706 sock_recv_ts_and_drops(msg, sk, skb);
707 707
708 if (!(flags & MSG_PEEK)) { 708 if (!(flags & MSG_PEEK)) {
709 atomic_sub(chunk, &sk->sk_rmem_alloc); 709 atomic_sub(chunk, &sk->sk_rmem_alloc);
diff --git a/net/can/bcm.c b/net/can/bcm.c
index 597da4f8f888..2f47039c79dd 100644
--- a/net/can/bcm.c
+++ b/net/can/bcm.c
@@ -1534,7 +1534,7 @@ static int bcm_recvmsg(struct kiocb *iocb, struct socket *sock,
1534 return err; 1534 return err;
1535 } 1535 }
1536 1536
1537 sock_recv_timestamp(msg, sk, skb); 1537 sock_recv_ts_and_drops(msg, sk, skb);
1538 1538
1539 if (msg->msg_name) { 1539 if (msg->msg_name) {
1540 msg->msg_namelen = sizeof(struct sockaddr_can); 1540 msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/can/raw.c b/net/can/raw.c
index b5e897922d32..962fc9f1d0c7 100644
--- a/net/can/raw.c
+++ b/net/can/raw.c
@@ -702,7 +702,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct socket *sock,
702 return err; 702 return err;
703 } 703 }
704 704
705 sock_recv_timestamp(msg, sk, skb); 705 sock_recv_ts_and_drops(msg, sk, skb);
706 706
707 if (msg->msg_name) { 707 if (msg->msg_name) {
708 msg->msg_namelen = sizeof(struct sockaddr_can); 708 msg->msg_namelen = sizeof(struct sockaddr_can);
diff --git a/net/core/sock.c b/net/core/sock.c
index 7626b6aacd68..43ca2c995393 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -276,6 +276,8 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
276{ 276{
277 int err = 0; 277 int err = 0;
278 int skb_len; 278 int skb_len;
279 unsigned long flags;
280 struct sk_buff_head *list = &sk->sk_receive_queue;
279 281
280 /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces 282 /* Cast sk->rcvbuf to unsigned... It's pointless, but reduces
281 number of warnings when compiling with -W --ANK 283 number of warnings when compiling with -W --ANK
@@ -305,7 +307,10 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
305 */ 307 */
306 skb_len = skb->len; 308 skb_len = skb->len;
307 309
308 skb_queue_tail(&sk->sk_receive_queue, skb); 310 spin_lock_irqsave(&list->lock, flags);
311 skb->dropcount = atomic_read(&sk->sk_drops);
312 __skb_queue_tail(list, skb);
313 spin_unlock_irqrestore(&list->lock, flags);
309 314
310 if (!sock_flag(sk, SOCK_DEAD)) 315 if (!sock_flag(sk, SOCK_DEAD))
311 sk->sk_data_ready(sk, skb_len); 316 sk->sk_data_ready(sk, skb_len);
@@ -702,6 +707,12 @@ set_rcvbuf:
702 707
703 /* We implement the SO_SNDLOWAT etc to 708 /* We implement the SO_SNDLOWAT etc to
704 not be settable (1003.1g 5.3) */ 709 not be settable (1003.1g 5.3) */
710 case SO_RXQ_OVFL:
711 if (valbool)
712 sock_set_flag(sk, SOCK_RXQ_OVFL);
713 else
714 sock_reset_flag(sk, SOCK_RXQ_OVFL);
715 break;
705 default: 716 default:
706 ret = -ENOPROTOOPT; 717 ret = -ENOPROTOOPT;
707 break; 718 break;
@@ -901,6 +912,10 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
901 v.val = sk->sk_mark; 912 v.val = sk->sk_mark;
902 break; 913 break;
903 914
915 case SO_RXQ_OVFL:
916 v.val = !!sock_flag(sk, SOCK_RXQ_OVFL);
917 break;
918
904 default: 919 default:
905 return -ENOPROTOOPT; 920 return -ENOPROTOOPT;
906 } 921 }
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c
index a413b1bf4465..25ad956a39d8 100644
--- a/net/ieee802154/dgram.c
+++ b/net/ieee802154/dgram.c
@@ -303,7 +303,7 @@ static int dgram_recvmsg(struct kiocb *iocb, struct sock *sk,
303 if (err) 303 if (err)
304 goto done; 304 goto done;
305 305
306 sock_recv_timestamp(msg, sk, skb); 306 sock_recv_ts_and_drops(msg, sk, skb);
307 307
308 if (flags & MSG_TRUNC) 308 if (flags & MSG_TRUNC)
309 copied = skb->len; 309 copied = skb->len;
diff --git a/net/ieee802154/raw.c b/net/ieee802154/raw.c
index 30e74eee07d6..769c8d138fc3 100644
--- a/net/ieee802154/raw.c
+++ b/net/ieee802154/raw.c
@@ -191,7 +191,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
191 if (err) 191 if (err)
192 goto done; 192 goto done;
193 193
194 sock_recv_timestamp(msg, sk, skb); 194 sock_recv_ts_and_drops(msg, sk, skb);
195 195
196 if (flags & MSG_TRUNC) 196 if (flags & MSG_TRUNC)
197 copied = skb->len; 197 copied = skb->len;
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index 757c9171e7c2..f18172b07611 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -682,7 +682,7 @@ static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
682 if (err) 682 if (err)
683 goto done; 683 goto done;
684 684
685 sock_recv_timestamp(msg, sk, skb); 685 sock_recv_ts_and_drops(msg, sk, skb);
686 686
687 /* Copy the address. */ 687 /* Copy the address. */
688 if (sin) { 688 if (sin) {
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 194bcdc6d9fc..71e5353b30c8 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -955,7 +955,7 @@ try_again:
955 UDP_INC_STATS_USER(sock_net(sk), 955 UDP_INC_STATS_USER(sock_net(sk),
956 UDP_MIB_INDATAGRAMS, is_udplite); 956 UDP_MIB_INDATAGRAMS, is_udplite);
957 957
958 sock_recv_timestamp(msg, sk, skb); 958 sock_recv_ts_and_drops(msg, sk, skb);
959 959
960 /* Copy the address. */ 960 /* Copy the address. */
961 if (sin) { 961 if (sin) {
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 4f24570b0869..d8375bc7f2d5 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -497,7 +497,7 @@ static int rawv6_recvmsg(struct kiocb *iocb, struct sock *sk,
497 sin6->sin6_scope_id = IP6CB(skb)->iif; 497 sin6->sin6_scope_id = IP6CB(skb)->iif;
498 } 498 }
499 499
500 sock_recv_timestamp(msg, sk, skb); 500 sock_recv_ts_and_drops(msg, sk, skb);
501 501
502 if (np->rxopt.all) 502 if (np->rxopt.all)
503 datagram_recv_ctl(sk, msg, skb); 503 datagram_recv_ctl(sk, msg, skb);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index ff778c172ef2..1f8e2afa4490 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -252,7 +252,7 @@ try_again:
252 UDP_MIB_INDATAGRAMS, is_udplite); 252 UDP_MIB_INDATAGRAMS, is_udplite);
253 } 253 }
254 254
255 sock_recv_timestamp(msg, sk, skb); 255 sock_recv_ts_and_drops(msg, sk, skb);
256 256
257 /* Copy the address. */ 257 /* Copy the address. */
258 if (msg->msg_name) { 258 if (msg->msg_name) {
diff --git a/net/key/af_key.c b/net/key/af_key.c
index c078ae6e975b..472f6594184a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -3606,7 +3606,7 @@ static int pfkey_recvmsg(struct kiocb *kiocb,
3606 if (err) 3606 if (err)
3607 goto out_free; 3607 goto out_free;
3608 3608
3609 sock_recv_timestamp(msg, sk, skb); 3609 sock_recv_ts_and_drops(msg, sk, skb);
3610 3610
3611 err = (flags & MSG_TRUNC) ? skb->len : copied; 3611 err = (flags & MSG_TRUNC) ? skb->len : copied;
3612 3612
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index f87ed4803c11..bf3a2954cd4d 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -627,15 +627,14 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
627 627
628 spin_lock(&sk->sk_receive_queue.lock); 628 spin_lock(&sk->sk_receive_queue.lock);
629 po->stats.tp_packets++; 629 po->stats.tp_packets++;
630 skb->dropcount = atomic_read(&sk->sk_drops);
630 __skb_queue_tail(&sk->sk_receive_queue, skb); 631 __skb_queue_tail(&sk->sk_receive_queue, skb);
631 spin_unlock(&sk->sk_receive_queue.lock); 632 spin_unlock(&sk->sk_receive_queue.lock);
632 sk->sk_data_ready(sk, skb->len); 633 sk->sk_data_ready(sk, skb->len);
633 return 0; 634 return 0;
634 635
635drop_n_acct: 636drop_n_acct:
636 spin_lock(&sk->sk_receive_queue.lock); 637 po->stats.tp_drops = atomic_inc_return(&sk->sk_drops);
637 po->stats.tp_drops++;
638 spin_unlock(&sk->sk_receive_queue.lock);
639 638
640drop_n_restore: 639drop_n_restore:
641 if (skb_head != skb->data && skb_shared(skb)) { 640 if (skb_head != skb->data && skb_shared(skb)) {
@@ -1478,7 +1477,7 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
1478 if (err) 1477 if (err)
1479 goto out_free; 1478 goto out_free;
1480 1479
1481 sock_recv_timestamp(msg, sk, skb); 1480 sock_recv_ts_and_drops(msg, sk, skb);
1482 1481
1483 if (msg->msg_name) 1482 if (msg->msg_name)
1484 memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa, 1483 memcpy(msg->msg_name, &PACKET_SKB_CB(skb)->sa,
diff --git a/net/rxrpc/ar-recvmsg.c b/net/rxrpc/ar-recvmsg.c
index a39bf97f8830..60c2b94e6b54 100644
--- a/net/rxrpc/ar-recvmsg.c
+++ b/net/rxrpc/ar-recvmsg.c
@@ -146,7 +146,7 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
146 memcpy(msg->msg_name, 146 memcpy(msg->msg_name,
147 &call->conn->trans->peer->srx, 147 &call->conn->trans->peer->srx,
148 sizeof(call->conn->trans->peer->srx)); 148 sizeof(call->conn->trans->peer->srx));
149 sock_recv_timestamp(msg, &rx->sk, skb); 149 sock_recv_ts_and_drops(msg, &rx->sk, skb);
150 } 150 }
151 151
152 /* receive the message */ 152 /* receive the message */
diff --git a/net/sctp/socket.c b/net/sctp/socket.c
index c8d05758661d..0970e92c6acd 100644
--- a/net/sctp/socket.c
+++ b/net/sctp/socket.c
@@ -1958,7 +1958,7 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk,
1958 if (err) 1958 if (err)
1959 goto out_free; 1959 goto out_free;
1960 1960
1961 sock_recv_timestamp(msg, sk, skb); 1961 sock_recv_ts_and_drops(msg, sk, skb);
1962 if (sctp_ulpevent_is_notification(event)) { 1962 if (sctp_ulpevent_is_notification(event)) {
1963 msg->msg_flags |= MSG_NOTIFICATION; 1963 msg->msg_flags |= MSG_NOTIFICATION;
1964 sp->pf->event_msgname(event, msg->msg_name, addr_len); 1964 sp->pf->event_msgname(event, msg->msg_name, addr_len);
diff --git a/net/socket.c b/net/socket.c
index 954f3381cc8a..807935693846 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -668,6 +668,21 @@ void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,
668 668
669EXPORT_SYMBOL_GPL(__sock_recv_timestamp); 669EXPORT_SYMBOL_GPL(__sock_recv_timestamp);
670 670
671inline void sock_recv_drops(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)
672{
673 if (sock_flag(sk, SOCK_RXQ_OVFL) && skb && skb->dropcount)
674 put_cmsg(msg, SOL_SOCKET, SO_RXQ_OVFL,
675 sizeof(__u32), &skb->dropcount);
676}
677
678void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,
679 struct sk_buff *skb)
680{
681 sock_recv_timestamp(msg, sk, skb);
682 sock_recv_drops(msg, sk, skb);
683}
684EXPORT_SYMBOL_GPL(sock_recv_ts_and_drops);
685
671static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, 686static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock,
672 struct msghdr *msg, size_t size, int flags) 687 struct msghdr *msg, size_t size, int flags)
673{ 688{