• David Howells's avatar
    cifs: Fix lack of credit renegotiation on read retry · 6a5dcd48
    David Howells authored
    When netfslib asks cifs to issue a read operation, it prefaces this with a
    call to ->clamp_length() which cifs uses to negotiate credits, providing
    receive capacity on the server; however, in the event that a read op needs
    reissuing, netfslib doesn't call ->clamp_length() again as that could
    shorten the subrequest, leaving a gap.
    
    This causes the retried read to be done with zero credits which causes the
    server to reject it with STATUS_INVALID_PARAMETER.  This is a problem for a
    DIO read that is requested that would go over the EOF.  The short read will
    be retried, causing EINVAL to be returned to the user when it fails.
    
    Fix this by making cifs_req_issue_read() negotiate new credits if retrying
    (NETFS_SREQ_RETRYING now gets set in the read side as well as the write
    side in this instance).
    
    This isn't sufficient, however: the new credits might not be sufficient to
    complete the remainder of the read, so also add an additional field,
    rreq->actual_len, that holds the actual size of the op we want to perform
    without having to alter subreq->len.
    
    We then rely on repeated short reads being retried until we finish the read
    or reach the end of file and make a zero-length read.
    
    Also fix a couple of places where the subrequest start and length need to
    be altered by the amount so far transferred when being used.
    
    Fixes: 69c3c023 ("cifs: Implement netfslib hooks")
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    cc: Steve French <sfrench@samba.org>
    cc: Paulo Alcantara <pc@manguebit.com>
    cc: Jeff Layton <jlayton@kernel.org>
    cc: linux-cifs@vger.kernel.org
    cc: netfs@lists.linux.dev
    cc: linux-fsdevel@vger.kernel.org
    Signed-off-by: default avatarSteve French <stfrench@microsoft.com>
    6a5dcd48
cifsglob.h 76.7 KB