Ability to peek full socket queue
Subsystems (6)
cover Ability to peek full socket queue
Hi.
This is an attempt to implement the ability to read socket's queue without removing skbs from it. Using MSG_PEEK doesn't work for unix sockets, both dgram and stream.
The proposal is to implement the SO_PEEK_OFF sockopt which specifies an offset in bytes where to start peeking the data from.
I've already sent an example of how this can look, and since nobody objected about the concept itself, here's the "official" v1. This includes all the unix socket types and (hopefully) addresses locking issues David pointed out.
PATCH 1/6 datagram: Factor out sk queue referencing
This makes lines shorter and simplifies further patching.
--- net/core/datagram.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)
net/core/datagram.c +5 -4
@@ -180,18 +180,19 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,* However, this function was correct in any case. 8) */ unsigned long cpu_flags; +struct sk_buff_head *queue = &sk->sk_receive_queue; -spin_lock_irqsave (&sk->sk_receive_queue.lock, cpu_flags); - skb =skb_peek (&sk->sk_receive_queue); +spin_lock_irqsave (&queue->lock, cpu_flags); + skb =skb_peek (queue);if (skb) { *peeked = skb->peeked;if (flags &MSG_PEEK ) { skb->peeked =1 ;atomic_inc (&skb->users); }else -__skb_unlink (skb, &sk->sk_receive_queue); +__skb_unlink (skb, queue); } -spin_unlock_irqrestore (&sk->sk_receive_queue.lock, cpu_flags); +spin_unlock_irqrestore (&queue->lock, cpu_flags);if (skb)return skb;
Signature · 1 line
1.5.5.6
Re: [PATCH 1/6] datagram: Factor out sk queue referencing
net/core/datagram.c
Quoted 9 lines · Pavel Emelyanov
This makes lines shorter and simplifies further patching.
Signed-off-by Pavel Emelyanov <[email protected]>--- net/core/datagram.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)net/core/datagram.c +0
-0
Re: [PATCH 1/6] datagram: Factor out sk queue referencing
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:39:19 +0100
Quoted 5 lines · Pavel Emelyanov
Quoted 4 lines
This makes lines shorter and simplifies further patching.
Signed-off-by Pavel Emelyanov <[email protected]>
Quoted 7 lines
net/core/datagram.c
Quoted 5 lines
--- net/core/datagram.c | 9 +++++---- 1 files changed, 5 insertions(+), 4 deletions(-)net/core/datagram.c +0
-0Acked-by Eric Dumazet <[email protected]>
Applied.
PATCH 2/6 datagram: Add offset argument to __skb_recv_datagram
In reply to Pavel EmelyanovThis one is only considered for MSG_PEEK flag and the value pointed by it specifies where to start peeking bytes from. If the offset happens to point into the middle of the returned skb, the offset within this skb is put back to this very argument.
--- include/linux/skbuff.h | 2 +- net/core/datagram.c | 21 +++++++++++++-------- net/ipv4/udp.c | 4 ++-- net/ipv6/udp.c | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-)
include/linux/skbuff.h +1 -1
@@ -2046,7 +2046,7 @@ static inline void skb_frag_add_head(struct sk_buff *skb, struct sk_buff *frag)for (iter =skb_shinfo (skb)->frag_list; iter; iter = iter->next) extern struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags, -int *peeked,int *err); +int *peeked,int *off,int *err);extern struct sk_buff *skb_recv_datagram (struct sock *sk,unsigned flags,int noblock,int *err); extern unsigned int datagram_poll(struct file *file, struct socket *sock,
net/core/datagram.c +13 -8
@@ -132,6 +132,8 @@ out_noerr:* __skb_recv_datagram - Receive a datagram skbuff * @sk: socket * @flags: MSG_ flags +* @off: an offset in bytes to peek skb from. Returns an offset +* within an skb where data actually starts * @peeked: returns non-zero if this packet has been seen before * @err: error code returned *
@@ -158,7 +160,7 @@ out_noerr:* the standard around please. */ struct sk_buff *__skb_recv_datagram (struct sock *sk,unsigned flags, -int *peeked,int *err) +int *peeked,int *off,int *err) {struct sk_buff *skb;long timeo;
@@ -183,19 +185,22 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,struct sk_buff_head *queue = &sk->sk_receive_queue;spin_lock_irqsave (&queue->lock, cpu_flags); - skb =skb_peek (queue); -if (skb) { + skb_queue_walk(queue, skb) { *peeked = skb->peeked;if (flags &MSG_PEEK ) { +if (*off >= skb->len) { + *off -= skb->len; +continue ; + } skb->peeked =1 ;atomic_inc (&skb->users); }else __skb_unlink (skb, queue); - } -spin_unlock_irqrestore (&queue->lock, cpu_flags); -if (skb) +spin_unlock_irqrestore (&queue->lock, cpu_flags);return skb; + } +spin_unlock_irqrestore (&queue->lock, cpu_flags);/* User doesn't want to wait */ error = -EAGAIN ;
@@ -215,10 +220,10 @@ EXPORT_SYMBOL(__skb_recv_datagram);struct sk_buff *skb_recv_datagram (struct sock *sk,unsigned flags,int noblock,int *err) { -int peeked; +int peeked, off =0 ;return __skb_recv_datagram (sk, flags | (noblock ?MSG_DONTWAIT :0 ), - &peeked, err); + &peeked, &off, err); }EXPORT_SYMBOL (skb_recv_datagram);
net/ipv4/udp.c +2 -2
@@ -1167,7 +1167,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name;struct sk_buff *skb;unsigned int ulen, copied; -int peeked; +int peeked, off =0 ;int err;int is_udplite =IS_UDPLITE (sk);bool slow;
@@ -1183,7 +1183,7 @@ int udp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, try_again: skb =__skb_recv_datagram (sk, flags | (noblock ?MSG_DONTWAIT :0 ), - &peeked, &err); + &peeked, &off, &err);if (!skb) goto out;
net/ipv6/udp.c +2 -2
@@ -342,7 +342,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk,struct inet_sock *inet =inet_sk (sk);struct sk_buff *skb;unsigned int ulen, copied; -int peeked; +int peeked, off =0 ;int err;int is_udplite =IS_UDPLITE (sk);int is_udp4;
@@ -359,7 +359,7 @@ int udpv6_recvmsg(struct kiocb *iocb, struct sock *sk, try_again: skb =__skb_recv_datagram (sk, flags | (noblock ?MSG_DONTWAIT :0 ), - &peeked, &err); + &peeked, &off, &err);if (!skb) goto out;
Signature · 1 line
1.5.5.6
Re: [PATCH 2/6] datagram: Add offset argument to __skb_recv_datagram
Quoted 5 lines · Pavel Emelyanov
This one is only considered for
MSG_PEEKflag and the value pointed by it specifies where to start peeking bytes from. If the offset happens to point into the middle of the returned skb, the offset within this skb is put back to this very argument.
Quoted 8 lines
Signed-off-by Pavel Emelyanov <[email protected]>--- include/linux/skbuff.h | 2 +- net/core/datagram.c | 21 +++++++++++++-------- net/ipv4/udp.c | 4 ++-- net/ipv6/udp.c | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-)
Re: [PATCH 2/6] datagram: Add offset argument to __skb_recv_datagram
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:40:32 +0100
Quoted 8 lines · Pavel Emelyanov
Quoted 7 lines
This one is only considered for
MSG_PEEKflag and the value pointed by it specifies where to start peeking bytes from. If the offset happens to point into the middle of the returned skb, the offset within this skb is put back to this very argument.Signed-off-by Pavel Emelyanov <[email protected]>
Quoted 8 lines
Quoted 6 lines
--- include/linux/skbuff.h | 2 +- net/core/datagram.c | 21 +++++++++++++-------- net/ipv4/udp.c | 4 ++-- net/ipv6/udp.c | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-)Acked-by Eric Dumazet <[email protected]>
Applied.
PATCH 3/6 skb: Add skb_peek_next helper
In reply to Pavel Emelyanov--- include/linux/skbuff.h | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)
include/linux/skbuff.h +18 -0
@@ -877,6 +877,24 @@ static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) }/** +* skb_peek_next - peek skb following the given one from a queue +* @skb: skb to start from +* @list_: list to peek at +* +* Returns %NULL when the end of the list is met or a pointer to the +* next element. The reference count is not incremented and the +* reference is therefore volatile. Use with caution. +*/ +static inline struct sk_buff *skb_peek_next (struct sk_buff *skb, +const struct sk_buff_head *list_) +{ +struct sk_buff *next = skb->next; +if (next == (struct sk_buff *)list_) + next =NULL ; +return next; +} + +/** * skb_peek_tail - peek at the tail of an &sk_buff_head * @list_: list to peek at *
Signature · 1 line
1.5.5.6
Re: [PATCH 3/6] skb: Add skb_peek_next helper
Quoted 25 lines · Pavel Emelyanov
Signed-off-by Pavel Emelyanov <[email protected]>--- include/linux/skbuff.h | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-)include/linux/skbuff.h +11
-0@@ -877,6 +877,24 @@ static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) }/** +* skb_peek_next - peek skb following the given one from a queue +* @skb: skb to start from +* @list_: list to peek at +* +* Returns %NULL when the end of the list is met or a pointer to the +* next element. The reference count is not incremented and the +* reference is therefore volatile. Use with caution. +*/ +static inline struct sk_buff *skb_peek_next (struct sk_buff *skb, +const struct sk_buff_head *list_) +{
include/linux/skbuff.h static inline struct sk_buff *skb_peek(const struct sk_buff_head *list_) · line 900
Quoted 10 lines
include/linux/skbuff.h +7
-0+struct sk_buff *next = skb->next; +if (next == (struct sk_buff *)list_) + next =NULL ; +return next; +} + +/** * skb_peek_tail - peek at the tail of an &sk_buff_head * @list_: list to peek at *
Re: [PATCH 3/6] skb: Add skb_peek_next helper
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:43:53 +0100
Quoted 3 lines · Pavel Emelyanov
Quoted 1 line
Signed-off-by Pavel Emelyanov <[email protected]>Acked-by Eric Dumazet <[email protected]>
Applied.
PATCH 4/6 sock: Introduce the SO_PEEK_OFF sock option
In reply to Pavel EmelyanovThis one specifies where to start MSG_PEEK-ing queue data from. When set to negative value means that MSG_PEEK works as ususally -- peeks from the head of the queue always.
When some bytes are peeked from queue and the peeking offset is non negative it is moved forward so that the next peek will return next portion of data.
When non-peeking recvmsg occurs and the peeking offset is non negative is is moved backward so that the next peek will still peek the proper data (i.e. the one that would have been picked if there were no non peeking recv in between).
The offset is set using per-proto opteration to let the protocol handle the locking issues and to check whether the peeking offset feature is supported by the protocol the socket belongs to.
--- include/asm-generic/socket.h | 1 + include/linux/net.h | 1 + include/net/sock.h | 25 +++++++++++++++++++++++++ net/core/sock.c | 13 +++++++++++++ 4 files changed, 40 insertions(+), 0 deletions(-)
include/asm-generic/socket.h +1 -0
@@ -66,5 +66,6 @@#define SO_RXQ_OVFL 40#define SO_WIFI_STATUS 41 +#define SO_PEEK_OFF 42#define SCM_WIFI_STATUS SO_WIFI_STATUS#endif /* __ASM_GENERIC_SOCKET_H */
include/linux/net.h +1 -0
@@ -206,6 +206,7 @@ struct proto_ops { int offset, size_t size, int flags);ssize_t (*splice_read)(struct socket *sock,loff_t *ppos,struct pipe_inode_info *pipe,size_t len,unsigned int flags); +void (*set_peek_off)(struct sock *sk,int val); };#define DECLARE_SOCKADDR (type, dst, src) \
include/net/sock.h +25 -0
@@ -357,6 +357,7 @@ struct sock {struct page *sk_sndmsg_page;struct sk_buff *sk_send_head;__u32 sk_sndmsg_off; +__s32 sk_peek_off;int sk_write_pending;#ifdef CONFIG_SECURITY void *sk_security;
@@ -373,6 +374,30 @@ struct sock {void (*sk_destruct)(struct sock *sk); }; +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 ; +} + +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 ; + } +} + +static inline void sk_peek_offset_fwd (struct sock *sk,int val) +{ +if (sk->sk_peek_off >=0 ) + sk->sk_peek_off += val; +} +/* * Hashed lists helper routines */
net/core/sock.c +13 -0
@@ -793,6 +793,12 @@ set_rcvbuf:sock_valbool_flag (sk,SOCK_WIFI_STATUS , valbool);break ; +case SO_PEEK_OFF : +if (sock->ops->set_peek_off) + sock->ops->set_peek_off (sk, val); +else + ret = -EOPNOTSUPP ; +break ;default : ret = -ENOPROTOOPT ;break ;
@@ -1018,6 +1024,12 @@ int sock_getsockopt(struct socket *sock, int level, int optname, v.val = !!sock_flag (sk,SOCK_WIFI_STATUS );break ; +case SO_PEEK_OFF : +if (!sock->ops->set_peek_off) +return -EOPNOTSUPP ; + + v.val = sk->sk_peek_off; +break ;default :return -ENOPROTOOPT ; }
@@ -2092,6 +2104,7 @@ void sock_init_data(struct socket *sock, struct sock *sk) sk->sk_sndmsg_page =NULL ; sk->sk_sndmsg_off =0 ; + sk->sk_peek_off =-1 ; sk->sk_peer_pid =NULL ; sk->sk_peer_cred =NULL ;
Signature · 1 line
1.5.5.6
Re: [PATCH 4/6] sock: Introduce the SO_PEEK_OFF sock option
Quoted 31 lines · Pavel Emelyanov
This one specifies where to start MSG_PEEK-ing queue data from. When set to negative value means that
MSG_PEEKworks as ususally -- peeks from the head of the queue always.When some bytes are peeked from queue and the peeking offset is non negative it is moved forward so that the next peek will return next portion of data.
When non-peeking recvmsg occurs and the peeking offset is non negative is is moved backward so that the next peek will still peek the proper data (i.e. the one that would have been picked if there were no non peeking recv in between).
The offset is set using per-proto opteration to let the protocol handle the locking issues and to check whether the peeking offset feature is supported by the protocol the socket belongs to.
Signed-off-by Pavel Emelyanov <[email protected]>--- include/asm-generic/socket.h | 1 + include/linux/net.h | 1 + include/net/sock.h | 25 +++++++++++++++++++++++++ net/core/sock.c | 13 +++++++++++++ 4 files changed, 40 insertions(+), 0 deletions(-)include/asm-generic/socket.h +0
-0
include/asm-generic/socket.h line 70
Quoted 5 lines
include/asm-generic/socket.h +1
-0@@ -66,5 +66,6 @@#define SO_RXQ_OVFL 40#define SO_WIFI_STATUS 41 +#define SO_PEEK_OFF 42#define SCM_WIFI_STATUS SO_WIFI_STATUS
small note : should be moved down by one line, after SCM_WIFI_STATUS
Other than that,
David Miller
maintainerRe: [PATCH 4/6] sock: Introduce the SO_PEEK_OFF sock option
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:45:50 +0100
Quoted 19 lines · Pavel Emelyanov
Quoted 18 lines
This one specifies where to start MSG_PEEK-ing queue data from. When set to negative value means that
MSG_PEEKworks as ususally -- peeks from the head of the queue always.When some bytes are peeked from queue and the peeking offset is non negative it is moved forward so that the next peek will return next portion of data.
When non-peeking recvmsg occurs and the peeking offset is non negative is is moved backward so that the next peek will still peek the proper data (i.e. the one that would have been picked if there were no non peeking recv in between).
The offset is set using per-proto opteration to let the protocol handle the locking issues and to check whether the peeking offset feature is supported by the protocol the socket belongs to.
Signed-off-by Pavel Emelyanov <[email protected]>
...
Quoted 4 lines
small note : should be moved down by one line, after
SCM_WIFI_STATUSOther than that,
You also didn't update all of the arch/*/include/asm/socket.h files.
I took care of all of this, but what should have been a simple matter of me typing "git am --signoff foo.mbox" and "make" turned into a 10 minute exercise in raking leaves. :-/
PATCH 5/6 unix: Support peeking offset for datagram and seqpacket sockets
In reply to Pavel EmelyanovThe sk_peek_off manipulations are protected with the unix_sk->readlock mutex. This mutex is enough since all we need is to syncronize setting the offset vs reading the queue head. The latter is fully covered with the mentioned lock.
The recently added __skb_recv_datagram's offset is used to pick the skb to read the data from.
--- net/unix/af_unix.c | 30 +++++++++++++++++++++++++----- 1 files changed, 25 insertions(+), 5 deletions(-)
net/unix/af_unix.c +25 -5
@@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,static int unix_seqpacket_recvmsg (struct kiocb *,struct socket *,struct msghdr *,size_t ,int ); +static void unix_set_peek_off (struct sock *sk,int val) +{ +struct unix_sock *u =unix_sk (sk); + +mutex_lock (&u->readlock); + sk->sk_peek_off = val; +mutex_unlock (&u->readlock); +} + +static const struct proto_ops unix_stream_ops = { .family =PF_UNIX , .owner =THIS_MODULE ,
@@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = { .recvmsg = unix_dgram_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, };static const struct proto_ops unix_seqpacket_ops = {
@@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = { .recvmsg = unix_seqpacket_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, };static struct proto unix_proto = {
@@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,int noblock = flags &MSG_DONTWAIT ;struct sk_buff *skb;int err; +int peeked, skip; err = -EOPNOTSUPP ;if (flags&MSG_OOB )
@@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } - skb =skb_recv_datagram (sk, flags, noblock, &err); + skip =sk_peek_offset (sk, flags); + + skb =__skb_recv_datagram (sk, flags, &peeked, &skip, &err);if (!skb) {unix_state_lock (sk);/* Signal EOF on disconnected non-blocking SEQPACKET socket. */
@@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,if (msg->msg_name)unix_copy_addr (msg, skb->sk); -if (size > skb->len) - size = skb->len; -else if (size < skb->len) +if (size > skb->len - skip) + size = skb->len - skip; +else if (size < skb->len - skip) msg->msg_flags |=MSG_TRUNC ; - err =skb_copy_datagram_iovec (skb,0 , msg->msg_iov, size); + err =skb_copy_datagram_iovec (skb, skip, msg->msg_iov, size);if (err) goto out_free;
@@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,if (!(flags &MSG_PEEK )) {if (UNIXCB (skb).fp)unix_detach_fds (siocb->scm, skb); + +sk_peek_offset_bwd (sk, skb->len); }else {/* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8)
@@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,clearly however! */ + +sk_peek_offset_fwd (sk, size); +if (UNIXCB (skb).fp) siocb->scm->fp =scm_fp_dup (UNIXCB (skb).fp); }
Signature · 1 line
1.5.5.6
Re: [PATCH 5/6] unix: Support peeking offset for datagram and seqpacket sockets
Quoted 4 lines · Pavel Emelyanov
The
sk_peek_offmanipulations are protected with theunix_sk->readlockmutex. This mutex is enough since all we need is to syncronize setting the offset vs reading the queue head. The latter is fully covered with the mentioned lock.
Quoted 8 lines
The recently added __skb_recv_datagram's offset is used to pick the skb to read the data from.
Signed-off-by Pavel Emelyanov <[email protected]>--- net/unix/af_unix.c | 30 +++++++++++++++++++++++++----- 1 files changed, 25 insertions(+), 5 deletions(-)
Very nice !
Re: [PATCH 5/6] unix: Support peeking offset for datagram and seqpacket sockets
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:49:56 +0100
Quoted 10 lines · Pavel Emelyanov
Quoted 9 lines
The
sk_peek_offmanipulations are protected with theunix_sk->readlockmutex. This mutex is enough since all we need is to syncronize setting the offset vs reading the queue head. The latter is fully covered with the mentioned lock.The recently added __skb_recv_datagram's offset is used to pick the skb to read the data from.
Signed-off-by Pavel Emelyanov <[email protected]>
Quoted 7 lines
Quoted 3 lines
--- net/unix/af_unix.c | 30 +++++++++++++++++++++++++----- 1 files changed, 25 insertions(+), 5 deletions(-)Very nice !
Acked-by Eric Dumazet <[email protected]>
Applied.
PATCH 6/6 unix: Support peeking offset for stream sockets
In reply to Pavel EmelyanovThe same here -- we can protect the sk_peek_off manipulations with the unix_sk->readlock mutex.
The peeking of data from a stream socket is done in the datagram style, i.e. even if there's enough room for more data in the user buffer, only the head skb's data is copied in there. This feature is preserved when peeking data from a given offset -- the data is read till the nearest skb's boundary.
--- net/unix/af_unix.c | 20 ++++++++++++++++++-- 1 files changed, 18 insertions(+), 2 deletions(-)
net/unix/af_unix.c +18 -2
@@ -559,6 +559,7 @@ static const struct proto_ops unix_stream_ops = { .recvmsg = unix_stream_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, + .set_peek_off = unix_set_peek_off, };static const struct proto_ops unix_dgram_ops = {
@@ -1904,6 +1905,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,int target;int err =0 ;long timeo; +int skip; err = -EINVAL ;if (sk->sk_state !=TCP_ESTABLISHED )
@@ -1933,12 +1935,15 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, goto out; } + skip =sk_peek_offset (sk, flags); + do { int chunk; struct sk_buff *skb; unix_state_lock(sk); skb = skb_peek(&sk->sk_receive_queue); +again: if (skb == NULL) { unix_sk(sk)->recursion_level = 0; if (copied >= target)
@@ -1973,6 +1978,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,unix_state_unlock (sk);break ; } + +if (skip >= skb->len) { + skip -= skb->len; + skb =skb_peek_next (skb, &sk->sk_receive_queue); + goto again; + } +unix_state_unlock (sk);if (check_creds) {
@@ -1992,8 +2004,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, sunaddr =NULL ; } - chunk = min_t(unsigned int, skb->len, size); -if (memcpy_toiovec (msg->msg_iov, skb->data, chunk)) { + chunk = min_t(unsigned int, skb->len - skip, size); +if (memcpy_toiovec (msg->msg_iov, skb->data + skip, chunk)) {if (copied ==0 ) copied = -EFAULT ;break ;
@@ -2005,6 +2017,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,if (!(flags &MSG_PEEK )) {skb_pull (skb, chunk); +sk_peek_offset_bwd (sk, chunk); +if (UNIXCB (skb).fp)unix_detach_fds (siocb->scm, skb);
@@ -2022,6 +2036,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,if (UNIXCB (skb).fp) siocb->scm->fp =scm_fp_dup (UNIXCB (skb).fp); +sk_peek_offset_fwd (sk, chunk); +break ; } }while (size);
Signature · 1 line
1.5.5.6
Re: [PATCH 6/6] unix: Support peeking offset for stream sockets
Quoted 9 lines · Pavel Emelyanov
The same here -- we can protect the
sk_peek_offmanipulations with theunix_sk->readlockmutex.The peeking of data from a stream socket is done in the datagram style, i.e. even if there's enough room for more data in the user buffer, only the head skb's data is copied in there. This feature is preserved when peeking data from a given offset -- the data is read till the nearest skb's boundary.
Quoted 3 lines
Signed-off-by Pavel Emelyanov <[email protected]>---
Re: [PATCH 6/6] unix: Support peeking offset for stream sockets
From: Eric Dumazet <[email protected]>
Date: Tue, 21 Feb 2012 18:51:19 +0100
Quoted 10 lines · Pavel Emelyanov
Quoted 9 lines
The same here -- we can protect the
sk_peek_offmanipulations with theunix_sk->readlockmutex.The peeking of data from a stream socket is done in the datagram style, i.e. even if there's enough room for more data in the user buffer, only the head skb's data is copied in there. This feature is preserved when peeking data from a given offset -- the data is read till the nearest skb's boundary.
Quoted 5 lines
Quoted 3 lines
Signed-off-by Pavel Emelyanov <[email protected]>---
Acked-by Eric Dumazet <[email protected]>
Applied.