• Al Viro's avatar
    9p: handling Rerror without copy_from_iter_full() · f615625a
    Al Viro authored
            p9_client_zc_rpc()/p9_check_zc_errors() are playing fast
    and loose with copy_from_iter_full().
    
    	Reading from file is done by sending Tread request.  Response
    consists of fixed-sized header (including the amount of data actually
    read) followed by the data itself.
    
    	For zero-copy case we arrange the things so that the first
    11 bytes of reply go into the fixed-sized buffer, with the rest going
    straight into the pages we want to read into.
    
    	What makes the things inconvenient is that sglist describing
    what should go where has to be set *before* the reply arrives.  As
    the result, if reply is an error, the things get interesting.  On success
    we get
    	size[4] Rread tag[2] count[4] data[count]
    For error layout varies depending upon the protocol variant -
    in original 9P and 9P2000 it's
    	size[4] Rerror tag[2] len[2] error[len]
    in 9P2000.U
    	size[4] Rerror tag[2] len[2] error[len] errno[4]
    in 9P2000.L
    	size[4] Rlerror tag[2] errno[4]
    
    	The last case is nice and simple - we have an 11-byte response
    that fits into the fixed-sized buffer we hoped to get an Rread into.
    In other two, though, we get a variable-length string spill into the
    pages we'd prepared for the data to be read.
    
    	Had that been in fixed-sized buffer (which is actually 4K),
    we would've dealt with that the same way we handle non-zerocopy case.
    However, for zerocopy it doesn't end up there, so we need to copy it
    from those pages.
    
    	The trouble is, by the time we get around to that, the
    references to pages in question are already dropped.  As the result,
    p9_zc_check_errors() tries to get the data using copy_from_iter_full().
    Unfortunately, the iov_iter it's trying to read from might *NOT* be
    capable of that.  It is, after all, a data destination, not data source.
    In particular, if it's an ITER_PIPE one, copy_from_iter_full() will
    simply fail.
    
    	In ->zc_request() itself we do have those pages and dealing with
    the problem in there would be a simple matter of memcpy_from_page()
    into the fixed-sized buffer.  Moreover, it isn't hard to recognize
    the (rare) case when such copying is needed.  That way we get rid of
    p9_zc_check_errors() entirely - p9_check_errors() can be used instead
    both for zero-copy and non-zero-copy cases.
    Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
    f615625a
client.c 50.9 KB