FAILED: patch "[PATCH] fix short copy handling in copy_mc_pipe_to_iter()" failed to apply to 4.19-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.19-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From c3497fd009ef2c59eea60d21c3ac22de3585ed7d Mon Sep 17 00:00:00 2001
From: Al Viro <[email protected]>
Date: Sun, 12 Jun 2022 19:50:29 -0400
Subject: [PATCH] fix short copy handling in copy_mc_pipe_to_iter()
Unlike other copying operations on ITER_PIPE, copy_mc_to_iter() can result in a short copy. In that case we need to trim the unused buffers, as well as the length of partially filled one - it's not enough to set ->head, ->iov_offset and ->count to reflect how much had we copied. Not hard to fix, fortunately...
I'd put a helper (pipe_discard_from(pipe, head)) into pipe_fs_i.h, rather than iov_iter.c - it has nothing to do with iov_iter and having it will allow us to avoid an ugly kludge in fs/splice.c. We could put it into lib/iov_iter.c for now and move it later, but I don't see the point going that way...
include/linux/pipe_fs_i.h +9 -0
@@ -229,6 +229,15 @@ static inline bool pipe_buf_try_steal(struct pipe_inode_info *pipe,return buf->ops->try_steal (pipe, buf); } +static inline void pipe_discard_from (struct pipe_inode_info *pipe, +unsigned int old_head) +{ +unsigned int mask = pipe->ring_size -1 ; + +while (pipe->head > old_head) +pipe_buf_release (pipe, &pipe->bufs[--pipe->head & mask]); +} +/* Differs from PIPE_BUF in that PIPE_SIZE is the length of the actual memory allocation, whereas PIPE_BUF makes atomicity guarantees. */ #define PIPE_SIZE PAGE_SIZE
lib/iov_iter.c +11 -4
@@ -689,6 +689,7 @@ static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes,struct pipe_inode_info *pipe = i->pipe;unsigned int p_mask = pipe->ring_size -1 ;unsigned int i_head; +unsigned int valid = pipe->head;size_t n, off, xfer =0 ;if (!sanity (i))
@@ -702,11 +703,17 @@ static size_t copy_mc_pipe_to_iter(const void *addr, size_t bytes, rem =copy_mc_to_kernel (p + off, addr + xfer, chunk); chunk -= rem;kunmap_local (p); - i->head = i_head; - i->iov_offset = off + chunk; - xfer += chunk; -if (rem) +if (chunk) { + i->head = i_head; + i->iov_offset = off + chunk; + xfer += chunk; + valid = i_head +1 ; + } +if (rem) { + pipe->bufs[i_head & p_mask].len -= rem; +pipe_discard_from (pipe, valid);break ; + } n -= chunk; off =0 ; i_head++;