[lkml]   [2012]   [Aug]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
Messages in this thread
    Patch in this message
    Subject[ 107/122] tcp: perform DMA to userspace only if there is a task waiting for it
    From: Greg KH <>

    3.5-stable review patch. If anyone has any objections, please let me know.


    From: Jiri Kosina <>

    [ Upstream commit 59ea33a68a9083ac98515e4861c00e71efdc49a1 ]

    Back in 2006, commit 1a2449a87b ("[I/OAT]: TCP recv offload to I/OAT")
    added support for receive offloading to IOAT dma engine if available.

    The code in tcp_rcv_established() tries to perform early DMA copy if
    applicable. It however does so without checking whether the userspace
    task is actually expecting the data in the buffer.

    This is not a problem under normal circumstances, but there is a corner
    case where this doesn't work -- and that's when MSG_TRUNC flag to
    recvmsg() is used.

    If the IOAT dma engine is not used, the code properly checks whether
    there is a valid ucopy.task and the socket is owned by userspace, but
    misses the check in the dmaengine case.

    This problem can be observed in real trivially -- for example 'tbench' is a
    good reproducer, as it makes a heavy use of MSG_TRUNC. On systems utilizing
    IOAT, you will soon find tbench waiting indefinitely in sk_wait_data(), as they
    have been already early-copied in tcp_rcv_established() using dma engine.

    This patch introduces the same check we are performing in the simple
    iovec copy case to the IOAT case as well. It fixes the indefinite
    recvmsg(MSG_TRUNC) hangs.

    Signed-off-by: Jiri Kosina <>
    Signed-off-by: David S. Miller <>
    Signed-off-by: Greg Kroah-Hartman <>
    net/ipv4/tcp_input.c | 4 +++-
    1 file changed, 3 insertions(+), 1 deletion(-)

    --- a/net/ipv4/tcp_input.c
    +++ b/net/ipv4/tcp_input.c
    @@ -5602,7 +5602,9 @@ int tcp_rcv_established(struct sock *sk,
    if (tp->copied_seq == tp->rcv_nxt &&
    len - tcp_header_len <= tp->ucopy.len) {
    #ifdef CONFIG_NET_DMA
    - if (tcp_dma_try_early_copy(sk, skb, tcp_header_len)) {
    + if (tp->ucopy.task == current &&
    + sock_owned_by_user(sk) &&
    + tcp_dma_try_early_copy(sk, skb, tcp_header_len)) {
    copied_early = 1;
    eaten = 1;

     \ /
      Last update: 2012-08-08 03:41    [W:0.022 / U:35.296 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site