diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2022-06-09 11:07:52 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2022-08-08 22:37:23 -0400 |
commit | 7d690c157c58d22de9ad71ef5c4e1f43cd8ad0e7 (patch) | |
tree | bf95adf480b40aaaffa3ea5bd4b65be5ecbf7f8e /fs | |
parent | 480cb846c27bda4e14d98a45a9f50c250f38f266 (diff) | |
download | lwn-7d690c157c58d22de9ad71ef5c4e1f43cd8ad0e7.tar.gz lwn-7d690c157c58d22de9ad71ef5c4e1f43cd8ad0e7.zip |
iter_to_pipe(): switch to advancing variant of iov_iter_get_pages()
... and untangle the cleanup on failure to add into pipe.
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 47 |
1 files changed, 24 insertions, 23 deletions
diff --git a/fs/splice.c b/fs/splice.c index 877290500050..0878b852b355 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -1158,39 +1158,40 @@ static int iter_to_pipe(struct iov_iter *from, }; size_t total = 0; int ret = 0; - bool failed = false; - while (iov_iter_count(from) && !failed) { + while (iov_iter_count(from)) { struct page *pages[16]; - ssize_t copied; + ssize_t left; size_t start; - int n; + int i, n; - copied = iov_iter_get_pages(from, pages, ~0UL, 16, &start); - if (copied <= 0) { - ret = copied; + left = iov_iter_get_pages2(from, pages, ~0UL, 16, &start); + if (left <= 0) { + ret = left; break; } - for (n = 0; copied; n++, start = 0) { - int size = min_t(int, copied, PAGE_SIZE - start); - if (!failed) { - buf.page = pages[n]; - buf.offset = start; - buf.len = size; - ret = add_to_pipe(pipe, &buf); - if (unlikely(ret < 0)) { - failed = true; - } else { - iov_iter_advance(from, ret); - total += ret; - } - } else { - put_page(pages[n]); + n = DIV_ROUND_UP(left + start, PAGE_SIZE); + for (i = 0; i < n; i++) { + int size = min_t(int, left, PAGE_SIZE - start); + + buf.page = pages[i]; + buf.offset = start; + buf.len = size; + ret = add_to_pipe(pipe, &buf); + if (unlikely(ret < 0)) { + iov_iter_revert(from, left); + // this one got dropped by add_to_pipe() + while (++i < n) + put_page(pages[i]); + goto out; } - copied -= size; + total += ret; + left -= size; + start = 0; } } +out: return total ? total : ret; } |