Skip to content

Commit f4f15c1

Browse files
MaxKellermannopsiff
authored andcommitted
fs/pipe: use spinlock in pipe_read() only if there is a watch_queue
mainline inclusion from mainline-v6.7-rc1 category: performance If there is no watch_queue, holding the pipe mutex is enough to prevent concurrent writes, and we can avoid the spinlock. O_NOTIFICATION_QUEUE is an exotic and rarely used feature, and of all the pipes that exist at any given time, only very few actually have a watch_queue, therefore it appears worthwile to optimize the common case. This patch does not optimize pipe_resize_ring() where the spinlocks could be avoided as well; that does not seem like a worthwile optimization because this function is not called often. Related commits: - commit 8df4412 ("pipe: Check for ring full inside of the spinlock in pipe_write()") - commit b667b86 ("pipe: Advance tail pointer inside of wait spinlock in pipe_read()") - commit 189b0dd ("pipe: Fix missing lock in pipe_resize_ring()") Signed-off-by: Max Kellermann <max.kellermann@ionos.com> Message-Id: <20230921075755.1378787-4-max.kellermann@ionos.com> Reviewed-by: David Howells <dhowells@redhat.com> Signed-off-by: Christian Brauner <brauner@kernel.org> (cherry picked from commit 478dbf1) Signed-off-by: Wentao Guan <guanwentao@uniontech.com> Change-Id: Icdeb15fb11c0c6e6d07a3adb17b46457795396a0
1 parent 9f5b0a6 commit f4f15c1

1 file changed

Lines changed: 32 additions & 11 deletions

File tree

fs/pipe.c

Lines changed: 32 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,36 @@ static inline bool pipe_readable(const struct pipe_inode_info *pipe)
227227
return !pipe_empty(head, tail) || !writers;
228228
}
229229

230+
static inline unsigned int pipe_update_tail(struct pipe_inode_info *pipe,
231+
struct pipe_buffer *buf,
232+
unsigned int tail)
233+
{
234+
pipe_buf_release(pipe, buf);
235+
236+
/*
237+
* If the pipe has a watch_queue, we need additional protection
238+
* by the spinlock because notifications get posted with only
239+
* this spinlock, no mutex
240+
*/
241+
if (pipe_has_watch_queue(pipe)) {
242+
spin_lock_irq(&pipe->rd_wait.lock);
243+
#ifdef CONFIG_WATCH_QUEUE
244+
if (buf->flags & PIPE_BUF_FLAG_LOSS)
245+
pipe->note_loss = true;
246+
#endif
247+
pipe->tail = ++tail;
248+
spin_unlock_irq(&pipe->rd_wait.lock);
249+
return tail;
250+
}
251+
252+
/*
253+
* Without a watch_queue, we can simply increment the tail
254+
* without the spinlock - the mutex is enough.
255+
*/
256+
pipe->tail = ++tail;
257+
return tail;
258+
}
259+
230260
static ssize_t
231261
pipe_read(struct kiocb *iocb, struct iov_iter *to)
232262
{
@@ -320,17 +350,8 @@ pipe_read(struct kiocb *iocb, struct iov_iter *to)
320350
buf->len = 0;
321351
}
322352

323-
if (!buf->len) {
324-
pipe_buf_release(pipe, buf);
325-
spin_lock_irq(&pipe->rd_wait.lock);
326-
#ifdef CONFIG_WATCH_QUEUE
327-
if (buf->flags & PIPE_BUF_FLAG_LOSS)
328-
pipe->note_loss = true;
329-
#endif
330-
tail++;
331-
pipe->tail = tail;
332-
spin_unlock_irq(&pipe->rd_wait.lock);
333-
}
353+
if (!buf->len)
354+
tail = pipe_update_tail(pipe, buf, tail);
334355
total_len -= chars;
335356
if (!total_len)
336357
break; /* common path: read succeeded */

0 commit comments

Comments
 (0)