Commit da73fcd8 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'pipe-rework' (patches from David Howells)

Merge two fixes for the pipe rework from David Howells:
 "Here are a couple of patches to fix bugs syzbot found in the pipe
  changes:

   - An assertion check will sometimes trip when polling a pipe because
     the ring size and indices used are approximate and may be being
     changed simultaneously.

     An equivalent approximate calculation was done previously, but
     without the assertion check, so I've just dropped the check. To
     make it accurate, the pipe mutex would need to be taken or the spin
     lock could be used - but usage of the spinlock would need to be
     rolled out into splice, iov_iter and other places for that.

   - The index mask and the max_usage values cannot be cached across
     pipe_wait() as F_SETPIPE_SZ could have been called during the wait.
     This can cause pipe_write() to break"

* pipe-rework:
  pipe: Fix missing mask update after pipe_wait()
  pipe: Remove assertion from pipe_poll()
parents 3f1266ec 8f868d68
......@@ -389,7 +389,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
{
struct file *filp = iocb->ki_filp;
struct pipe_inode_info *pipe = filp->private_data;
unsigned int head, max_usage, mask;
unsigned int head;
ssize_t ret = 0;
int do_wakeup = 0;
size_t total_len = iov_iter_count(from);
......@@ -408,12 +408,11 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
}
head = pipe->head;
max_usage = pipe->max_usage;
mask = pipe->ring_size - 1;
/* We try to merge small writes */
chars = total_len & (PAGE_SIZE-1); /* size of the last buffer */
if (!pipe_empty(head, pipe->tail) && chars != 0) {
unsigned int mask = pipe->ring_size - 1;
struct pipe_buffer *buf = &pipe->bufs[(head - 1) & mask];
int offset = buf->offset + buf->len;
......@@ -443,7 +442,8 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
}
head = pipe->head;
if (!pipe_full(head, pipe->tail, max_usage)) {
if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
unsigned int mask = pipe->ring_size - 1;
struct pipe_buffer *buf = &pipe->bufs[head & mask];
struct page *page = pipe->tmp_page;
int copied;
......@@ -465,7 +465,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
spin_lock_irq(&pipe->wait.lock);
head = pipe->head;
if (pipe_full(head, pipe->tail, max_usage)) {
if (pipe_full(head, pipe->tail, pipe->max_usage)) {
spin_unlock_irq(&pipe->wait.lock);
continue;
}
......@@ -510,7 +510,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
break;
}
if (!pipe_full(head, pipe->tail, max_usage))
if (!pipe_full(head, pipe->tail, pipe->max_usage))
continue;
/* Wait for buffer space to become available. */
......@@ -579,8 +579,6 @@ pipe_poll(struct file *filp, poll_table *wait)
poll_wait(filp, &pipe->wait, wait);
BUG_ON(pipe_occupancy(head, tail) > pipe->ring_size);
/* Reading only -- no need for acquiring the semaphore. */
mask = 0;
if (filp->f_mode & FMODE_READ) {
......@@ -1176,6 +1174,7 @@ static long pipe_set_size(struct pipe_inode_info *pipe, unsigned long arg)
pipe->max_usage = nr_slots;
pipe->tail = tail;
pipe->head = head;
wake_up_interruptible_all(&pipe->wait);
return pipe->max_usage * PAGE_SIZE;
out_revert_acct:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment