* [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET
@ 2016-04-03 23:29 Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 1/4] sock: convert sk_peek_offset functions to WRITE_ONCE Willem de Bruijn
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-03 23:29 UTC (permalink / raw)
To: netdev; +Cc: davem, samanthakumar, edumazet, willemb
From: Willem de Bruijn <willemb@google.com>
Support peeking at a non-zero offset for UDP sockets. Match the
existing behavior on Unix datagram sockets.
1/4 makes the sk_peek_offset functions safe to use outside locks
2/4 removes udp headers before enqueue, to simplify offset arithmetic
3/4 introduces SO_PEEK_OFFSET support
4/4 moves sk->sk_peek_off on read, to match Unix socket semantics.
Willem de Bruijn (2):
sock: convert sk_peek_offset functions to WRITE_ONCE
udp: move peek offset on read and peek
samanthakumar (2):
udp: remove headers from UDP packets before queueing
udp: enable MSG_PEEK at non-zero offset
include/linux/skbuff.h | 7 ++++++-
include/net/sock.h | 27 ++++++++++++++++-----------
include/net/udp.h | 9 +++++++++
net/core/datagram.c | 9 ++++++---
net/core/sock.c | 28 ++++++++++++++++++++++------
net/ipv4/af_inet.c | 1 +
net/ipv4/udp.c | 38 ++++++++++++++++++++------------------
net/ipv6/af_inet6.c | 1 +
net/ipv6/udp.c | 30 ++++++++++++++++--------------
9 files changed, 97 insertions(+), 53 deletions(-)
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH net-next 1/4] sock: convert sk_peek_offset functions to WRITE_ONCE
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
@ 2016-04-03 23:29 ` Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 2/4] udp: remove headers from UDP packets before queueing Willem de Bruijn
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-03 23:29 UTC (permalink / raw)
To: netdev; +Cc: davem, samanthakumar, edumazet, willemb
From: Willem de Bruijn <willemb@google.com>
Make the peek offset interface safe to use in lockless environments.
Use READ_ONCE and WRITE_ONCE to avoid race conditions between testing
and updating the peek offset.
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
include/net/sock.h | 24 +++++++++++++-----------
1 file changed, 13 insertions(+), 11 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 255d3e0..6435f6d 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -458,26 +458,28 @@ struct sock {
static inline int sk_peek_offset(struct sock *sk, int flags)
{
- if ((flags & MSG_PEEK) && (sk->sk_peek_off >= 0))
- return sk->sk_peek_off;
- else
- return 0;
+ if (unlikely(flags & MSG_PEEK)) {
+ s32 off = READ_ONCE(sk->sk_peek_off);
+ if (off >= 0)
+ return off;
+ }
+
+ return 0;
}
static inline void sk_peek_offset_bwd(struct sock *sk, int val)
{
- if (sk->sk_peek_off >= 0) {
- if (sk->sk_peek_off >= val)
- sk->sk_peek_off -= val;
- else
- sk->sk_peek_off = 0;
+ s32 off = READ_ONCE(sk->sk_peek_off);
+
+ if (unlikely(off >= 0)) {
+ off = max_t(s32, off - val, 0);
+ WRITE_ONCE(sk->sk_peek_off, off);
}
}
static inline void sk_peek_offset_fwd(struct sock *sk, int val)
{
- if (sk->sk_peek_off >= 0)
- sk->sk_peek_off += val;
+ sk_peek_offset_bwd(sk, -val);
}
/*
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 2/4] udp: remove headers from UDP packets before queueing
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 1/4] sock: convert sk_peek_offset functions to WRITE_ONCE Willem de Bruijn
@ 2016-04-03 23:29 ` Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 3/4] udp: enable MSG_PEEK at non-zero offset Willem de Bruijn
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-03 23:29 UTC (permalink / raw)
To: netdev; +Cc: davem, samanthakumar, edumazet, willemb
From: samanthakumar <samanthakumar@google.com>
Remove UDP transport headers before queueing packets for reception.
This change simplifies a follow-up patch to add MSG_PEEK support.
Signed-off-by: Sam Kumar <samanthakumar@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
include/net/sock.h | 1 +
include/net/udp.h | 9 +++++++++
net/core/sock.c | 19 +++++++++++++------
net/ipv4/udp.c | 20 +++++++++++---------
net/ipv6/udp.c | 12 +++++++-----
5 files changed, 41 insertions(+), 20 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index 6435f6d..b30c2b3 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -1859,6 +1859,7 @@ void sk_reset_timer(struct sock *sk, struct timer_list *timer,
void sk_stop_timer(struct sock *sk, struct timer_list *timer);
+int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb);
int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb);
diff --git a/include/net/udp.h b/include/net/udp.h
index 92927f7..baa2ec1 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -158,6 +158,15 @@ static inline __sum16 udp_v4_check(int len, __be32 saddr,
void udp_set_csum(bool nocheck, struct sk_buff *skb,
__be32 saddr, __be32 daddr, int len);
+static inline void udp_csum_pull_header(struct sk_buff *skb)
+{
+ if (skb->ip_summed == CHECKSUM_NONE)
+ skb->csum = csum_partial(udp_hdr(skb), sizeof(struct udphdr),
+ skb->csum);
+ skb_pull_rcsum(skb, sizeof(struct udphdr));
+ UDP_SKB_CB(skb)->cscov -= sizeof(struct udphdr);
+}
+
struct sk_buff **udp_gro_receive(struct sk_buff **head, struct sk_buff *skb,
struct udphdr *uh);
int udp_gro_complete(struct sk_buff *skb, int nhoff);
diff --git a/net/core/sock.c b/net/core/sock.c
index b67b9ae..a33f494 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -402,9 +402,8 @@ static void sock_disable_timestamp(struct sock *sk, unsigned long flags)
}
-int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+int __sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
{
- int err;
unsigned long flags;
struct sk_buff_head *list = &sk->sk_receive_queue;
@@ -414,10 +413,6 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
return -ENOMEM;
}
- err = sk_filter(sk, skb);
- if (err)
- return err;
-
if (!sk_rmem_schedule(sk, skb, skb->truesize)) {
atomic_inc(&sk->sk_drops);
return -ENOBUFS;
@@ -440,6 +435,18 @@ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
sk->sk_data_ready(sk);
return 0;
}
+EXPORT_SYMBOL(__sock_queue_rcv_skb);
+
+int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
+{
+ int err;
+
+ err = sk_filter(sk, skb);
+ if (err)
+ return err;
+
+ return __sock_queue_rcv_skb(sk, skb);
+}
EXPORT_SYMBOL(sock_queue_rcv_skb);
int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 08eed5e..6ebc7de 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1357,7 +1357,7 @@ try_again:
if (!skb)
goto out;
- ulen = skb->len - sizeof(struct udphdr);
+ ulen = skb->len;
copied = len;
if (copied > ulen)
copied = ulen;
@@ -1377,11 +1377,9 @@ try_again:
}
if (checksum_valid || skb_csum_unnecessary(skb))
- err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
- msg, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
else {
- err = skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr),
- msg);
+ err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
if (err == -EINVAL)
goto csum_copy_err;
@@ -1548,7 +1546,7 @@ static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
sk_incoming_cpu_update(sk);
}
- rc = sock_queue_rcv_skb(sk, skb);
+ rc = __sock_queue_rcv_skb(sk, skb);
if (rc < 0) {
int is_udplite = IS_UDPLITE(sk);
@@ -1664,10 +1662,14 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
}
}
- if (rcu_access_pointer(sk->sk_filter) &&
- udp_lib_checksum_complete(skb))
- goto csum_error;
+ if (rcu_access_pointer(sk->sk_filter)) {
+ if (udp_lib_checksum_complete(skb))
+ goto csum_error;
+ if (sk_filter(sk, skb))
+ goto drop;
+ }
+ udp_csum_pull_header(skb);
if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) {
UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_RCVBUFERRORS,
is_udplite);
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index 8125931..ebcf05f 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -420,7 +420,7 @@ try_again:
if (!skb)
goto out;
- ulen = skb->len - sizeof(struct udphdr);
+ ulen = skb->len;
copied = len;
if (copied > ulen)
copied = ulen;
@@ -442,10 +442,9 @@ try_again:
}
if (checksum_valid || skb_csum_unnecessary(skb))
- err = skb_copy_datagram_msg(skb, sizeof(struct udphdr),
- msg, copied);
+ err = skb_copy_datagram_msg(skb, 0, msg, copied);
else {
- err = skb_copy_and_csum_datagram_msg(skb, sizeof(struct udphdr), msg);
+ err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
if (err == -EINVAL)
goto csum_copy_err;
}
@@ -598,7 +597,7 @@ static int __udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
sk_incoming_cpu_update(sk);
}
- rc = sock_queue_rcv_skb(sk, skb);
+ rc = __sock_queue_rcv_skb(sk, skb);
if (rc < 0) {
int is_udplite = IS_UDPLITE(sk);
@@ -692,8 +691,11 @@ int udpv6_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
if (rcu_access_pointer(sk->sk_filter)) {
if (udp_lib_checksum_complete(skb))
goto csum_error;
+ if (sk_filter(sk, skb))
+ goto drop;
}
+ udp_csum_pull_header(skb);
if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) {
UDP6_INC_STATS_BH(sock_net(sk),
UDP_MIB_RCVBUFERRORS, is_udplite);
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 3/4] udp: enable MSG_PEEK at non-zero offset
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 1/4] sock: convert sk_peek_offset functions to WRITE_ONCE Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 2/4] udp: remove headers from UDP packets before queueing Willem de Bruijn
@ 2016-04-03 23:29 ` Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 4/4] udp: move peek offset on read and peek Willem de Bruijn
2016-04-04 21:49 ` [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET David Miller
4 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-03 23:29 UTC (permalink / raw)
To: netdev; +Cc: davem, samanthakumar, edumazet, willemb
From: samanthakumar <samanthakumar@google.com>
Enable peeking at UDP datagrams at the offset specified with socket
option SOL_SOCKET/SO_PEEK_OFF. Peek at any datagram in the queue, up
to the end of the given datagram.
When peeking, always checksum the packet immediately, to avoid
recomputation on subsequent peeks and final read.
This implementation does not move the peek offset. A follow-up patch
adds that.
Signed-off-by: Sam Kumar <samanthakumar@google.com>
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
include/net/sock.h | 2 ++
net/core/sock.c | 9 +++++++++
net/ipv4/af_inet.c | 1 +
net/ipv4/udp.c | 13 +++++++------
net/ipv6/af_inet6.c | 1 +
net/ipv6/udp.c | 13 +++++++------
6 files changed, 27 insertions(+), 12 deletions(-)
diff --git a/include/net/sock.h b/include/net/sock.h
index b30c2b3..5978bcf 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -456,6 +456,8 @@ struct sock {
#define SK_CAN_REUSE 1
#define SK_FORCE_REUSE 2
+int sk_set_peek_off(struct sock *sk, int val);
+
static inline int sk_peek_offset(struct sock *sk, int flags)
{
if (unlikely(flags & MSG_PEEK)) {
diff --git a/net/core/sock.c b/net/core/sock.c
index a33f494..3739381 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -2149,6 +2149,15 @@ void __sk_mem_reclaim(struct sock *sk, int amount)
}
EXPORT_SYMBOL(__sk_mem_reclaim);
+int sk_set_peek_off(struct sock *sk, int val)
+{
+ if (val < 0)
+ return -EINVAL;
+
+ sk->sk_peek_off = val;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sk_set_peek_off);
/*
* Set of default routines for initialising struct proto_ops when
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 9e48199..a38b991 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -948,6 +948,7 @@ const struct proto_ops inet_dgram_ops = {
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
.sendpage = inet_sendpage,
+ .set_peek_off = sk_set_peek_off,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt,
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 6ebc7de..016d13c 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1342,7 +1342,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
DECLARE_SOCKADDR(struct sockaddr_in *, sin, msg->msg_name);
struct sk_buff *skb;
unsigned int ulen, copied;
- int peeked, off = 0;
+ int peeked, peeking, off;
int err;
int is_udplite = IS_UDPLITE(sk);
bool checksum_valid = false;
@@ -1352,6 +1352,7 @@ int udp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, int noblock,
return ip_recv_error(sk, msg, len, addr_len);
try_again:
+ peeking = off = sk_peek_offset(sk, flags);
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, &off, &err);
if (!skb)
@@ -1359,8 +1360,8 @@ try_again:
ulen = skb->len;
copied = len;
- if (copied > ulen)
- copied = ulen;
+ if (copied > ulen - off)
+ copied = ulen - off;
else if (copied < ulen)
msg->msg_flags |= MSG_TRUNC;
@@ -1370,16 +1371,16 @@ try_again:
* coverage checksum (UDP-Lite), do it before the copy.
*/
- if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov || peeking) {
checksum_valid = !udp_lib_checksum_complete(skb);
if (!checksum_valid)
goto csum_copy_err;
}
if (checksum_valid || skb_csum_unnecessary(skb))
- err = skb_copy_datagram_msg(skb, 0, msg, copied);
+ err = skb_copy_datagram_msg(skb, off, msg, copied);
else {
- err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
+ err = skb_copy_and_csum_datagram_msg(skb, off, msg);
if (err == -EINVAL)
goto csum_copy_err;
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index b11c37c..2b78aad 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -561,6 +561,7 @@ const struct proto_ops inet6_dgram_ops = {
.recvmsg = inet_recvmsg, /* ok */
.mmap = sock_no_mmap,
.sendpage = sock_no_sendpage,
+ .set_peek_off = sk_set_peek_off,
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_sock_common_setsockopt,
.compat_getsockopt = compat_sock_common_getsockopt,
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index ebcf05f..d107810 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -401,7 +401,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
struct inet_sock *inet = inet_sk(sk);
struct sk_buff *skb;
unsigned int ulen, copied;
- int peeked, off = 0;
+ int peeked, peeking, off;
int err;
int is_udplite = IS_UDPLITE(sk);
bool checksum_valid = false;
@@ -415,6 +415,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
return ipv6_recv_rxpmtu(sk, msg, len, addr_len);
try_again:
+ peeking = off = sk_peek_offset(sk, flags);
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, &off, &err);
if (!skb)
@@ -422,8 +423,8 @@ try_again:
ulen = skb->len;
copied = len;
- if (copied > ulen)
- copied = ulen;
+ if (copied > ulen - off)
+ copied = ulen - off;
else if (copied < ulen)
msg->msg_flags |= MSG_TRUNC;
@@ -435,16 +436,16 @@ try_again:
* coverage checksum (UDP-Lite), do it before the copy.
*/
- if (copied < ulen || UDP_SKB_CB(skb)->partial_cov) {
+ if (copied < ulen || UDP_SKB_CB(skb)->partial_cov || peeking) {
checksum_valid = !udp_lib_checksum_complete(skb);
if (!checksum_valid)
goto csum_copy_err;
}
if (checksum_valid || skb_csum_unnecessary(skb))
- err = skb_copy_datagram_msg(skb, 0, msg, copied);
+ err = skb_copy_datagram_msg(skb, off, msg, copied);
else {
- err = skb_copy_and_csum_datagram_msg(skb, 0, msg);
+ err = skb_copy_and_csum_datagram_msg(skb, off, msg);
if (err == -EINVAL)
goto csum_copy_err;
}
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH net-next 4/4] udp: move peek offset on read and peek
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
` (2 preceding siblings ...)
2016-04-03 23:29 ` [PATCH net-next 3/4] udp: enable MSG_PEEK at non-zero offset Willem de Bruijn
@ 2016-04-03 23:29 ` Willem de Bruijn
2016-04-04 21:49 ` [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET David Miller
4 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-03 23:29 UTC (permalink / raw)
To: netdev; +Cc: davem, samanthakumar, edumazet, willemb
From: Willem de Bruijn <willemb@google.com>
For UDP sockets, implement the SO_PEEK_OFF semantics introduced in
commit ef64a54f6e55 ("sock: Introduce the SO_PEEK_OFF sock option").
Move the offset forward on peek by the size of the data peeked,
move it backwards on regular reads.
The socket lock is not held for the duration of udp_recvmsg, so
peek and read operations can run concurrently. Only the last store
to sk_peek_off is preserved.
Signed-off-by: Willem de Bruijn <willemb@google.com>
---
include/linux/skbuff.h | 7 ++++++-
net/core/datagram.c | 9 ++++++---
net/ipv4/udp.c | 9 ++++-----
net/ipv6/udp.c | 9 ++++-----
4 files changed, 20 insertions(+), 14 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 15d0df9..0073812 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2949,7 +2949,12 @@ int skb_copy_datagram_from_iter(struct sk_buff *skb, int offset,
struct iov_iter *from, int len);
int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *frm);
void skb_free_datagram(struct sock *sk, struct sk_buff *skb);
-void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb);
+void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len);
+static inline void skb_free_datagram_locked(struct sock *sk,
+ struct sk_buff *skb)
+{
+ __skb_free_datagram_locked(sk, skb, 0);
+}
int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags);
int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len);
int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len);
diff --git a/net/core/datagram.c b/net/core/datagram.c
index fa9dc64..b7de71f 100644
--- a/net/core/datagram.c
+++ b/net/core/datagram.c
@@ -301,16 +301,19 @@ void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
}
EXPORT_SYMBOL(skb_free_datagram);
-void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
+void __skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb, int len)
{
bool slow;
if (likely(atomic_read(&skb->users) == 1))
smp_rmb();
- else if (likely(!atomic_dec_and_test(&skb->users)))
+ else if (likely(!atomic_dec_and_test(&skb->users))) {
+ sk_peek_offset_bwd(sk, len);
return;
+ }
slow = lock_sock_fast(sk);
+ sk_peek_offset_bwd(sk, len);
skb_orphan(skb);
sk_mem_reclaim_partial(sk);
unlock_sock_fast(sk, slow);
@@ -318,7 +321,7 @@ void skb_free_datagram_locked(struct sock *sk, struct sk_buff *skb)
/* skb is now orphaned, can be freed outside of locked section */
__kfree_skb(skb);
}
-EXPORT_SYMBOL(skb_free_datagram_locked);
+EXPORT_SYMBOL(__skb_free_datagram_locked);
/**
* skb_kill_datagram - Free a datagram skbuff forcibly
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 016d13c..075c874 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -1356,7 +1356,7 @@ try_again:
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, &off, &err);
if (!skb)
- goto out;
+ return err;
ulen = skb->len;
copied = len;
@@ -1393,7 +1393,8 @@ try_again:
UDP_INC_STATS_USER(sock_net(sk),
UDP_MIB_INERRORS, is_udplite);
}
- goto out_free;
+ skb_free_datagram_locked(sk, skb);
+ return err;
}
if (!peeked)
@@ -1417,9 +1418,7 @@ try_again:
if (flags & MSG_TRUNC)
err = ulen;
-out_free:
- skb_free_datagram_locked(sk, skb);
-out:
+ __skb_free_datagram_locked(sk, skb, peeking ? -err : err);
return err;
csum_copy_err:
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index d107810..323282a 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -419,7 +419,7 @@ try_again:
skb = __skb_recv_datagram(sk, flags | (noblock ? MSG_DONTWAIT : 0),
&peeked, &off, &err);
if (!skb)
- goto out;
+ return err;
ulen = skb->len;
copied = len;
@@ -462,7 +462,8 @@ try_again:
UDP_MIB_INERRORS,
is_udplite);
}
- goto out_free;
+ skb_free_datagram_locked(sk, skb);
+ return err;
}
if (!peeked) {
if (is_udp4)
@@ -510,9 +511,7 @@ try_again:
if (flags & MSG_TRUNC)
err = ulen;
-out_free:
- skb_free_datagram_locked(sk, skb);
-out:
+ __skb_free_datagram_locked(sk, skb, peeking ? -err : err);
return err;
csum_copy_err:
--
2.8.0.rc3.226.g39d4020
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
` (3 preceding siblings ...)
2016-04-03 23:29 ` [PATCH net-next 4/4] udp: move peek offset on read and peek Willem de Bruijn
@ 2016-04-04 21:49 ` David Miller
2016-04-04 22:23 ` Willem de Bruijn
4 siblings, 1 reply; 7+ messages in thread
From: David Miller @ 2016-04-04 21:49 UTC (permalink / raw)
To: willemdebruijn.kernel; +Cc: netdev, samanthakumar, edumazet, willemb
From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
Date: Sun, 3 Apr 2016 19:29:49 -0400
> From: Willem de Bruijn <willemb@google.com>
>
> Support peeking at a non-zero offset for UDP sockets. Match the
> existing behavior on Unix datagram sockets.
>
> 1/4 makes the sk_peek_offset functions safe to use outside locks
> 2/4 removes udp headers before enqueue, to simplify offset arithmetic
> 3/4 introduces SO_PEEK_OFFSET support
> 4/4 moves sk->sk_peek_off on read, to match Unix socket semantics.
I don't see how you can separate patches #3 and #4.
Once you hook up the socket operation, the user can successfully use
the feature and therefore must receive the full set of semantics.
You hook up the op in patch #3 but only give the full proper semantics
in #4.
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET
2016-04-04 21:49 ` [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET David Miller
@ 2016-04-04 22:23 ` Willem de Bruijn
0 siblings, 0 replies; 7+ messages in thread
From: Willem de Bruijn @ 2016-04-04 22:23 UTC (permalink / raw)
To: David Miller
Cc: Network Development, Sam Kumar, Eric Dumazet, Willem de Bruijn
On Mon, Apr 4, 2016 at 5:49 PM, David Miller <davem@davemloft.net> wrote:
> From: Willem de Bruijn <willemdebruijn.kernel@gmail.com>
> Date: Sun, 3 Apr 2016 19:29:49 -0400
>
>> From: Willem de Bruijn <willemb@google.com>
>>
>> Support peeking at a non-zero offset for UDP sockets. Match the
>> existing behavior on Unix datagram sockets.
>>
>> 1/4 makes the sk_peek_offset functions safe to use outside locks
>> 2/4 removes udp headers before enqueue, to simplify offset arithmetic
>> 3/4 introduces SO_PEEK_OFFSET support
>> 4/4 moves sk->sk_peek_off on read, to match Unix socket semantics.
>
> I don't see how you can separate patches #3 and #4.
>
> Once you hook up the socket operation, the user can successfully use
> the feature and therefore must receive the full set of semantics.
Okay, I'll squash the two patches.
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2016-04-04 22:24 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2016-04-03 23:29 [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 1/4] sock: convert sk_peek_offset functions to WRITE_ONCE Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 2/4] udp: remove headers from UDP packets before queueing Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 3/4] udp: enable MSG_PEEK at non-zero offset Willem de Bruijn
2016-04-03 23:29 ` [PATCH net-next 4/4] udp: move peek offset on read and peek Willem de Bruijn
2016-04-04 21:49 ` [PATCH net-next 0/4] udp: support SO_PEEK_OFFSET David Miller
2016-04-04 22:23 ` Willem de Bruijn
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).