On Fri, Jul 29, 2022 at 11:12:45PM +0200, Alexander Gordeev wrote: > On Fri, Jul 29, 2022 at 06:21:23PM +0100, Al Viro wrote: > > > Hi Al, > > > > > > This changes causes sendfile09 LTP testcase fail in linux-next > > > (up to next-20220727) on s390. In fact, not this change exactly, > > > but rather 92d4d18eecb9 ("new iov_iter flavour - ITER_UBUF") - > > > which differs from what is posted here. > > > > > > AFAICT page_cache_pipe_buf_confirm() encounters !PageUptodate() > > > and !page->mapping page and returns -ENODATA. > > > > > > I am going to narrow the testcase and get more details, but please > > > let me know if I am missing something. > > > > Grrr.... > > > > - } else if (iter_is_iovec(to)) { > > + } else if (!user_backed_iter(to)) { > > > > in mm/shmem.c. Spot the typo... > > > > Could you check if replacing that line with > > } else if (user_backed_iter(to)) { > > > > fixes the breakage? > > Yes, it does! So just to be sure - this is the fix: FWIW, there'd been another braino, caught by test from Hugh Dickins; this one in ITER_PIPE: allocate buffers as we go in copy-to-pipe primitives Incremental follows; folded and pushed out. diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 642841ce7595..939078ffbfb5 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c @@ -469,7 +469,7 @@ static size_t copy_pipe_to_iter(const void *addr, size_t bytes, struct page *page = append_pipe(i, n, &off); chunk = min_t(size_t, n, PAGE_SIZE - off); if (!page) - break; + return bytes - n; memcpy_to_page(page, off, addr, chunk); addr += chunk; } @@ -774,7 +774,7 @@ static size_t pipe_zero(size_t bytes, struct iov_iter *i) char *p; if (!page) - break; + return bytes - n; chunk = min_t(size_t, n, PAGE_SIZE - off); p = kmap_local_page(page); memset(p + off, 0, chunk); diff --git a/mm/shmem.c b/mm/shmem.c index 6b83f3971795..6c8a84a1fbbb 100644 --- a/mm/shmem.c +++ b/mm/shmem.c @@ -2603,7 +2603,7 @@ static ssize_t shmem_file_read_iter(struct kiocb *iocb, struct iov_iter *to) ret = copy_page_to_iter(page, offset, nr, to); put_page(page); - } else if (!user_backed_iter(to)) { + } else if (user_backed_iter(to)) { /* * Copy to user tends to be so well optimized, but * clear_user() not so much, that it is noticeably