Message ID | 20250307221004.1115255-1-linux@rasmusvillemoes.dk (mailing list archive) |
---|---|
State | New |
Headers | show |
Series | fs/pipe.c: simplify tmp_page handling | expand |
On Fri, Mar 07, 2025 at 11:10:04PM +0100, Rasmus Villemoes wrote: > Assigning the newly allocated page to pipe->tmp_page, only to > unconditionally clear ->tmp_page a little later, seems somewhat odd. > > It made sense prior to commit a194dfe6e6f6 ("pipe: Rearrange sequence > in pipe_write() to preallocate slot"), when a user copy was done > between the allocation and the buf->page = page assignment, and a > failure there would then just leave the pipe's one-element page cache > populated. Now, the same purpose is served by the page being inserted > as a size-0 buffer, and the next write attempting to merge with that > buffer. > > Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> > --- > fs/pipe.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/fs/pipe.c b/fs/pipe.c > index 4d0799e4e719..097400cce241 100644 > --- a/fs/pipe.c > +++ b/fs/pipe.c > @@ -508,13 +508,14 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) > struct page *page = pipe->tmp_page; > int copied; > > - if (!page) { > + if (page) { > + pipe->tmp_page = NULL; > + } else { > page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT); > if (unlikely(!page)) { > ret = ret ? : -ENOMEM; > break; > } > - pipe->tmp_page = page; > } > > /* Allocate a slot in the ring in advance and attach an > @@ -534,7 +535,6 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) > buf->flags = PIPE_BUF_FLAG_PACKET; > else > buf->flags = PIPE_BUF_FLAG_CAN_MERGE; > - pipe->tmp_page = NULL; > > copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); > if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) { This bit got reworked in https://lore.kernel.org/all/20250303230409.452687-3-mjguzik@gmail.com/ I see it is in -next, merged from https://web.git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs.git/log/?h=vfs-6.15.pipe
On 03/07, Rasmus Villemoes wrote: > > Assigning the newly allocated page to pipe->tmp_page, only to > unconditionally clear ->tmp_page a little later, seems somewhat odd. Oh yes, but could you look at [PATCH v2 1/1] pipe: change pipe_write() to never add a zero-sized buffer https://lore.kernel.org/all/20250210114039.GA3588@redhat.com/ already in Christian's tree although I will probably need to rebase this patch on top of the recent changes. Oleg. > It made sense prior to commit a194dfe6e6f6 ("pipe: Rearrange sequence > in pipe_write() to preallocate slot"), when a user copy was done > between the allocation and the buf->page = page assignment, and a > failure there would then just leave the pipe's one-element page cache > populated. Now, the same purpose is served by the page being inserted > as a size-0 buffer, and the next write attempting to merge with that > buffer. > > Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> > --- > fs/pipe.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/fs/pipe.c b/fs/pipe.c > index 4d0799e4e719..097400cce241 100644 > --- a/fs/pipe.c > +++ b/fs/pipe.c > @@ -508,13 +508,14 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) > struct page *page = pipe->tmp_page; > int copied; > > - if (!page) { > + if (page) { > + pipe->tmp_page = NULL; > + } else { > page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT); > if (unlikely(!page)) { > ret = ret ? : -ENOMEM; > break; > } > - pipe->tmp_page = page; > } > > /* Allocate a slot in the ring in advance and attach an > @@ -534,7 +535,6 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) > buf->flags = PIPE_BUF_FLAG_PACKET; > else > buf->flags = PIPE_BUF_FLAG_CAN_MERGE; > - pipe->tmp_page = NULL; > > copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); > if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) { > -- > 2.48.1 >
diff --git a/fs/pipe.c b/fs/pipe.c index 4d0799e4e719..097400cce241 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -508,13 +508,14 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) struct page *page = pipe->tmp_page; int copied; - if (!page) { + if (page) { + pipe->tmp_page = NULL; + } else { page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT); if (unlikely(!page)) { ret = ret ? : -ENOMEM; break; } - pipe->tmp_page = page; } /* Allocate a slot in the ring in advance and attach an @@ -534,7 +535,6 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from) buf->flags = PIPE_BUF_FLAG_PACKET; else buf->flags = PIPE_BUF_FLAG_CAN_MERGE; - pipe->tmp_page = NULL; copied = copy_page_from_iter(page, 0, PAGE_SIZE, from); if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
Assigning the newly allocated page to pipe->tmp_page, only to unconditionally clear ->tmp_page a little later, seems somewhat odd. It made sense prior to commit a194dfe6e6f6 ("pipe: Rearrange sequence in pipe_write() to preallocate slot"), when a user copy was done between the allocation and the buf->page = page assignment, and a failure there would then just leave the pipe's one-element page cache populated. Now, the same purpose is served by the page being inserted as a size-0 buffer, and the next write attempting to merge with that buffer. Signed-off-by: Rasmus Villemoes <linux@rasmusvillemoes.dk> --- fs/pipe.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)