summaryrefslogtreecommitdiffstats
path: root/net/unix
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2015-05-21 10:59:59 -0400
committerDavid S. Miller <davem@davemloft.net>2015-05-25 00:06:58 -0400
commit869e7c62486ec0e170a9771acaa251d1a33b5871 (patch)
treec9086093021e0d0e1d7573f437cb2f7ffdf36273 /net/unix
parentbe12a1fe298e8be04d5215364f94654dff81b0bc (diff)
net: af_unix: implement stream sendpage support
This patch implements sendpage support for AF_UNIX SOCK_STREAM sockets. This is also required for a complete splice implementation. The implementation is a bit tricky because we append to already existing skbs and so have to hold unix_sk->readlock to protect the reading side from either advancing UNIXCB.consumed or freeing the skb at the socket receive tail. Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Acked-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/unix')
-rw-r--r--net/unix/af_unix.c99
1 files changed, 98 insertions, 1 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 941b3d26e3bf..7762c0b46721 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -518,6 +518,8 @@ static int unix_ioctl(struct socket *, unsigned int, unsigned long);
518static int unix_shutdown(struct socket *, int); 518static int unix_shutdown(struct socket *, int);
519static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t); 519static int unix_stream_sendmsg(struct socket *, struct msghdr *, size_t);
520static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int); 520static int unix_stream_recvmsg(struct socket *, struct msghdr *, size_t, int);
521static ssize_t unix_stream_sendpage(struct socket *, struct page *, int offset,
522 size_t size, int flags);
521static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t); 523static int unix_dgram_sendmsg(struct socket *, struct msghdr *, size_t);
522static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int); 524static int unix_dgram_recvmsg(struct socket *, struct msghdr *, size_t, int);
523static int unix_dgram_connect(struct socket *, struct sockaddr *, 525static int unix_dgram_connect(struct socket *, struct sockaddr *,
@@ -558,7 +560,7 @@ static const struct proto_ops unix_stream_ops = {
558 .sendmsg = unix_stream_sendmsg, 560 .sendmsg = unix_stream_sendmsg,
559 .recvmsg = unix_stream_recvmsg, 561 .recvmsg = unix_stream_recvmsg,
560 .mmap = sock_no_mmap, 562 .mmap = sock_no_mmap,
561 .sendpage = sock_no_sendpage, 563 .sendpage = unix_stream_sendpage,
562 .set_peek_off = unix_set_peek_off, 564 .set_peek_off = unix_set_peek_off,
563}; 565};
564 566
@@ -1720,6 +1722,101 @@ out_err:
1720 return sent ? : err; 1722 return sent ? : err;
1721} 1723}
1722 1724
1725static ssize_t unix_stream_sendpage(struct socket *socket, struct page *page,
1726 int offset, size_t size, int flags)
1727{
1728 int err = 0;
1729 bool send_sigpipe = true;
1730 struct sock *other, *sk = socket->sk;
1731 struct sk_buff *skb, *newskb = NULL, *tail = NULL;
1732
1733 if (flags & MSG_OOB)
1734 return -EOPNOTSUPP;
1735
1736 other = unix_peer(sk);
1737 if (!other || sk->sk_state != TCP_ESTABLISHED)
1738 return -ENOTCONN;
1739
1740 if (false) {
1741alloc_skb:
1742 unix_state_unlock(other);
1743 mutex_unlock(&unix_sk(other)->readlock);
1744 newskb = sock_alloc_send_pskb(sk, 0, 0, flags & MSG_DONTWAIT,
1745 &err, 0);
1746 if (!newskb)
1747 return err;
1748 }
1749
1750 /* we must acquire readlock as we modify already present
1751 * skbs in the sk_receive_queue and mess with skb->len
1752 */
1753 err = mutex_lock_interruptible(&unix_sk(other)->readlock);
1754 if (err) {
1755 err = flags & MSG_DONTWAIT ? -EAGAIN : -ERESTARTSYS;
1756 send_sigpipe = false;
1757 goto err;
1758 }
1759
1760 if (sk->sk_shutdown & SEND_SHUTDOWN) {
1761 err = -EPIPE;
1762 goto err_unlock;
1763 }
1764
1765 unix_state_lock(other);
1766
1767 if (sock_flag(other, SOCK_DEAD) ||
1768 other->sk_shutdown & RCV_SHUTDOWN) {
1769 err = -EPIPE;
1770 goto err_state_unlock;
1771 }
1772
1773 skb = skb_peek_tail(&other->sk_receive_queue);
1774 if (tail && tail == skb) {
1775 skb = newskb;
1776 } else if (!skb) {
1777 if (newskb)
1778 skb = newskb;
1779 else
1780 goto alloc_skb;
1781 } else if (newskb) {
1782 /* this is fast path, we don't necessarily need to
1783 * call to kfree_skb even though with newskb == NULL
1784 * this - does no harm
1785 */
1786 consume_skb(newskb);
1787 }
1788
1789 if (skb_append_pagefrags(skb, page, offset, size)) {
1790 tail = skb;
1791 goto alloc_skb;
1792 }
1793
1794 skb->len += size;
1795 skb->data_len += size;
1796 skb->truesize += size;
1797 atomic_add(size, &sk->sk_wmem_alloc);
1798
1799 if (newskb)
1800 __skb_queue_tail(&other->sk_receive_queue, newskb);
1801
1802 unix_state_unlock(other);
1803 mutex_unlock(&unix_sk(other)->readlock);
1804
1805 other->sk_data_ready(other);
1806
1807 return size;
1808
1809err_state_unlock:
1810 unix_state_unlock(other);
1811err_unlock:
1812 mutex_unlock(&unix_sk(other)->readlock);
1813err:
1814 kfree_skb(newskb);
1815 if (send_sigpipe && !(flags & MSG_NOSIGNAL))
1816 send_sig(SIGPIPE, current, 0);
1817 return err;
1818}
1819
1723static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg, 1820static int unix_seqpacket_sendmsg(struct socket *sock, struct msghdr *msg,
1724 size_t len) 1821 size_t len)
1725{ 1822{