Skip to content

Commit ee5eda8

Browse files
oleg-nesterovbrauner
authored andcommitted
pipe: change pipe_write() to never add a zero-sized buffer
a194dfe ("pipe: Rearrange sequence in pipe_write() to preallocate slot") changed pipe_write() to increment pipe->head in advance. IIUC to avoid the race with the post_one_notification()-like code which can add another buffer under pipe->rd_wait.lock without pipe->mutex. This is no longer necessary after c73be61 ("pipe: Add general notification queue support"), pipe_write() checks pipe_has_watch_queue() and returns -EXDEV at the start. And can't help in any case, pipe_write() no longer takes this rd_wait.lock spinlock. Change pipe_write() to call copy_page_from_iter() first and do nothing if it fails. This way pipe_write() can't add a zero-sized buffer and we can simplify pipe_read() which currently has to take care of this very unlikely case. Also, with this patch we can probably kill eat_empty_buffer() and more "is this buffer empty" checks in fs/splice.c later. Link: https://lore.kernel.org/all/20250209150718.GA17013@redhat.com/ Signed-off-by: Oleg Nesterov <oleg@redhat.com> Link: https://lore.kernel.org/r/20250210114039.GA3588@redhat.com Tested-by: K Prateek Nayak <kprateek.nayak@amd.com> Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent f2ffc48 commit ee5eda8

1 file changed

Lines changed: 9 additions & 36 deletions

File tree

fs/pipe.c

Lines changed: 9 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -360,29 +360,9 @@ anon_pipe_read(struct kiocb *iocb, struct iov_iter *to)
360360
break;
361361
}
362362
mutex_unlock(&pipe->mutex);
363-
364363
/*
365364
* We only get here if we didn't actually read anything.
366365
*
367-
* However, we could have seen (and removed) a zero-sized
368-
* pipe buffer, and might have made space in the buffers
369-
* that way.
370-
*
371-
* You can't make zero-sized pipe buffers by doing an empty
372-
* write (not even in packet mode), but they can happen if
373-
* the writer gets an EFAULT when trying to fill a buffer
374-
* that already got allocated and inserted in the buffer
375-
* array.
376-
*
377-
* So we still need to wake up any pending writers in the
378-
* _very_ unlikely case that the pipe was full, but we got
379-
* no data.
380-
*/
381-
if (unlikely(wake_writer))
382-
wake_up_interruptible_sync_poll(&pipe->wr_wait, EPOLLOUT | EPOLLWRNORM);
383-
kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
384-
385-
/*
386366
* But because we didn't read anything, at this point we can
387367
* just return directly with -ERESTARTSYS if we're interrupted,
388368
* since we've done any required wakeups and there's no need
@@ -391,7 +371,6 @@ anon_pipe_read(struct kiocb *iocb, struct iov_iter *to)
391371
if (wait_event_interruptible_exclusive(pipe->rd_wait, pipe_readable(pipe)) < 0)
392372
return -ERESTARTSYS;
393373

394-
wake_writer = false;
395374
wake_next_reader = true;
396375
mutex_lock(&pipe->mutex);
397376
}
@@ -526,33 +505,27 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
526505
pipe->tmp_page = page;
527506
}
528507

529-
/* Allocate a slot in the ring in advance and attach an
530-
* empty buffer. If we fault or otherwise fail to use
531-
* it, either the reader will consume it or it'll still
532-
* be there for the next write.
533-
*/
534-
pipe->head = head + 1;
508+
copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
509+
if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
510+
if (!ret)
511+
ret = -EFAULT;
512+
break;
513+
}
535514

515+
pipe->head = head + 1;
516+
pipe->tmp_page = NULL;
536517
/* Insert it into the buffer array */
537518
buf = &pipe->bufs[head & mask];
538519
buf->page = page;
539520
buf->ops = &anon_pipe_buf_ops;
540521
buf->offset = 0;
541-
buf->len = 0;
542522
if (is_packetized(filp))
543523
buf->flags = PIPE_BUF_FLAG_PACKET;
544524
else
545525
buf->flags = PIPE_BUF_FLAG_CAN_MERGE;
546-
pipe->tmp_page = NULL;
547526

548-
copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
549-
if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
550-
if (!ret)
551-
ret = -EFAULT;
552-
break;
553-
}
554-
ret += copied;
555527
buf->len = copied;
528+
ret += copied;
556529

557530
if (!iov_iter_count(from))
558531
break;

0 commit comments

Comments
 (0)