lkml.org 
[lkml]   [2010]   [Jul]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[039/205] SUNRPC: Fix a re-entrancy bug in xs_tcp_read_calldir()
    2.6.34-stable review patch.  If anyone has any objections, please let us know.

    ------------------

    From: Trond Myklebust <Trond.Myklebust@netapp.com>

    commit b76ce56192bcf618013fb9aecd83488cffd645cc upstream.

    If the attempt to read the calldir fails, then instead of storing the read
    bytes, we currently discard them. This leads to a garbage final result when
    upon re-entry to the same routine, we read the remaining bytes.

    Fixes the regression in bugzilla number 16213. Please see
    https://bugzilla.kernel.org/show_bug.cgi?id=16213

    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    net/sunrpc/xprtsock.c | 38 ++++++++++++++++++++++----------------
    1 file changed, 22 insertions(+), 16 deletions(-)

    --- a/net/sunrpc/xprtsock.c
    +++ b/net/sunrpc/xprtsock.c
    @@ -224,7 +224,8 @@ struct sock_xprt {
    * State of TCP reply receive
    */
    __be32 tcp_fraghdr,
    - tcp_xid;
    + tcp_xid,
    + tcp_calldir;

    u32 tcp_offset,
    tcp_reclen;
    @@ -942,7 +943,7 @@ static inline void xs_tcp_read_calldir(s
    {
    size_t len, used;
    u32 offset;
    - __be32 calldir;
    + char *p;

    /*
    * We want transport->tcp_offset to be 8 at the end of this routine
    @@ -951,26 +952,33 @@ static inline void xs_tcp_read_calldir(s
    * transport->tcp_offset is 4 (after having already read the xid).
    */
    offset = transport->tcp_offset - sizeof(transport->tcp_xid);
    - len = sizeof(calldir) - offset;
    + len = sizeof(transport->tcp_calldir) - offset;
    dprintk("RPC: reading CALL/REPLY flag (%Zu bytes)\n", len);
    - used = xdr_skb_read_bits(desc, &calldir, len);
    + p = ((char *) &transport->tcp_calldir) + offset;
    + used = xdr_skb_read_bits(desc, p, len);
    transport->tcp_offset += used;
    if (used != len)
    return;
    transport->tcp_flags &= ~TCP_RCV_READ_CALLDIR;
    - transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
    - transport->tcp_flags |= TCP_RCV_COPY_DATA;
    /*
    * We don't yet have the XDR buffer, so we will write the calldir
    * out after we get the buffer from the 'struct rpc_rqst'
    */
    - if (ntohl(calldir) == RPC_REPLY)
    + switch (ntohl(transport->tcp_calldir)) {
    + case RPC_REPLY:
    + transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
    + transport->tcp_flags |= TCP_RCV_COPY_DATA;
    transport->tcp_flags |= TCP_RPC_REPLY;
    - else
    + break;
    + case RPC_CALL:
    + transport->tcp_flags |= TCP_RCV_COPY_CALLDIR;
    + transport->tcp_flags |= TCP_RCV_COPY_DATA;
    transport->tcp_flags &= ~TCP_RPC_REPLY;
    - dprintk("RPC: reading %s CALL/REPLY flag %08x\n",
    - (transport->tcp_flags & TCP_RPC_REPLY) ?
    - "reply for" : "request with", calldir);
    + break;
    + default:
    + dprintk("RPC: invalid request message type\n");
    + xprt_force_disconnect(&transport->xprt);
    + }
    xs_tcp_check_fraghdr(transport);
    }

    @@ -990,12 +998,10 @@ static inline void xs_tcp_read_common(st
    /*
    * Save the RPC direction in the XDR buffer
    */
    - __be32 calldir = transport->tcp_flags & TCP_RPC_REPLY ?
    - htonl(RPC_REPLY) : 0;
    -
    memcpy(rcvbuf->head[0].iov_base + transport->tcp_copied,
    - &calldir, sizeof(calldir));
    - transport->tcp_copied += sizeof(calldir);
    + &transport->tcp_calldir,
    + sizeof(transport->tcp_calldir));
    + transport->tcp_copied += sizeof(transport->tcp_calldir);
    transport->tcp_flags &= ~TCP_RCV_COPY_CALLDIR;
    }




    \
     
     \ /
      Last update: 2010-07-30 20:37    [W:4.272 / U:0.020 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site