diff options
Diffstat (limited to 'net/unix/af_unix.c')
-rw-r--r-- | net/unix/af_unix.c | 73 |
1 files changed, 36 insertions, 37 deletions
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index 826e09938bff..86de99ad2976 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c | |||
@@ -114,6 +114,7 @@ | |||
114 | #include <linux/mount.h> | 114 | #include <linux/mount.h> |
115 | #include <net/checksum.h> | 115 | #include <net/checksum.h> |
116 | #include <linux/security.h> | 116 | #include <linux/security.h> |
117 | #include <linux/freezer.h> | ||
117 | 118 | ||
118 | struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; | 119 | struct hlist_head unix_socket_table[2 * UNIX_HASH_SIZE]; |
119 | EXPORT_SYMBOL_GPL(unix_socket_table); | 120 | EXPORT_SYMBOL_GPL(unix_socket_table); |
@@ -1478,7 +1479,8 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1478 | MAX_SKB_FRAGS * PAGE_SIZE); | 1479 | MAX_SKB_FRAGS * PAGE_SIZE); |
1479 | 1480 | ||
1480 | skb = sock_alloc_send_pskb(sk, len - data_len, data_len, | 1481 | skb = sock_alloc_send_pskb(sk, len - data_len, data_len, |
1481 | msg->msg_flags & MSG_DONTWAIT, &err); | 1482 | msg->msg_flags & MSG_DONTWAIT, &err, |
1483 | PAGE_ALLOC_COSTLY_ORDER); | ||
1482 | if (skb == NULL) | 1484 | if (skb == NULL) |
1483 | goto out; | 1485 | goto out; |
1484 | 1486 | ||
@@ -1595,6 +1597,10 @@ out: | |||
1595 | return err; | 1597 | return err; |
1596 | } | 1598 | } |
1597 | 1599 | ||
1600 | /* We use paged skbs for stream sockets, and limit occupancy to 32768 | ||
1601 | * bytes, and a minimun of a full page. | ||
1602 | */ | ||
1603 | #define UNIX_SKB_FRAGS_SZ (PAGE_SIZE << get_order(32768)) | ||
1598 | 1604 | ||
1599 | static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | 1605 | static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, |
1600 | struct msghdr *msg, size_t len) | 1606 | struct msghdr *msg, size_t len) |
@@ -1608,6 +1614,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1608 | struct scm_cookie tmp_scm; | 1614 | struct scm_cookie tmp_scm; |
1609 | bool fds_sent = false; | 1615 | bool fds_sent = false; |
1610 | int max_level; | 1616 | int max_level; |
1617 | int data_len; | ||
1611 | 1618 | ||
1612 | if (NULL == siocb->scm) | 1619 | if (NULL == siocb->scm) |
1613 | siocb->scm = &tmp_scm; | 1620 | siocb->scm = &tmp_scm; |
@@ -1634,40 +1641,22 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1634 | goto pipe_err; | 1641 | goto pipe_err; |
1635 | 1642 | ||
1636 | while (sent < len) { | 1643 | while (sent < len) { |
1637 | /* | 1644 | size = len - sent; |
1638 | * Optimisation for the fact that under 0.01% of X | ||
1639 | * messages typically need breaking up. | ||
1640 | */ | ||
1641 | |||
1642 | size = len-sent; | ||
1643 | 1645 | ||
1644 | /* Keep two messages in the pipe so it schedules better */ | 1646 | /* Keep two messages in the pipe so it schedules better */ |
1645 | if (size > ((sk->sk_sndbuf >> 1) - 64)) | 1647 | size = min_t(int, size, (sk->sk_sndbuf >> 1) - 64); |
1646 | size = (sk->sk_sndbuf >> 1) - 64; | ||
1647 | 1648 | ||
1648 | if (size > SKB_MAX_ALLOC) | 1649 | /* allow fallback to order-0 allocations */ |
1649 | size = SKB_MAX_ALLOC; | 1650 | size = min_t(int, size, SKB_MAX_HEAD(0) + UNIX_SKB_FRAGS_SZ); |
1650 | 1651 | ||
1651 | /* | 1652 | data_len = max_t(int, 0, size - SKB_MAX_HEAD(0)); |
1652 | * Grab a buffer | ||
1653 | */ | ||
1654 | 1653 | ||
1655 | skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, | 1654 | skb = sock_alloc_send_pskb(sk, size - data_len, data_len, |
1656 | &err); | 1655 | msg->msg_flags & MSG_DONTWAIT, &err, |
1657 | 1656 | get_order(UNIX_SKB_FRAGS_SZ)); | |
1658 | if (skb == NULL) | 1657 | if (!skb) |
1659 | goto out_err; | 1658 | goto out_err; |
1660 | 1659 | ||
1661 | /* | ||
1662 | * If you pass two values to the sock_alloc_send_skb | ||
1663 | * it tries to grab the large buffer with GFP_NOFS | ||
1664 | * (which can fail easily), and if it fails grab the | ||
1665 | * fallback size buffer which is under a page and will | ||
1666 | * succeed. [Alan] | ||
1667 | */ | ||
1668 | size = min_t(int, size, skb_tailroom(skb)); | ||
1669 | |||
1670 | |||
1671 | /* Only send the fds in the first buffer */ | 1660 | /* Only send the fds in the first buffer */ |
1672 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); | 1661 | err = unix_scm_to_skb(siocb->scm, skb, !fds_sent); |
1673 | if (err < 0) { | 1662 | if (err < 0) { |
@@ -1677,7 +1666,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, | |||
1677 | max_level = err + 1; | 1666 | max_level = err + 1; |
1678 | fds_sent = true; | 1667 | fds_sent = true; |
1679 | 1668 | ||
1680 | err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); | 1669 | skb_put(skb, size - data_len); |
1670 | skb->data_len = data_len; | ||
1671 | skb->len = size; | ||
1672 | err = skb_copy_datagram_from_iovec(skb, 0, msg->msg_iov, | ||
1673 | sent, size); | ||
1681 | if (err) { | 1674 | if (err) { |
1682 | kfree_skb(skb); | 1675 | kfree_skb(skb); |
1683 | goto out_err; | 1676 | goto out_err; |
@@ -1879,7 +1872,7 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, | |||
1879 | 1872 | ||
1880 | set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | 1873 | set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); |
1881 | unix_state_unlock(sk); | 1874 | unix_state_unlock(sk); |
1882 | timeo = schedule_timeout(timeo); | 1875 | timeo = freezable_schedule_timeout(timeo); |
1883 | unix_state_lock(sk); | 1876 | unix_state_lock(sk); |
1884 | clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); | 1877 | clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags); |
1885 | } | 1878 | } |
@@ -1889,6 +1882,11 @@ static long unix_stream_data_wait(struct sock *sk, long timeo, | |||
1889 | return timeo; | 1882 | return timeo; |
1890 | } | 1883 | } |
1891 | 1884 | ||
1885 | static unsigned int unix_skb_len(const struct sk_buff *skb) | ||
1886 | { | ||
1887 | return skb->len - UNIXCB(skb).consumed; | ||
1888 | } | ||
1889 | |||
1892 | static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, | 1890 | static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, |
1893 | struct msghdr *msg, size_t size, | 1891 | struct msghdr *msg, size_t size, |
1894 | int flags) | 1892 | int flags) |
@@ -1976,8 +1974,8 @@ again: | |||
1976 | } | 1974 | } |
1977 | 1975 | ||
1978 | skip = sk_peek_offset(sk, flags); | 1976 | skip = sk_peek_offset(sk, flags); |
1979 | while (skip >= skb->len) { | 1977 | while (skip >= unix_skb_len(skb)) { |
1980 | skip -= skb->len; | 1978 | skip -= unix_skb_len(skb); |
1981 | last = skb; | 1979 | last = skb; |
1982 | skb = skb_peek_next(skb, &sk->sk_receive_queue); | 1980 | skb = skb_peek_next(skb, &sk->sk_receive_queue); |
1983 | if (!skb) | 1981 | if (!skb) |
@@ -2004,8 +2002,9 @@ again: | |||
2004 | sunaddr = NULL; | 2002 | sunaddr = NULL; |
2005 | } | 2003 | } |
2006 | 2004 | ||
2007 | chunk = min_t(unsigned int, skb->len - skip, size); | 2005 | chunk = min_t(unsigned int, unix_skb_len(skb) - skip, size); |
2008 | if (memcpy_toiovec(msg->msg_iov, skb->data + skip, chunk)) { | 2006 | if (skb_copy_datagram_iovec(skb, UNIXCB(skb).consumed + skip, |
2007 | msg->msg_iov, chunk)) { | ||
2009 | if (copied == 0) | 2008 | if (copied == 0) |
2010 | copied = -EFAULT; | 2009 | copied = -EFAULT; |
2011 | break; | 2010 | break; |
@@ -2015,14 +2014,14 @@ again: | |||
2015 | 2014 | ||
2016 | /* Mark read part of skb as used */ | 2015 | /* Mark read part of skb as used */ |
2017 | if (!(flags & MSG_PEEK)) { | 2016 | if (!(flags & MSG_PEEK)) { |
2018 | skb_pull(skb, chunk); | 2017 | UNIXCB(skb).consumed += chunk; |
2019 | 2018 | ||
2020 | sk_peek_offset_bwd(sk, chunk); | 2019 | sk_peek_offset_bwd(sk, chunk); |
2021 | 2020 | ||
2022 | if (UNIXCB(skb).fp) | 2021 | if (UNIXCB(skb).fp) |
2023 | unix_detach_fds(siocb->scm, skb); | 2022 | unix_detach_fds(siocb->scm, skb); |
2024 | 2023 | ||
2025 | if (skb->len) | 2024 | if (unix_skb_len(skb)) |
2026 | break; | 2025 | break; |
2027 | 2026 | ||
2028 | skb_unlink(skb, &sk->sk_receive_queue); | 2027 | skb_unlink(skb, &sk->sk_receive_queue); |
@@ -2106,7 +2105,7 @@ long unix_inq_len(struct sock *sk) | |||
2106 | if (sk->sk_type == SOCK_STREAM || | 2105 | if (sk->sk_type == SOCK_STREAM || |
2107 | sk->sk_type == SOCK_SEQPACKET) { | 2106 | sk->sk_type == SOCK_SEQPACKET) { |
2108 | skb_queue_walk(&sk->sk_receive_queue, skb) | 2107 | skb_queue_walk(&sk->sk_receive_queue, skb) |
2109 | amount += skb->len; | 2108 | amount += unix_skb_len(skb); |
2110 | } else { | 2109 | } else { |
2111 | skb = skb_peek(&sk->sk_receive_queue); | 2110 | skb = skb_peek(&sk->sk_receive_queue); |
2112 | if (skb) | 2111 | if (skb) |