Merge tag 'timers-urgent-2022-08-13' of git://git.kernel.org/pub/scm/linux/kernel...
[linux-2.6-microblaze.git] / fs / splice.c
index 93a2c9b..0878b85 100644 (file)
@@ -301,11 +301,9 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
 {
        struct iov_iter to;
        struct kiocb kiocb;
-       unsigned int i_head;
        int ret;
 
        iov_iter_pipe(&to, READ, pipe, len);
-       i_head = to.head;
        init_sync_kiocb(&kiocb, in);
        kiocb.ki_pos = *ppos;
        ret = call_read_iter(in, &kiocb, &to);
@@ -313,9 +311,8 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
                *ppos = kiocb.ki_pos;
                file_accessed(in);
        } else if (ret < 0) {
-               to.head = i_head;
-               to.iov_offset = 0;
-               iov_iter_advance(&to, 0); /* to free what was emitted */
+               /* free what was emitted */
+               pipe_discard_from(pipe, to.start_head);
                /*
                 * callers of ->splice_read() expect -EAGAIN on
                 * "can't put anything in there", rather than -EFAULT.
@@ -1161,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;
 }