pipe: Fix missing mask update after pipe_wait()
[platform/kernel/linux-starfive.git] / fs / pipe.c
index d7b8d3f..70313af 100644 (file)
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -324,16 +324,18 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
                        }
 
                        if (!buf->len) {
+                               bool wake;
                                pipe_buf_release(pipe, buf);
                                spin_lock_irq(&pipe->wait.lock);
                                tail++;
                                pipe->tail = tail;
                                do_wakeup = 1;
-                               if (head - (tail - 1) == pipe->max_usage)
-                                       wake_up_interruptible_sync_poll_locked(
+                               wake = head - (tail - 1) == pipe->max_usage / 2;
+                               if (wake)
+                                       wake_up_locked_poll(
                                                &pipe->wait, EPOLLOUT | EPOLLWRNORM);
                                spin_unlock_irq(&pipe->wait.lock);
-                               if (head - (tail - 1) == pipe->max_usage)
+                               if (wake)
                                        kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
                        }
                        total_len -= chars;
@@ -369,7 +371,7 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
 
        /* Signal writers asynchronously that there is more room. */
        if (do_wakeup) {
-               wake_up_interruptible_sync_poll(&pipe->wait, EPOLLOUT | EPOLLWRNORM);
+               wake_up_interruptible_poll(&pipe->wait, EPOLLOUT | EPOLLWRNORM);
                kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT);
        }
        if (ret > 0)
@@ -387,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);
@@ -406,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;
 
@@ -441,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;
@@ -463,6 +465,11 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                        spin_lock_irq(&pipe->wait.lock);
 
                        head = pipe->head;
+                       if (pipe_full(head, pipe->tail, pipe->max_usage)) {
+                               spin_unlock_irq(&pipe->wait.lock);
+                               continue;
+                       }
+
                        pipe->head = head + 1;
 
                        /* Always wake up, even if the copy fails. Otherwise
@@ -470,7 +477,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
                         * syscall merging.
                         * FIXME! Is this really true?
                         */
-                       wake_up_interruptible_sync_poll_locked(
+                       wake_up_locked_poll(
                                &pipe->wait, EPOLLIN | EPOLLRDNORM);
 
                        spin_unlock_irq(&pipe->wait.lock);
@@ -503,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. */
@@ -524,7 +531,7 @@ pipe_write(struct kiocb *iocb, struct iov_iter *from)
 out:
        __pipe_unlock(pipe);
        if (do_wakeup) {
-               wake_up_interruptible_sync_poll(&pipe->wait, EPOLLIN | EPOLLRDNORM);
+               wake_up_interruptible_poll(&pipe->wait, EPOLLIN | EPOLLRDNORM);
                kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
        }
        if (ret > 0 && sb_start_write_trylock(file_inode(filp)->i_sb)) {
@@ -572,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) {
@@ -1167,6 +1172,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: