Skip to content

Commit 6a96566

Browse files
committed
Merge tag 'notifications-pipe-prep-20191115' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs
Pull pipe rework from David Howells: "This is my set of preparatory patches for building a general notification queue on top of pipes. It makes a number of significant changes: - It removes the nr_exclusive argument from __wake_up_sync_key() as this is always 1. This prepares for the next step: - Adds wake_up_interruptible_sync_poll_locked() so that poll can be woken up from a function that's holding the poll waitqueue spinlock. - Change the pipe buffer ring to be managed in terms of unbounded head and tail indices rather than bounded index and length. This means that reading the pipe only needs to modify one index, not two. - A selection of helper functions are provided to query the state of the pipe buffer, plus a couple to apply updates to the pipe indices. - The pipe ring is allowed to have kernel-reserved slots. This allows many notification messages to be spliced in by the kernel without allowing userspace to pin too many pages if it writes to the same pipe. - Advance the head and tail indices inside the pipe waitqueue lock and use wake_up_interruptible_sync_poll_locked() to poke poll without having to take the lock twice. - Rearrange pipe_write() to preallocate the buffer it is going to write into and then drop the spinlock. This allows kernel notifications to then be added the ring whilst it is filling the buffer it allocated. The read side is stalled because the pipe mutex is still held. - Don't wake up readers on a pipe if there was already data in it when we added more. - Don't wake up writers on a pipe if the ring wasn't full before we removed a buffer" * tag 'notifications-pipe-prep-20191115' of git://git.kernel.org/pub/scm/linux/kernel/git/dhowells/linux-fs: pipe: Remove sync on wake_ups pipe: Increase the writer-wakeup threshold to reduce context-switch count pipe: Check for ring full inside of the spinlock in pipe_write() pipe: Remove redundant wakeup from pipe_write() pipe: Rearrange sequence in pipe_write() to preallocate slot pipe: Conditionalise wakeup in pipe_read() pipe: Advance tail pointer inside of wait spinlock in pipe_read() pipe: Allow pipes to have kernel-reserved slots pipe: Use head and tail pointers for the ring, not cursor and length Add wake_up_interruptible_sync_poll_locked() Remove the nr_exclusive argument from __wake_up_sync_key() pipe: Reduce #inclusion of pipe_fs_i.h
2 parents 32ef955 + 3c0edea commit 6a96566

File tree

13 files changed

+532
-334
lines changed

13 files changed

+532
-334
lines changed

drivers/char/virtio_console.c

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -919,6 +919,7 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
919919
.pos = *ppos,
920920
.u.data = &sgl,
921921
};
922+
unsigned int occupancy;
922923

923924
/*
924925
* Rproc_serial does not yet support splice. To support splice
@@ -929,29 +930,26 @@ static ssize_t port_fops_splice_write(struct pipe_inode_info *pipe,
929930
if (is_rproc_serial(port->out_vq->vdev))
930931
return -EINVAL;
931932

932-
/*
933-
* pipe->nrbufs == 0 means there are no data to transfer,
934-
* so this returns just 0 for no data.
935-
*/
936933
pipe_lock(pipe);
937-
if (!pipe->nrbufs) {
938-
ret = 0;
934+
ret = 0;
935+
if (pipe_empty(pipe->head, pipe->tail))
939936
goto error_out;
940-
}
941937

942938
ret = wait_port_writable(port, filp->f_flags & O_NONBLOCK);
943939
if (ret < 0)
944940
goto error_out;
945941

946-
buf = alloc_buf(port->portdev->vdev, 0, pipe->nrbufs);
942+
occupancy = pipe_occupancy(pipe->head, pipe->tail);
943+
buf = alloc_buf(port->portdev->vdev, 0, occupancy);
944+
947945
if (!buf) {
948946
ret = -ENOMEM;
949947
goto error_out;
950948
}
951949

952950
sgl.n = 0;
953951
sgl.len = 0;
954-
sgl.size = pipe->nrbufs;
952+
sgl.size = occupancy;
955953
sgl.sg = buf->sg;
956954
sg_init_table(sgl.sg, sgl.size);
957955
ret = __splice_from_pipe(pipe, &sd, pipe_to_sg);

fs/exec.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,6 @@
5959
#include <linux/kmod.h>
6060
#include <linux/fsnotify.h>
6161
#include <linux/fs_struct.h>
62-
#include <linux/pipe_fs_i.h>
6362
#include <linux/oom.h>
6463
#include <linux/compat.h>
6564
#include <linux/vmalloc.h>

