net: cleanup datagram receive helpers
Subsystems (5)
Paolo Abeni
maintainerPATCH v2 1/2 unix: uses an atomic type for scm files accounting
In reply to Paolo AbeniSo the scm_stat_{add,del} helper can be invoked with no additional lock held.
This clean-up the code a bit and will make the next patch easier.
--- include/net/af_unix.h | 2 +- net/unix/af_unix.c | 21 ++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-)
include/net/af_unix.h +1 -1
@@ -42,7 +42,7 @@ struct unix_skb_parms { } __randomize_layout;struct scm_stat { -u32 nr_fds; +atomic_t nr_fds; };#define UNIXCB (skb) (*(struct unix_skb_parms *)&((skb)->cb))
net/unix/af_unix.c +6 -15
@@ -689,7 +689,8 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)if (sk) { u =unix_sk (sock->sk); -seq_printf (m,"scm_fds: %u\n" ,READ_ONCE (u->scm_stat.nr_fds)); +seq_printf (m,"scm_fds: %u\n" , +atomic_read (&u->scm_stat.nr_fds)); } }
@@ -1598,10 +1599,8 @@ static void scm_stat_add(struct sock *sk, struct sk_buff *skb)struct scm_fp_list *fp =UNIXCB (skb).fp;struct unix_sock *u =unix_sk (sk); -lockdep_assert_held (&sk->sk_receive_queue.lock); -if (unlikely (fp && fp->count)) - u->scm_stat.nr_fds += fp->count; +atomic_add (fp->count, &u->scm_stat.nr_fds); }static void scm_stat_del (struct sock *sk,struct sk_buff *skb)
@@ -1609,10 +1608,8 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)struct scm_fp_list *fp =UNIXCB (skb).fp;struct unix_sock *u =unix_sk (sk); -lockdep_assert_held (&sk->sk_receive_queue.lock); -if (unlikely (fp && fp->count)) - u->scm_stat.nr_fds -= fp->count; +atomic_sub (fp->count, &u->scm_stat.nr_fds); }/*
@@ -1801,10 +1798,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,if (sock_flag (other,SOCK_RCVTSTAMP ))__net_timestamp (skb);maybe_add_creds (skb, sock, other); -spin_lock (&other->sk_receive_queue.lock);scm_stat_add (other, skb); -__skb_queue_tail (&other->sk_receive_queue, skb); -spin_unlock (&other->sk_receive_queue.lock); +skb_queue_tail (&other->sk_receive_queue, skb);unix_state_unlock (other); other->sk_data_ready (other);sock_put (other);
@@ -1906,10 +1901,8 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, goto pipe_err_free;maybe_add_creds (skb, sock, other); -spin_lock (&other->sk_receive_queue.lock);scm_stat_add (other, skb); -__skb_queue_tail (&other->sk_receive_queue, skb); -spin_unlock (&other->sk_receive_queue.lock); +skb_queue_tail (&other->sk_receive_queue, skb);unix_state_unlock (other); other->sk_data_ready (other); sent += size;
@@ -2405,9 +2398,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,sk_peek_offset_bwd (sk, chunk);if (UNIXCB (skb).fp) { -spin_lock (&sk->sk_receive_queue.lock);scm_stat_del (sk, skb); -spin_unlock (&sk->sk_receive_queue.lock);unix_detach_fds (&scm, skb); }
Signature · 1 line
2.21.1
Paolo Abeni
maintainerv2 cover net: cleanup datagram receive helpers
Several receive helpers have an optional destructor argument, which uglify the code a bit and is taxed by retpoline overhead.
This series refactor the code so that we can drop such optional argument, cleaning the helpers a bit and avoiding an indirect call in fast path.
The first patch refactor a bit the caller, so that the second patch actually dropping the argument is more straight-forward
v1 -> v2:
- call scm_stat_del() only when not peeking - Kirill
- fix build issue with CONFIG_INET_ESPINTCP
Paolo Abeni (2):
unix: uses an atomic type for scm files accounting
net: datagram: drop 'destructor' argument from several helpers
include/linux/skbuff.h | 12 ++---------- include/net/af_unix.h | 2 +- net/core/datagram.c | 25 +++++++------------------ net/ipv4/udp.c | 14 ++++++++------ net/unix/af_unix.c | 28 +++++++++++----------------- net/xfrm/espintcp.c | 2 +- 6 files changed, 30 insertions(+), 53 deletions(-)
Signature · 1 line
2.21.1
Paolo Abeni
maintainerPATCH v2 2/2 net: datagram: drop 'destructor' argument from several helpers
The only users for such argument are the UDP protocol and the UNIX socket family. We can safely reclaim the accounted memory directly from the UDP code and, after the previous patch, we can do scm stats accounting outside the datagram helpers.
Overall this cleans up a bit some datagram-related helpers, and avoids an indirect call per packet in the UDP receive path.
v1 -> v2:
- call scm_stat_del() only when not peeking - Kirill
- fix build issue with CONFIG_INET_ESPINTCP
--- include/linux/skbuff.h | 12 ++---------- net/core/datagram.c | 25 +++++++------------------ net/ipv4/udp.c | 14 ++++++++------ net/unix/af_unix.c | 7 +++++-- net/xfrm/espintcp.c | 2 +- 5 files changed, 23 insertions(+), 37 deletions(-)
include/linux/skbuff.h +2 -10
@@ -3514,23 +3514,15 @@ int __skb_wait_for_more_packets(struct sock *sk, struct sk_buff_head *queue,struct sk_buff *__skb_try_recv_from_queue (struct sock *sk,struct sk_buff_head *queue,unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb),int *off,int *err,struct sk_buff **last);struct sk_buff *__skb_try_recv_datagram (struct sock *sk,struct sk_buff_head *queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err, +unsigned int flags,int *off,int *err,struct sk_buff **last);struct sk_buff *__skb_recv_datagram (struct sock *sk,struct sk_buff_head *sk_queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err); +unsigned int flags,int *off,int *err);struct sk_buff *skb_recv_datagram (struct sock *sk,unsigned flags,int noblock,int *err); __poll_t datagram_poll(struct file *file, struct socket *sock,
net/core/datagram.c +7 -18
@@ -166,8 +166,6 @@ static struct sk_buff *skb_set_peeked(struct sk_buff *skb)struct sk_buff *__skb_try_recv_from_queue (struct sock *sk,struct sk_buff_head *queue,unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb),int *off,int *err,struct sk_buff **last) {
@@ -198,8 +196,6 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,refcount_inc (&skb->users); }else {__skb_unlink (skb, queue); -if (destructor) -destructor (sk, skb); } *off = _off;return skb;
@@ -212,7 +208,6 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,* @sk: socket * @queue: socket queue from which to receive * @flags: MSG\_ flags -* @destructor: invoked under the receive lock on successful dequeue * @off: an offset in bytes to peek skb from. Returns an offset * within an skb where data actually starts * @err: error code returned
@@ -245,10 +240,7 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,*/ struct sk_buff *__skb_try_recv_datagram (struct sock *sk,struct sk_buff_head *queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err, +unsigned int flags,int *off,int *err,struct sk_buff **last) {struct sk_buff *skb;
@@ -269,8 +261,8 @@ struct sk_buff *__skb_try_recv_datagram(struct sock *sk,* However, this function was correct in any case. 8) */ spin_lock_irqsave (&queue->lock, cpu_flags); - skb =__skb_try_recv_from_queue (sk, queue, flags, destructor, - off, &error, last); + skb =__skb_try_recv_from_queue (sk, queue, flags, off, &error, + last);spin_unlock_irqrestore (&queue->lock, cpu_flags);if (error) goto no_packet;
@@ -293,10 +285,7 @@ EXPORT_SYMBOL(__skb_try_recv_datagram);struct sk_buff *__skb_recv_datagram (struct sock *sk,struct sk_buff_head *sk_queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err) +unsigned int flags,int *off,int *err) {struct sk_buff *skb, *last;long timeo;
@@ -304,8 +293,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, timeo =sock_rcvtimeo (sk, flags &MSG_DONTWAIT ); do { - skb = __skb_try_recv_datagram(sk, sk_queue, flags, destructor, - off, err, &last); + skb = __skb_try_recv_datagram(sk, sk_queue, flags, off, err, + &last); if (skb) return skb;
@@ -326,7 +315,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags,return __skb_recv_datagram (sk, &sk->sk_receive_queue, flags | (noblock ?MSG_DONTWAIT :0 ), -NULL , &off, err); + &off, err); }EXPORT_SYMBOL (skb_recv_datagram);
net/ipv4/udp.c +8 -6
@@ -1671,10 +1671,11 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags, error = -EAGAIN ; do { spin_lock_bh(&queue->lock); - skb = __skb_try_recv_from_queue(sk, queue, flags, - udp_skb_destructor, - off, err, &last); + skb = __skb_try_recv_from_queue(sk, queue, flags, off, + err, &last); if (skb) { + if (!(flags & MSG_PEEK)) + udp_skb_destructor(sk, skb); spin_unlock_bh(&queue->lock); return skb; }
@@ -1692,9 +1693,10 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags,spin_lock (&sk_queue->lock);skb_queue_splice_tail_init (sk_queue, queue); - skb =__skb_try_recv_from_queue (sk, queue, flags, - udp_skb_dtor_locked, - off, err, &last); + skb =__skb_try_recv_from_queue (sk, queue, flags, off, + err, &last); +if (skb && !(flags &MSG_PEEK )) +udp_skb_dtor_locked (sk, skb);spin_unlock (&sk_queue->lock);spin_unlock_bh (&queue->lock);if (skb)
net/unix/af_unix.c +5 -2
@@ -2102,9 +2102,12 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, skip =sk_peek_offset (sk, flags); skb =__skb_try_recv_datagram (sk, &sk->sk_receive_queue, flags, - scm_stat_del, &skip, &err, &last); -if (skb) + &skip, &err, &last); +if (skb) { +if (!(flags &MSG_PEEK )) +scm_stat_del (sk, skb);break ; + }mutex_unlock (&u->iolock);
net/xfrm/espintcp.c +1 -1
@@ -100,7 +100,7 @@ static int espintcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, flags |= nonblock ?MSG_DONTWAIT :0 ; - skb =__skb_recv_datagram (sk, &ctx->ike_queue, flags,NULL , &off, &err); + skb =__skb_recv_datagram (sk, &ctx->ike_queue, flags, &off, &err);if (!skb)return err;
Signature · 1 line
2.21.1
Re: [PATCH net-next v2 1/2] unix: uses an atomic type for scm files accounting
In reply to Paolo AbeniQuoted 7 lines · Paolo Abeni
So the scm_stat_{add,del} helper can be invoked with no additional lock held.
This clean-up the code a bit and will make the next patch easier.
Signed-off-by Paolo Abeni <[email protected]>
Quoted 91 lines
--- include/net/af_unix.h | 2 +- net/unix/af_unix.c | 21 ++++++--------------- 2 files changed, 7 insertions(+), 16 deletions(-)include/net/af_unix.h +1
-1@@ -42,7 +42,7 @@ struct unix_skb_parms { } __randomize_layout;struct scm_stat { -u32 nr_fds; +atomic_t nr_fds; };#define UNIXCB (skb) (*(struct unix_skb_parms *)&((skb)->cb))net/unix/af_unix.c +6
-15@@ -689,7 +689,8 @@ static void unix_show_fdinfo(struct seq_file *m, struct socket *sock)if (sk) { u =unix_sk (sock->sk); -seq_printf (m,"scm_fds: %u\n" ,READ_ONCE (u->scm_stat.nr_fds)); +seq_printf (m,"scm_fds: %u\n" , +atomic_read (&u->scm_stat.nr_fds)); } }@@ -1598,10 +1599,8 @@ static void scm_stat_add(struct sock *sk, struct sk_buff *skb)struct scm_fp_list *fp =UNIXCB (skb).fp;struct unix_sock *u =unix_sk (sk); -lockdep_assert_held (&sk->sk_receive_queue.lock); -if (unlikely (fp && fp->count)) - u->scm_stat.nr_fds += fp->count; +atomic_add (fp->count, &u->scm_stat.nr_fds); }static void scm_stat_del (struct sock *sk,struct sk_buff *skb)@@ -1609,10 +1608,8 @@ static void scm_stat_del(struct sock *sk, struct sk_buff *skb)struct scm_fp_list *fp =UNIXCB (skb).fp;struct unix_sock *u =unix_sk (sk); -lockdep_assert_held (&sk->sk_receive_queue.lock); -if (unlikely (fp && fp->count)) - u->scm_stat.nr_fds -= fp->count; +atomic_sub (fp->count, &u->scm_stat.nr_fds); }/* @@ -1801,10 +1798,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg,if (sock_flag (other,SOCK_RCVTSTAMP ))__net_timestamp (skb);maybe_add_creds (skb, sock, other); -spin_lock (&other->sk_receive_queue.lock);scm_stat_add (other, skb); -__skb_queue_tail (&other->sk_receive_queue, skb); -spin_unlock (&other->sk_receive_queue.lock); +skb_queue_tail (&other->sk_receive_queue, skb);unix_state_unlock (other); other->sk_data_ready (other);sock_put (other);@@ -1906,10 +1901,8 @@ static int unix_stream_sendmsg(struct socket *sock, struct msghdr *msg, goto pipe_err_free;maybe_add_creds (skb, sock, other); -spin_lock (&other->sk_receive_queue.lock);scm_stat_add (other, skb); -__skb_queue_tail (&other->sk_receive_queue, skb); -spin_unlock (&other->sk_receive_queue.lock); +skb_queue_tail (&other->sk_receive_queue, skb);unix_state_unlock (other); other->sk_data_ready (other); sent += size;@@ -2405,9 +2398,7 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state,sk_peek_offset_bwd (sk, chunk);if (UNIXCB (skb).fp) { -spin_lock (&sk->sk_receive_queue.lock);scm_stat_del (sk, skb); -spin_unlock (&sk->sk_receive_queue.lock);unix_detach_fds (&scm, skb); }
Re: [PATCH net-next v2 2/2] net: datagram: drop 'destructor' argument from several helpers
In reply to Paolo AbeniQuoted 5 lines · Paolo Abeni
The only users for such argument are the UDP protocol and the UNIX socket family. We can safely reclaim the accounted memory directly from the UDP code and, after the previous patch, we can do scm stats accounting outside the datagram helpers.
Quoted 8 lines
Overall this cleans up a bit some datagram-related helpers, and avoids an indirect call per packet in the UDP receive path.
v1 -> v2:
- callscm_stat_del()only when not peeking - Kirill
- fix build issue withCONFIG_INET_ESPINTCPSigned-off-by Paolo Abeni <[email protected]>
Quoted 189 lines
--- include/linux/skbuff.h | 12 ++---------- net/core/datagram.c | 25 +++++++------------------ net/ipv4/udp.c | 14 ++++++++------ net/unix/af_unix.c | 7 +++++-- net/xfrm/espintcp.c | 2 +- 5 files changed, 23 insertions(+), 37 deletions(-)include/linux/skbuff.h +2
-10@@ -3514,23 +3514,15 @@ int __skb_wait_for_more_packets(struct sock *sk, struct sk_buff_head *queue,struct sk_buff *__skb_try_recv_from_queue (struct sock *sk,struct sk_buff_head *queue,unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb),int *off,int *err,struct sk_buff **last);struct sk_buff *__skb_try_recv_datagram (struct sock *sk,struct sk_buff_head *queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err, +unsigned int flags,int *off,int *err,struct sk_buff **last);struct sk_buff *__skb_recv_datagram (struct sock *sk,struct sk_buff_head *sk_queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err); +unsigned int flags,int *off,int *err);struct sk_buff *skb_recv_datagram (struct sock *sk,unsigned flags,int noblock,int *err); __poll_t datagram_poll(struct file *file, struct socket *sock,net/core/datagram.c +7
-18@@ -166,8 +166,6 @@ static struct sk_buff *skb_set_peeked(struct sk_buff *skb)struct sk_buff *__skb_try_recv_from_queue (struct sock *sk,struct sk_buff_head *queue,unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb),int *off,int *err,struct sk_buff **last) {@@ -198,8 +196,6 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,refcount_inc (&skb->users); }else {__skb_unlink (skb, queue); -if (destructor) -destructor (sk, skb); } *off = _off;return skb;@@ -212,7 +208,6 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,* @sk: socket * @queue: socket queue from which to receive * @flags: MSG\_ flags -* @destructor: invoked under the receive lock on successful dequeue * @off: an offset in bytes to peek skb from. Returns an offset * within an skb where data actually starts * @err: error code returned @@ -245,10 +240,7 @@ struct sk_buff *__skb_try_recv_from_queue(struct sock *sk,*/ struct sk_buff *__skb_try_recv_datagram (struct sock *sk,struct sk_buff_head *queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err, +unsigned int flags,int *off,int *err,struct sk_buff **last) {struct sk_buff *skb;@@ -269,8 +261,8 @@ struct sk_buff *__skb_try_recv_datagram(struct sock *sk,* However, this function was correct in any case. 8) */ spin_lock_irqsave (&queue->lock, cpu_flags); - skb =__skb_try_recv_from_queue (sk, queue, flags, destructor, - off, &error, last); + skb =__skb_try_recv_from_queue (sk, queue, flags, off, &error, + last);spin_unlock_irqrestore (&queue->lock, cpu_flags);if (error) goto no_packet;@@ -293,10 +285,7 @@ EXPORT_SYMBOL(__skb_try_recv_datagram);struct sk_buff *__skb_recv_datagram (struct sock *sk,struct sk_buff_head *sk_queue, -unsigned int flags, -void (*destructor)(struct sock *sk, -struct sk_buff *skb), -int *off,int *err) +unsigned int flags,int *off,int *err) {struct sk_buff *skb, *last;long timeo;@@ -304,8 +293,8 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, timeo =sock_rcvtimeo (sk, flags &MSG_DONTWAIT ); do { - skb = __skb_try_recv_datagram(sk, sk_queue, flags, destructor, - off, err, &last); + skb = __skb_try_recv_datagram(sk, sk_queue, flags, off, err, + &last); if (skb) return skb;@@ -326,7 +315,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned int flags,return __skb_recv_datagram (sk, &sk->sk_receive_queue, flags | (noblock ?MSG_DONTWAIT :0 ), -NULL , &off, err); + &off, err); }EXPORT_SYMBOL (skb_recv_datagram);net/ipv4/udp.c +8
-6@@ -1671,10 +1671,11 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags, error = -EAGAIN ; do { spin_lock_bh(&queue->lock); - skb = __skb_try_recv_from_queue(sk, queue, flags, - udp_skb_destructor, - off, err, &last); + skb = __skb_try_recv_from_queue(sk, queue, flags, off, + err, &last); if (skb) { + if (!(flags & MSG_PEEK)) + udp_skb_destructor(sk, skb); spin_unlock_bh(&queue->lock); return skb; }@@ -1692,9 +1693,10 @@ struct sk_buff *__skb_recv_udp(struct sock *sk, unsigned int flags,spin_lock (&sk_queue->lock);skb_queue_splice_tail_init (sk_queue, queue); - skb =__skb_try_recv_from_queue (sk, queue, flags, - udp_skb_dtor_locked, - off, err, &last); + skb =__skb_try_recv_from_queue (sk, queue, flags, off, + err, &last); +if (skb && !(flags &MSG_PEEK )) +udp_skb_dtor_locked (sk, skb);spin_unlock (&sk_queue->lock);spin_unlock_bh (&queue->lock);if (skb)net/unix/af_unix.c +5
-2@@ -2102,9 +2102,12 @@ static int unix_dgram_recvmsg(struct socket *sock, struct msghdr *msg, skip =sk_peek_offset (sk, flags); skb =__skb_try_recv_datagram (sk, &sk->sk_receive_queue, flags, - scm_stat_del, &skip, &err, &last); -if (skb) + &skip, &err, &last); +if (skb) { +if (!(flags &MSG_PEEK )) +scm_stat_del (sk, skb);break ; + }mutex_unlock (&u->iolock);net/xfrm/espintcp.c +1
-1@@ -100,7 +100,7 @@ static int espintcp_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, flags |= nonblock ?MSG_DONTWAIT :0 ; - skb =__skb_recv_datagram (sk, &ctx->ike_queue, flags,NULL , &off, &err); + skb =__skb_recv_datagram (sk, &ctx->ike_queue, flags, &off, &err);if (!skb)return err;
Re: [PATCH net-next v2 2/2] net: datagram: drop 'destructor' argument from several helpers
Quoted 10 lines · Kirill Tkhai
Quoted 8 lines · Paolo Abeni
The only users for such argument are the UDP protocol and the UNIX socket family. We can safely reclaim the accounted memory directly from the UDP code and, after the previous patch, we can do scm stats accounting outside the datagram helpers.
Overall this cleans up a bit some datagram-related helpers, and avoids an indirect call per packet in the UDP receive path.
Quoted 7 lines
Quoted 5 lines
v1 -> v2:
- callscm_stat_del()only when not peeking - Kirill
- fix build issue withCONFIG_INET_ESPINTCPSigned-off-by Paolo Abeni <[email protected]>Reviewed-by Kirill Tkhai <[email protected]>
Nice cleanup, thanks!
David Miller
maintainerFrom: Paolo Abeni <[email protected]>
Date: Fri, 28 Feb 2020 14:45:20 +0100
Quoted 6 lines
Several receive helpers have an optional destructor argument, which uglify the code a bit and is taxed by retpoline overhead.
This series refactor the code so that we can drop such optional argument, cleaning the helpers a bit and avoiding an indirect call in fast path.
Quoted 6 lines
The first patch refactor a bit the caller, so that the second patch actually dropping the argument is more straight-forward
v1 -> v2:
- callscm_stat_del()only when not peeking - Kirill
- fix build issue withCONFIG_INET_ESPINTCP
Series applie, thanks Paolo.