aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2012-02-21 02:32:06 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-21 15:03:58 -0500
commitfc0d753641f7b919c7273d9bd21ae6ab45e757f3 (patch)
tree75ad4f14627fa05d39533177523dfd3d2454fa68 /net/unix
parentf55bb7f9cb82dec2f2e803d7bd0fc5929248e4d8 (diff)
unix: Support peeking offset for stream sockets
The 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. Signed-off-by: Pavel Emelyanov <xemul@parallels.com> Acked-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c20
1 files changed, 18 insertions, 2 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 3d9481de031f..0be4d24f6ae8 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -559,6 +559,7 @@ static const struct proto_ops unix_stream_ops = {
559 .recvmsg = unix_stream_recvmsg, 559 .recvmsg = unix_stream_recvmsg,
560 .mmap = sock_no_mmap, 560 .mmap = sock_no_mmap,
561 .sendpage = sock_no_sendpage, 561 .sendpage = sock_no_sendpage,
562 .set_peek_off = unix_set_peek_off,
562}; 563};
563 564
564static const struct proto_ops unix_dgram_ops = { 565static const struct proto_ops unix_dgram_ops = {
@@ -1904,6 +1905,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1904 int target; 1905 int target;
1905 int err = 0; 1906 int err = 0;
1906 long timeo; 1907 long timeo;
1908 int skip;
1907 1909
1908 err = -EINVAL; 1910 err = -EINVAL;
1909 if (sk->sk_state != TCP_ESTABLISHED) 1911 if (sk->sk_state != TCP_ESTABLISHED)
@@ -1933,12 +1935,15 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1933 goto out; 1935 goto out;
1934 } 1936 }
1935 1937
1938 skip = sk_peek_offset(sk, flags);
1939
1936 do { 1940 do {
1937 int chunk; 1941 int chunk;
1938 struct sk_buff *skb; 1942 struct sk_buff *skb;
1939 1943
1940 unix_state_lock(sk); 1944 unix_state_lock(sk);
1941 skb = skb_peek(&sk->sk_receive_queue); 1945 skb = skb_peek(&sk->sk_receive_queue);
1946again:
1942 if (skb == NULL) { 1947 if (skb == NULL) {
1943 unix_sk(sk)->recursion_level = 0; 1948 unix_sk(sk)->recursion_level = 0;
1944 if (copied >= target) 1949 if (copied >= target)
@@ -1973,6 +1978,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1973 unix_state_unlock(sk); 1978 unix_state_unlock(sk);
1974 break; 1979 break;
1975 } 1980 }
1981
1982 if (skip >= skb->len) {
1983 skip -= skb->len;
1984 skb = skb_peek_next(skb, &sk->sk_receive_queue);
1985 goto again;
1986 }
1987
1976 unix_state_unlock(sk); 1988 unix_state_unlock(sk);
1977 1989
1978 if (check_creds) { 1990 if (check_creds) {
@@ -1992,8 +2004,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
1992 sunaddr = NULL; 2004 sunaddr = NULL;
1993 } 2005 }
1994 2006
1995 chunk = min_t(unsigned int, skb->len, size); 2007 chunk = min_t(unsigned int, skb->len - skip, size);
1996 if (memcpy_toiovec(msg->msg_iov, skb->data, chunk)) { 2008 if (memcpy_toiovec(msg->msg_iov, skb->data + skip, chunk)) {
1997 if (copied == 0) 2009 if (copied == 0)
1998 copied = -EFAULT; 2010 copied = -EFAULT;
1999 break; 2011 break;
@@ -2005,6 +2017,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
2005 if (!(flags & MSG_PEEK)) { 2017 if (!(flags & MSG_PEEK)) {
2006 skb_pull(skb, chunk); 2018 skb_pull(skb, chunk);
2007 2019
2020 sk_peek_offset_bwd(sk, chunk);
2021
2008 if (UNIXCB(skb).fp) 2022 if (UNIXCB(skb).fp)
2009 unix_detach_fds(siocb->scm, skb); 2023 unix_detach_fds(siocb->scm, skb);
2010 2024
@@ -2022,6 +2036,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
2022 if (UNIXCB(skb).fp) 2036 if (UNIXCB(skb).fp)
2023 siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); 2037 siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
2024 2038
2039 sk_peek_offset_fwd(sk, chunk);
2040
2025 break; 2041 break;
2026 } 2042 }
2027 } while (size); 2043 } while (size);