fs/fuse/dev.c

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -705,7 +705,7 @@ static int fuse_copy_fill(struct fuse_copy_state *cs)
705705
cs->pipebufs++;
706706
cs->nr_segs--;
707707
} else {
708-
if (cs->nr_segs == cs->pipe->buffers)
708+
if (cs->nr_segs >= cs->pipe->max_usage)
709709
return -EIO;
710710

711711
page = alloc_page(GFP_HIGHUSER);
@@ -881,7 +881,7 @@ static int fuse_ref_page(struct fuse_copy_state *cs, struct page *page,
881881
struct pipe_buffer *buf;
882882
int err;
883883

884-
if (cs->nr_segs == cs->pipe->buffers)
884+
if (cs->nr_segs >= cs->pipe->max_usage)
885885
return -EIO;
886886

887887
err = unlock_request(cs->req);
@@ -1343,7 +1343,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
13431343
if (!fud)
13441344
return -EPERM;
13451345

1346-
bufs = kvmalloc_array(pipe->buffers, sizeof(struct pipe_buffer),
1346+
bufs = kvmalloc_array(pipe->max_usage, sizeof(struct pipe_buffer),
13471347
GFP_KERNEL);
13481348
if (!bufs)
13491349
return -ENOMEM;
@@ -1355,7 +1355,7 @@ static ssize_t fuse_dev_splice_read(struct file *in, loff_t *ppos,
13551355
if (ret < 0)
13561356
goto out;
13571357

1358-
if (pipe->nrbufs + cs.nr_segs > pipe->buffers) {
1358+
if (pipe_occupancy(pipe->head, pipe->tail) + cs.nr_segs > pipe->max_usage) {
13591359
ret = -EIO;
13601360
goto out;
13611361
}
@@ -1937,6 +1937,7 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
19371937
struct file *out, loff_t *ppos,
19381938
size_t len, unsigned int flags)
19391939
{
1940+
unsigned int head, tail, mask, count;
19401941
unsigned nbuf;
19411942
unsigned idx;
19421943
struct pipe_buffer *bufs;
@@ -1951,17 +1952,21 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
19511952

19521953
pipe_lock(pipe);
19531954

1954-
bufs = kvmalloc_array(pipe->nrbufs, sizeof(struct pipe_buffer),
1955-
GFP_KERNEL);
1955+
head = pipe->head;
1956+
tail = pipe->tail;
1957+
mask = pipe->ring_size - 1;
1958+
count = head - tail;
1959+
1960+
bufs = kvmalloc_array(count, sizeof(struct pipe_buffer), GFP_KERNEL);
19561961
if (!bufs) {
19571962
pipe_unlock(pipe);
19581963
return -ENOMEM;
19591964
}
19601965

19611966
nbuf = 0;
19621967
rem = 0;
1963-
for (idx = 0; idx < pipe->nrbufs && rem < len; idx++)
1964-
rem += pipe->bufs[(pipe->curbuf + idx) & (pipe->buffers - 1)].len;
1968+
for (idx = tail; idx < head && rem < len; idx++)
1969+
rem += pipe->bufs[idx & mask].len;
19651970

19661971
ret = -EINVAL;
19671972
if (rem < len)
@@ -1972,16 +1977,16 @@ static ssize_t fuse_dev_splice_write(struct pipe_inode_info *pipe,
19721977
struct pipe_buffer *ibuf;
19731978
struct pipe_buffer *obuf;
19741979

1975-
BUG_ON(nbuf >= pipe->buffers);
1976-
BUG_ON(!pipe->nrbufs);
1977-
ibuf = &pipe->bufs[pipe->curbuf];
1980+
BUG_ON(nbuf >= pipe->ring_size);
1981+
BUG_ON(tail == head);
1982+
ibuf = &pipe->bufs[tail & mask];
19781983
obuf = &bufs[nbuf];
19791984

19801985
if (rem >= ibuf->len) {
19811986
*obuf = *ibuf;
19821987
ibuf->ops = NULL;
1983-
pipe->curbuf = (pipe->curbuf + 1) & (pipe->buffers - 1);
1984-
pipe->nrbufs--;
1988+
tail++;
1989+
pipe->tail = tail;
19851990
} else {
19861991
if (!pipe_buf_get(pipe, ibuf))
19871992
goto out_free;

fs/ocfs2/aops.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
#include <linux/pagemap.h>
1212
#include <asm/byteorder.h>
1313
#include <linux/swap.h>
14-
#include <linux/pipe_fs_i.h>
1514
#include <linux/mpage.h>
1615
#include <linux/quotaops.h>
1716
#include <linux/blkdev.h>

0 commit comments

Comments
 (0)