• David Howells's avatar
    nfsd: Fix reading via splice · 101df45e
    David Howells authored
    nfsd_splice_actor() has a clause in its loop that chops up a compound page
    into individual pages such that if the same page is seen twice in a row, it
    is discarded the second time.  This is a problem with the advent of
    shmem_splice_read() as that inserts zero_pages into the pipe in lieu of
    pages that aren't present in the pagecache.
    
    Fix this by assuming that the last page is being extended only if the
    currently stored length + starting offset is not currently on a page
    boundary.
    
    This can be tested by NFS-exporting a tmpfs filesystem on the test machine
    and truncating it to more than a page in size (eg. truncate -s 8192) and
    then reading it by NFS.  The first page will be all zeros, but thereafter
    garbage will be read.
    
    Note: I wonder if we can ever get a situation now where we get a splice
    that gives us contiguous parts of a page in separate actor calls.  As NFSD
    can only be splicing from a file (I think), there are only three sources of
    the page: copy_splice_read(), shmem_splice_read() and file_splice_read().
    The first allocates pages for the data it reads, so the problem cannot
    occur; the second should never see a partial page; and the third waits for
    each page to become available before we're allowed to read from it.
    
    Fixes: bd194b18
    
     ("shmem: Implement splice-read")
    Reported-by: default avatarChuck Lever <chuck.lever@oracle.com>
    Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
    Reviewed-by: default avatarJeff Layton <jlayton@kernel.org>
    Reviewed-by: default avatarNeilBrown <neilb@suse.de>
    cc: Hugh Dickins <hughd@google.com>
    cc: Jens Axboe <axboe@kernel.dk>
    cc: Matthew Wilcox <willy@infradead.org>
    cc: linux-nfs@vger.kernel.org
    cc: linux-fsdevel@vger.kernel.org
    cc: linux-mm@kvack.org
    Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
    101df45e
vfs.c 61.2 KB