diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-12-05 16:35:53 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-12-05 16:35:53 -0800 |
commit | da73fcd8cfdc3d0ef49280fa0d511723a0220e03 (patch) | |
tree | eabffed509dec4905670a19bc94fb73328f319ca /fs | |
parent | 3f1266ec704d3efcfc8179c71bed9a75963b6344 (diff) | |
parent | 8f868d68d335a17923dffb6858f8e9b656424699 (diff) | |
download | lwn-da73fcd8cfdc3d0ef49280fa0d511723a0220e03.tar.gz lwn-da73fcd8cfdc3d0ef49280fa0d511723a0220e03.zip |
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()
Diffstat (limited to 'fs')
-rw-r--r-- | fs/pipe.c | 15 |
1 files changed, 7 insertions, 8 deletions
diff --git a/fs/pipe.c b/fs/pipe.c index 648ce440ca85..b901c8eefafd 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -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: |