• Chuck Lever's avatar
    svcrdma: Fix Read chunk round-up · 175e0310
    Chuck Lever authored
    A single NFSv4 WRITE compound can often have three operations:
    PUTFH, WRITE, then GETATTR.
    
    When the WRITE payload is sent in a Read chunk, the client places
    the GETATTR in the inline part of the RPC/RDMA message, just after
    the WRITE operation (sans payload). The position value in the Read
    chunk enables the receiver to insert the Read chunk at the correct
    place in the received XDR stream; that is between the WRITE and
    GETATTR.
    
    According to RFC 8166, an NFS/RDMA client does not have to add XDR
    round-up to the Read chunk that carries the WRITE payload. The
    receiver adds XDR round-up padding if it is absent and the
    receiver's XDR decoder requires it to be present.
    
    Commit 193bcb7b ("svcrdma: Populate tail iovec when receiving")
    attempted to add support for receiving such a compound so that just
    the WRITE payload appears in rq_arg's page list, and the trailing
    GETATTR is placed in rq_arg's tail iovec. (TCP just strings the
    whole compound into the head iovec and page list, without regard
    to the alignment of the WRITE payload).
    
    The server transport logic also had to accommodate the optional XDR
    round-up of the Read chunk, which it did simply by lengthening the
    tail iovec when round-up was needed. This approach is adequate for
    the NFSv2 and NFSv3 WRITE decoders.
    
    Unfortunately it is not sufficient for nfsd4_decode_write. When the
    Read chunk length is a couple of bytes less than PAGE_SIZE, the
    computation at the end of nfsd4_decode_write allows argp->pagelen to
    go negative, which breaks the logic in read_buf that looks for the
    tail iovec.
    
    The result is that a WRITE operation whose payload length is just
    less than a multiple of a page succeeds, but the subsequent GETATTR
    in the same compound fails with NFS4ERR_OP_ILLEGAL because the XDR
    decoder can't find it. Clients ignore the error, but they must
    update their attribute cache via a separate round trip.
    
    As nfsd4_decode_write appears to expect the payload itself to always
    have appropriate XDR round-up, have svc_rdma_build_normal_read_chunk
    add the Read chunk XDR round-up to the page_len rather than
    lengthening the tail iovec.
    Reported-by: default avatarOlga Kornievskaia <kolga@netapp.com>
    Fixes: 193bcb7b ("svcrdma: Populate tail iovec when receiving")
    Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
    Tested-by: default avatarOlga Kornievskaia <kolga@netapp.com>
    Signed-off-by: default avatarJ. Bruce Fields <bfields@redhat.com>
    175e0310
svc_rdma_rw.c 23 KB