diff options
author | David S. Miller <davem@davemloft.net> | 2016-03-22 16:18:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-03-22 16:18:42 -0400 |
commit | 9a3492194eca6253ae7ba93c7a402cecad7f1c94 (patch) | |
tree | 8ca3e07cbeae365ba4d5d359e5931261ed0151e4 | |
parent | 9a0384c020b055a555500906be8ac314c92f3998 (diff) | |
parent | f7f9b5e7f8eccfd68ffa7b8d74b07c478bb9e7f0 (diff) |
Merge branch 'AF_VSOCK-missed-wakeups'
Claudio Imbrenda says:
====================
AF_VSOCK: Shrink the area influenced by prepare_to_wait
This patchset applies on net-next.
I think I found a problem with the patch submitted by Laura Abbott
( https://lkml.org/lkml/2016/2/4/711 ): we might miss wakeups.
Since the condition is not checked between the prepare_to_wait and the
schedule(), if a wakeup happens after the condition is checked but before
the sleep happens, and we miss it. ( A description of the problem can be
found here: http://www.makelinux.net/ldd3/chp-6-sect-2 ).
The first patch reverts the previous broken patch, while the second patch
properly fixes the sleep-while-waiting issue.
====================
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/vmw_vsock/af_vsock.c | 155 |
1 files changed, 87 insertions, 68 deletions
diff --git a/net/vmw_vsock/af_vsock.c b/net/vmw_vsock/af_vsock.c index bbe65dcb9738..3dce53ebea92 100644 --- a/net/vmw_vsock/af_vsock.c +++ b/net/vmw_vsock/af_vsock.c | |||
@@ -1209,10 +1209,14 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, | |||
1209 | 1209 | ||
1210 | if (signal_pending(current)) { | 1210 | if (signal_pending(current)) { |
1211 | err = sock_intr_errno(timeout); | 1211 | err = sock_intr_errno(timeout); |
1212 | goto out_wait_error; | 1212 | sk->sk_state = SS_UNCONNECTED; |
1213 | sock->state = SS_UNCONNECTED; | ||
1214 | goto out_wait; | ||
1213 | } else if (timeout == 0) { | 1215 | } else if (timeout == 0) { |
1214 | err = -ETIMEDOUT; | 1216 | err = -ETIMEDOUT; |
1215 | goto out_wait_error; | 1217 | sk->sk_state = SS_UNCONNECTED; |
1218 | sock->state = SS_UNCONNECTED; | ||
1219 | goto out_wait; | ||
1216 | } | 1220 | } |
1217 | 1221 | ||
1218 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | 1222 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
@@ -1220,20 +1224,17 @@ static int vsock_stream_connect(struct socket *sock, struct sockaddr *addr, | |||
1220 | 1224 | ||
1221 | if (sk->sk_err) { | 1225 | if (sk->sk_err) { |
1222 | err = -sk->sk_err; | 1226 | err = -sk->sk_err; |
1223 | goto out_wait_error; | 1227 | sk->sk_state = SS_UNCONNECTED; |
1224 | } else | 1228 | sock->state = SS_UNCONNECTED; |
1229 | } else { | ||
1225 | err = 0; | 1230 | err = 0; |
1231 | } | ||
1226 | 1232 | ||
1227 | out_wait: | 1233 | out_wait: |
1228 | finish_wait(sk_sleep(sk), &wait); | 1234 | finish_wait(sk_sleep(sk), &wait); |
1229 | out: | 1235 | out: |
1230 | release_sock(sk); | 1236 | release_sock(sk); |
1231 | return err; | 1237 | return err; |
1232 | |||
1233 | out_wait_error: | ||
1234 | sk->sk_state = SS_UNCONNECTED; | ||
1235 | sock->state = SS_UNCONNECTED; | ||
1236 | goto out_wait; | ||
1237 | } | 1238 | } |
1238 | 1239 | ||
1239 | static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) | 1240 | static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) |
@@ -1270,18 +1271,20 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) | |||
1270 | listener->sk_err == 0) { | 1271 | listener->sk_err == 0) { |
1271 | release_sock(listener); | 1272 | release_sock(listener); |
1272 | timeout = schedule_timeout(timeout); | 1273 | timeout = schedule_timeout(timeout); |
1274 | finish_wait(sk_sleep(listener), &wait); | ||
1273 | lock_sock(listener); | 1275 | lock_sock(listener); |
1274 | 1276 | ||
1275 | if (signal_pending(current)) { | 1277 | if (signal_pending(current)) { |
1276 | err = sock_intr_errno(timeout); | 1278 | err = sock_intr_errno(timeout); |
1277 | goto out_wait; | 1279 | goto out; |
1278 | } else if (timeout == 0) { | 1280 | } else if (timeout == 0) { |
1279 | err = -EAGAIN; | 1281 | err = -EAGAIN; |
1280 | goto out_wait; | 1282 | goto out; |
1281 | } | 1283 | } |
1282 | 1284 | ||
1283 | prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); | 1285 | prepare_to_wait(sk_sleep(listener), &wait, TASK_INTERRUPTIBLE); |
1284 | } | 1286 | } |
1287 | finish_wait(sk_sleep(listener), &wait); | ||
1285 | 1288 | ||
1286 | if (listener->sk_err) | 1289 | if (listener->sk_err) |
1287 | err = -listener->sk_err; | 1290 | err = -listener->sk_err; |
@@ -1301,19 +1304,15 @@ static int vsock_accept(struct socket *sock, struct socket *newsock, int flags) | |||
1301 | */ | 1304 | */ |
1302 | if (err) { | 1305 | if (err) { |
1303 | vconnected->rejected = true; | 1306 | vconnected->rejected = true; |
1304 | release_sock(connected); | 1307 | } else { |
1305 | sock_put(connected); | 1308 | newsock->state = SS_CONNECTED; |
1306 | goto out_wait; | 1309 | sock_graft(connected, newsock); |
1307 | } | 1310 | } |
1308 | 1311 | ||
1309 | newsock->state = SS_CONNECTED; | ||
1310 | sock_graft(connected, newsock); | ||
1311 | release_sock(connected); | 1312 | release_sock(connected); |
1312 | sock_put(connected); | 1313 | sock_put(connected); |
1313 | } | 1314 | } |
1314 | 1315 | ||
1315 | out_wait: | ||
1316 | finish_wait(sk_sleep(listener), &wait); | ||
1317 | out: | 1316 | out: |
1318 | release_sock(listener); | 1317 | release_sock(listener); |
1319 | return err; | 1318 | return err; |
@@ -1557,9 +1556,11 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, | |||
1557 | if (err < 0) | 1556 | if (err < 0) |
1558 | goto out; | 1557 | goto out; |
1559 | 1558 | ||
1559 | |||
1560 | while (total_written < len) { | 1560 | while (total_written < len) { |
1561 | ssize_t written; | 1561 | ssize_t written; |
1562 | 1562 | ||
1563 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
1563 | while (vsock_stream_has_space(vsk) == 0 && | 1564 | while (vsock_stream_has_space(vsk) == 0 && |
1564 | sk->sk_err == 0 && | 1565 | sk->sk_err == 0 && |
1565 | !(sk->sk_shutdown & SEND_SHUTDOWN) && | 1566 | !(sk->sk_shutdown & SEND_SHUTDOWN) && |
@@ -1568,27 +1569,33 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, | |||
1568 | /* Don't wait for non-blocking sockets. */ | 1569 | /* Don't wait for non-blocking sockets. */ |
1569 | if (timeout == 0) { | 1570 | if (timeout == 0) { |
1570 | err = -EAGAIN; | 1571 | err = -EAGAIN; |
1571 | goto out_wait; | 1572 | finish_wait(sk_sleep(sk), &wait); |
1573 | goto out_err; | ||
1572 | } | 1574 | } |
1573 | 1575 | ||
1574 | err = transport->notify_send_pre_block(vsk, &send_data); | 1576 | err = transport->notify_send_pre_block(vsk, &send_data); |
1575 | if (err < 0) | 1577 | if (err < 0) { |
1576 | goto out_wait; | 1578 | finish_wait(sk_sleep(sk), &wait); |
1579 | goto out_err; | ||
1580 | } | ||
1577 | 1581 | ||
1578 | release_sock(sk); | 1582 | release_sock(sk); |
1579 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
1580 | timeout = schedule_timeout(timeout); | 1583 | timeout = schedule_timeout(timeout); |
1581 | finish_wait(sk_sleep(sk), &wait); | ||
1582 | lock_sock(sk); | 1584 | lock_sock(sk); |
1583 | if (signal_pending(current)) { | 1585 | if (signal_pending(current)) { |
1584 | err = sock_intr_errno(timeout); | 1586 | err = sock_intr_errno(timeout); |
1585 | goto out_wait; | 1587 | finish_wait(sk_sleep(sk), &wait); |
1588 | goto out_err; | ||
1586 | } else if (timeout == 0) { | 1589 | } else if (timeout == 0) { |
1587 | err = -EAGAIN; | 1590 | err = -EAGAIN; |
1588 | goto out_wait; | 1591 | finish_wait(sk_sleep(sk), &wait); |
1592 | goto out_err; | ||
1589 | } | 1593 | } |
1590 | 1594 | ||
1595 | prepare_to_wait(sk_sleep(sk), &wait, | ||
1596 | TASK_INTERRUPTIBLE); | ||
1591 | } | 1597 | } |
1598 | finish_wait(sk_sleep(sk), &wait); | ||
1592 | 1599 | ||
1593 | /* These checks occur both as part of and after the loop | 1600 | /* These checks occur both as part of and after the loop |
1594 | * conditional since we need to check before and after | 1601 | * conditional since we need to check before and after |
@@ -1596,16 +1603,16 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, | |||
1596 | */ | 1603 | */ |
1597 | if (sk->sk_err) { | 1604 | if (sk->sk_err) { |
1598 | err = -sk->sk_err; | 1605 | err = -sk->sk_err; |
1599 | goto out_wait; | 1606 | goto out_err; |
1600 | } else if ((sk->sk_shutdown & SEND_SHUTDOWN) || | 1607 | } else if ((sk->sk_shutdown & SEND_SHUTDOWN) || |
1601 | (vsk->peer_shutdown & RCV_SHUTDOWN)) { | 1608 | (vsk->peer_shutdown & RCV_SHUTDOWN)) { |
1602 | err = -EPIPE; | 1609 | err = -EPIPE; |
1603 | goto out_wait; | 1610 | goto out_err; |
1604 | } | 1611 | } |
1605 | 1612 | ||
1606 | err = transport->notify_send_pre_enqueue(vsk, &send_data); | 1613 | err = transport->notify_send_pre_enqueue(vsk, &send_data); |
1607 | if (err < 0) | 1614 | if (err < 0) |
1608 | goto out_wait; | 1615 | goto out_err; |
1609 | 1616 | ||
1610 | /* Note that enqueue will only write as many bytes as are free | 1617 | /* Note that enqueue will only write as many bytes as are free |
1611 | * in the produce queue, so we don't need to ensure len is | 1618 | * in the produce queue, so we don't need to ensure len is |
@@ -1618,7 +1625,7 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, | |||
1618 | len - total_written); | 1625 | len - total_written); |
1619 | if (written < 0) { | 1626 | if (written < 0) { |
1620 | err = -ENOMEM; | 1627 | err = -ENOMEM; |
1621 | goto out_wait; | 1628 | goto out_err; |
1622 | } | 1629 | } |
1623 | 1630 | ||
1624 | total_written += written; | 1631 | total_written += written; |
@@ -1626,11 +1633,11 @@ static int vsock_stream_sendmsg(struct socket *sock, struct msghdr *msg, | |||
1626 | err = transport->notify_send_post_enqueue( | 1633 | err = transport->notify_send_post_enqueue( |
1627 | vsk, written, &send_data); | 1634 | vsk, written, &send_data); |
1628 | if (err < 0) | 1635 | if (err < 0) |
1629 | goto out_wait; | 1636 | goto out_err; |
1630 | 1637 | ||
1631 | } | 1638 | } |
1632 | 1639 | ||
1633 | out_wait: | 1640 | out_err: |
1634 | if (total_written > 0) | 1641 | if (total_written > 0) |
1635 | err = total_written; | 1642 | err = total_written; |
1636 | out: | 1643 | out: |
@@ -1715,18 +1722,59 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |||
1715 | 1722 | ||
1716 | 1723 | ||
1717 | while (1) { | 1724 | while (1) { |
1718 | s64 ready = vsock_stream_has_data(vsk); | 1725 | s64 ready; |
1719 | 1726 | ||
1720 | if (ready < 0) { | 1727 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); |
1721 | /* Invalid queue pair content. XXX This should be | 1728 | ready = vsock_stream_has_data(vsk); |
1722 | * changed to a connection reset in a later change. | ||
1723 | */ | ||
1724 | 1729 | ||
1725 | err = -ENOMEM; | 1730 | if (ready == 0) { |
1726 | goto out; | 1731 | if (sk->sk_err != 0 || |
1727 | } else if (ready > 0) { | 1732 | (sk->sk_shutdown & RCV_SHUTDOWN) || |
1733 | (vsk->peer_shutdown & SEND_SHUTDOWN)) { | ||
1734 | finish_wait(sk_sleep(sk), &wait); | ||
1735 | break; | ||
1736 | } | ||
1737 | /* Don't wait for non-blocking sockets. */ | ||
1738 | if (timeout == 0) { | ||
1739 | err = -EAGAIN; | ||
1740 | finish_wait(sk_sleep(sk), &wait); | ||
1741 | break; | ||
1742 | } | ||
1743 | |||
1744 | err = transport->notify_recv_pre_block( | ||
1745 | vsk, target, &recv_data); | ||
1746 | if (err < 0) { | ||
1747 | finish_wait(sk_sleep(sk), &wait); | ||
1748 | break; | ||
1749 | } | ||
1750 | release_sock(sk); | ||
1751 | timeout = schedule_timeout(timeout); | ||
1752 | lock_sock(sk); | ||
1753 | |||
1754 | if (signal_pending(current)) { | ||
1755 | err = sock_intr_errno(timeout); | ||
1756 | finish_wait(sk_sleep(sk), &wait); | ||
1757 | break; | ||
1758 | } else if (timeout == 0) { | ||
1759 | err = -EAGAIN; | ||
1760 | finish_wait(sk_sleep(sk), &wait); | ||
1761 | break; | ||
1762 | } | ||
1763 | } else { | ||
1728 | ssize_t read; | 1764 | ssize_t read; |
1729 | 1765 | ||
1766 | finish_wait(sk_sleep(sk), &wait); | ||
1767 | |||
1768 | if (ready < 0) { | ||
1769 | /* Invalid queue pair content. XXX This should | ||
1770 | * be changed to a connection reset in a later | ||
1771 | * change. | ||
1772 | */ | ||
1773 | |||
1774 | err = -ENOMEM; | ||
1775 | goto out; | ||
1776 | } | ||
1777 | |||
1730 | err = transport->notify_recv_pre_dequeue( | 1778 | err = transport->notify_recv_pre_dequeue( |
1731 | vsk, target, &recv_data); | 1779 | vsk, target, &recv_data); |
1732 | if (err < 0) | 1780 | if (err < 0) |
@@ -1752,35 +1800,6 @@ vsock_stream_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, | |||
1752 | break; | 1800 | break; |
1753 | 1801 | ||
1754 | target -= read; | 1802 | target -= read; |
1755 | } else { | ||
1756 | if (sk->sk_err != 0 || (sk->sk_shutdown & RCV_SHUTDOWN) | ||
1757 | || (vsk->peer_shutdown & SEND_SHUTDOWN)) { | ||
1758 | break; | ||
1759 | } | ||
1760 | /* Don't wait for non-blocking sockets. */ | ||
1761 | if (timeout == 0) { | ||
1762 | err = -EAGAIN; | ||
1763 | break; | ||
1764 | } | ||
1765 | |||
1766 | err = transport->notify_recv_pre_block( | ||
1767 | vsk, target, &recv_data); | ||
1768 | if (err < 0) | ||
1769 | break; | ||
1770 | |||
1771 | release_sock(sk); | ||
1772 | prepare_to_wait(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); | ||
1773 | timeout = schedule_timeout(timeout); | ||
1774 | finish_wait(sk_sleep(sk), &wait); | ||
1775 | lock_sock(sk); | ||
1776 | |||
1777 | if (signal_pending(current)) { | ||
1778 | err = sock_intr_errno(timeout); | ||
1779 | break; | ||
1780 | } else if (timeout == 0) { | ||
1781 | err = -EAGAIN; | ||
1782 | break; | ||
1783 | } | ||
1784 | } | 1803 | } |
1785 | } | 1804 | } |
1786 | 1805 | ||