aboutsummaryrefslogtreecommitdiffstats
path: root/net/unix/af_unix.c
diff options
context:
space:
mode:
authorPavel Emelyanov <xemul@parallels.com>2012-02-21 02:31:51 -0500
committerDavid S. Miller <davem@davemloft.net>2012-02-21 15:03:58 -0500
commitf55bb7f9cb82dec2f2e803d7bd0fc5929248e4d8 (patch)
tree25b5f83aa834490eb6a07e52db93b972e16e498f /net/unix/af_unix.c
parentef64a54f6e558155b4f149bb10666b9e914b6c54 (diff)
unix: Support peeking offset for datagram and seqpacket sockets
The 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. 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/af_unix.c')
-rw-r--r--net/unix/af_unix.c30
1 files changed, 25 insertions, 5 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 85d3bb7490aa..3d9481de031f 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -530,6 +530,16 @@ static int unix_seqpacket_sendmsg(struct kiocb *, struct socket *,
530static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *, 530static int unix_seqpacket_recvmsg(struct kiocb *, struct socket *,
531 struct msghdr *, size_t, int); 531 struct msghdr *, size_t, int);
532 532
533static void unix_set_peek_off(struct sock *sk, int val)
534{
535 struct unix_sock *u = unix_sk(sk);
536
537 mutex_lock(&u->readlock);
538 sk->sk_peek_off = val;
539 mutex_unlock(&u->readlock);
540}
541
542
533static const struct proto_ops unix_stream_ops = { 543static const struct proto_ops unix_stream_ops = {
534 .family = PF_UNIX, 544 .family = PF_UNIX,
535 .owner = THIS_MODULE, 545 .owner = THIS_MODULE,
@@ -570,6 +580,7 @@ static const struct proto_ops unix_dgram_ops = {
570 .recvmsg = unix_dgram_recvmsg, 580 .recvmsg = unix_dgram_recvmsg,
571 .mmap = sock_no_mmap, 581 .mmap = sock_no_mmap,
572 .sendpage = sock_no_sendpage, 582 .sendpage = sock_no_sendpage,
583 .set_peek_off = unix_set_peek_off,
573}; 584};
574 585
575static const struct proto_ops unix_seqpacket_ops = { 586static const struct proto_ops unix_seqpacket_ops = {
@@ -591,6 +602,7 @@ static const struct proto_ops unix_seqpacket_ops = {
591 .recvmsg = unix_seqpacket_recvmsg, 602 .recvmsg = unix_seqpacket_recvmsg,
592 .mmap = sock_no_mmap, 603 .mmap = sock_no_mmap,
593 .sendpage = sock_no_sendpage, 604 .sendpage = sock_no_sendpage,
605 .set_peek_off = unix_set_peek_off,
594}; 606};
595 607
596static struct proto unix_proto = { 608static struct proto unix_proto = {
@@ -1756,6 +1768,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1756 int noblock = flags & MSG_DONTWAIT; 1768 int noblock = flags & MSG_DONTWAIT;
1757 struct sk_buff *skb; 1769 struct sk_buff *skb;
1758 int err; 1770 int err;
1771 int peeked, skip;
1759 1772
1760 err = -EOPNOTSUPP; 1773 err = -EOPNOTSUPP;
1761 if (flags&MSG_OOB) 1774 if (flags&MSG_OOB)
@@ -1769,7 +1782,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1769 goto out; 1782 goto out;
1770 } 1783 }
1771 1784
1772 skb = skb_recv_datagram(sk, flags, noblock, &err); 1785 skip = sk_peek_offset(sk, flags);
1786
1787 skb = __skb_recv_datagram(sk, flags, &peeked, &skip, &err);
1773 if (!skb) { 1788 if (!skb) {
1774 unix_state_lock(sk); 1789 unix_state_lock(sk);
1775 /* Signal EOF on disconnected non-blocking SEQPACKET socket. */ 1790 /* Signal EOF on disconnected non-blocking SEQPACKET socket. */
@@ -1786,12 +1801,12 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1786 if (msg->msg_name) 1801 if (msg->msg_name)
1787 unix_copy_addr(msg, skb->sk); 1802 unix_copy_addr(msg, skb->sk);
1788 1803
1789 if (size > skb->len) 1804 if (size > skb->len - skip)
1790 size = skb->len; 1805 size = skb->len - skip;
1791 else if (size < skb->len) 1806 else if (size < skb->len - skip)
1792 msg->msg_flags |= MSG_TRUNC; 1807 msg->msg_flags |= MSG_TRUNC;
1793 1808
1794 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, size); 1809 err = skb_copy_datagram_iovec(skb, skip, msg->msg_iov, size);
1795 if (err) 1810 if (err)
1796 goto out_free; 1811 goto out_free;
1797 1812
@@ -1808,6 +1823,8 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1808 if (!(flags & MSG_PEEK)) { 1823 if (!(flags & MSG_PEEK)) {
1809 if (UNIXCB(skb).fp) 1824 if (UNIXCB(skb).fp)
1810 unix_detach_fds(siocb->scm, skb); 1825 unix_detach_fds(siocb->scm, skb);
1826
1827 sk_peek_offset_bwd(sk, skb->len);
1811 } else { 1828 } else {
1812 /* It is questionable: on PEEK we could: 1829 /* It is questionable: on PEEK we could:
1813 - do not return fds - good, but too simple 8) 1830 - do not return fds - good, but too simple 8)
@@ -1821,6 +1838,9 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock,
1821 clearly however! 1838 clearly however!
1822 1839
1823 */ 1840 */
1841
1842 sk_peek_offset_fwd(sk, size);
1843
1824 if (UNIXCB(skb).fp) 1844 if (UNIXCB(skb).fp)
1825 siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp); 1845 siocb->scm->fp = scm_fp_dup(UNIXCB(skb).fp);
1826 } 1846 }