Merge patch series "some pipe + wait stuff"
Mateusz Guzik <mjguzik@gmail.com> says: As a side effect of looking at the pipe hang I came up with 3 changes to consider for -next. The first one is a trivial clean up which I wont mind if it merely gets folded into someone else's change for pipes. The second one reduces page alloc/free calls for the backing area (60% less during a kernel build in my testing). I already posted this, but the cc list was not proper. The last one concerns the wait/wakeup mechanism and drops one lock trip in the common case after waking up. * patches from https://lore.kernel.org/r/20250303230409.452687-1-mjguzik@gmail.com: wait: avoid spurious calls to prepare_to_wait_event() in ___wait_event() pipe: cache 2 pages instead of 1 pipe: drop an always true check in anon_pipe_write() Link: https://lore.kernel.org/r/20250303230409.452687-1-mjguzik@gmail.com Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
@@ -112,20 +112,40 @@ void pipe_double_lock(struct pipe_inode_info *pipe1,
|
||||
pipe_lock(pipe2);
|
||||
}
|
||||
|
||||
static struct page *anon_pipe_get_page(struct pipe_inode_info *pipe)
|
||||
{
|
||||
for (int i = 0; i < ARRAY_SIZE(pipe->tmp_page); i++) {
|
||||
if (pipe->tmp_page[i]) {
|
||||
struct page *page = pipe->tmp_page[i];
|
||||
pipe->tmp_page[i] = NULL;
|
||||
return page;
|
||||
}
|
||||
}
|
||||
|
||||
return alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT);
|
||||
}
|
||||
|
||||
static void anon_pipe_put_page(struct pipe_inode_info *pipe,
|
||||
struct page *page)
|
||||
{
|
||||
if (page_count(page) == 1) {
|
||||
for (int i = 0; i < ARRAY_SIZE(pipe->tmp_page); i++) {
|
||||
if (!pipe->tmp_page[i]) {
|
||||
pipe->tmp_page[i] = page;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
put_page(page);
|
||||
}
|
||||
|
||||
static void anon_pipe_buf_release(struct pipe_inode_info *pipe,
|
||||
struct pipe_buffer *buf)
|
||||
{
|
||||
struct page *page = buf->page;
|
||||
|
||||
/*
|
||||
* If nobody else uses this page, and we don't already have a
|
||||
* temporary page, let's keep track of it as a one-deep
|
||||
* allocation cache. (Otherwise just release our reference to it)
|
||||
*/
|
||||
if (page_count(page) == 1 && !pipe->tmp_page)
|
||||
pipe->tmp_page = page;
|
||||
else
|
||||
put_page(page);
|
||||
anon_pipe_put_page(pipe, page);
|
||||
}
|
||||
|
||||
static bool anon_pipe_buf_try_steal(struct pipe_inode_info *pipe,
|
||||
@@ -493,27 +513,25 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
if (!pipe_full(head, pipe->tail, pipe->max_usage)) {
|
||||
unsigned int mask = pipe->ring_size - 1;
|
||||
struct pipe_buffer *buf;
|
||||
struct page *page = pipe->tmp_page;
|
||||
struct page *page;
|
||||
int copied;
|
||||
|
||||
if (!page) {
|
||||
page = alloc_page(GFP_HIGHUSER | __GFP_ACCOUNT);
|
||||
if (unlikely(!page)) {
|
||||
ret = ret ? : -ENOMEM;
|
||||
break;
|
||||
}
|
||||
pipe->tmp_page = page;
|
||||
page = anon_pipe_get_page(pipe);
|
||||
if (unlikely(!page)) {
|
||||
if (!ret)
|
||||
ret = -ENOMEM;
|
||||
break;
|
||||
}
|
||||
|
||||
copied = copy_page_from_iter(page, 0, PAGE_SIZE, from);
|
||||
if (unlikely(copied < PAGE_SIZE && iov_iter_count(from))) {
|
||||
anon_pipe_put_page(pipe, page);
|
||||
if (!ret)
|
||||
ret = -EFAULT;
|
||||
break;
|
||||
}
|
||||
|
||||
pipe->head = head + 1;
|
||||
pipe->tmp_page = NULL;
|
||||
/* Insert it into the buffer array */
|
||||
buf = &pipe->bufs[head & mask];
|
||||
buf->page = page;
|
||||
@@ -529,10 +547,9 @@ anon_pipe_write(struct kiocb *iocb, struct iov_iter *from)
|
||||
|
||||
if (!iov_iter_count(from))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!pipe_full(head, pipe->tail, pipe->max_usage))
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Wait for buffer space to become available. */
|
||||
if ((filp->f_flags & O_NONBLOCK) ||
|
||||
@@ -847,8 +864,10 @@ void free_pipe_info(struct pipe_inode_info *pipe)
|
||||
if (pipe->watch_queue)
|
||||
put_watch_queue(pipe->watch_queue);
|
||||
#endif
|
||||
if (pipe->tmp_page)
|
||||
__free_page(pipe->tmp_page);
|
||||
for (i = 0; i < ARRAY_SIZE(pipe->tmp_page); i++) {
|
||||
if (pipe->tmp_page[i])
|
||||
__free_page(pipe->tmp_page[i]);
|
||||
}
|
||||
kfree(pipe->bufs);
|
||||
kfree(pipe);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ struct pipe_inode_info {
|
||||
#ifdef CONFIG_WATCH_QUEUE
|
||||
bool note_loss;
|
||||
#endif
|
||||
struct page *tmp_page;
|
||||
struct page *tmp_page[2];
|
||||
struct fasync_struct *fasync_readers;
|
||||
struct fasync_struct *fasync_writers;
|
||||
struct pipe_buffer *bufs;
|
||||
|
||||
@@ -316,6 +316,9 @@ extern void init_wait_entry(struct wait_queue_entry *wq_entry, int flags);
|
||||
} \
|
||||
\
|
||||
cmd; \
|
||||
\
|
||||
if (condition) \
|
||||
break; \
|
||||
} \
|
||||
finish_wait(&wq_head, &__wq_entry); \
|
||||
__out: __ret; \
|
||||
|
||||
Reference in New Issue
Block a user