summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2022-06-09 11:07:52 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2022-08-08 22:37:23 -0400
commit7d690c157c58d22de9ad71ef5c4e1f43cd8ad0e7 (patch)
treebf95adf480b40aaaffa3ea5bd4b65be5ecbf7f8e /fs
parent480cb846c27bda4e14d98a45a9f50c250f38f266 (diff)
downloadlwn-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.c47
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;
}