You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
pipe: add support for shrinking and growing pipes
This patch adds F_GETPIPE_SZ and F_SETPIPE_SZ fcntl() actions for growing and shrinking the size of a pipe and adjusts pipe.c and splice.c (and relay and network splice) usage to work with these larger (or smaller) pipes. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
+10
-5
@@ -1231,8 +1231,8 @@ static ssize_t subbuf_splice_actor(struct file *in,
|
||||
size_t read_subbuf = read_start / subbuf_size;
|
||||
size_t padding = rbuf->padding[read_subbuf];
|
||||
size_t nonpad_end = read_subbuf * subbuf_size + subbuf_size - padding;
|
||||
struct page *pages[PIPE_BUFFERS];
|
||||
struct partial_page partial[PIPE_BUFFERS];
|
||||
struct page *pages[PIPE_DEF_BUFFERS];
|
||||
struct partial_page partial[PIPE_DEF_BUFFERS];
|
||||
struct splice_pipe_desc spd = {
|
||||
.pages = pages,
|
||||
.nr_pages = 0,
|
||||
@@ -1245,6 +1245,8 @@ static ssize_t subbuf_splice_actor(struct file *in,
|
||||
|
||||
if (rbuf->subbufs_produced == rbuf->subbufs_consumed)
|
||||
return 0;
|
||||
if (splice_grow_spd(pipe, &spd))
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Adjust read len, if longer than what is available
|
||||
@@ -1255,7 +1257,7 @@ static ssize_t subbuf_splice_actor(struct file *in,
|
||||
subbuf_pages = rbuf->chan->alloc_size >> PAGE_SHIFT;
|
||||
pidx = (read_start / PAGE_SIZE) % subbuf_pages;
|
||||
poff = read_start & ~PAGE_MASK;
|
||||
nr_pages = min_t(unsigned int, subbuf_pages, PIPE_BUFFERS);
|
||||
nr_pages = min_t(unsigned int, subbuf_pages, pipe->buffers);
|
||||
|
||||
for (total_len = 0; spd.nr_pages < nr_pages; spd.nr_pages++) {
|
||||
unsigned int this_len, this_end, private;
|
||||
@@ -1289,16 +1291,19 @@ static ssize_t subbuf_splice_actor(struct file *in,
|
||||
}
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
if (!spd.nr_pages)
|
||||
return 0;
|
||||
goto out;
|
||||
|
||||
ret = *nonpad_ret = splice_to_pipe(pipe, &spd);
|
||||
if (ret < 0 || ret < total_len)
|
||||
return ret;
|
||||
goto out;
|
||||
|
||||
if (read_start + ret == nonpad_end)
|
||||
ret += padding;
|
||||
|
||||
out:
|
||||
splice_shrink_spd(pipe, &spd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
+36
-24
@@ -3269,12 +3269,12 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
|
||||
size_t len,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct page *pages[PIPE_BUFFERS];
|
||||
struct partial_page partial[PIPE_BUFFERS];
|
||||
struct page *pages_def[PIPE_DEF_BUFFERS];
|
||||
struct partial_page partial_def[PIPE_DEF_BUFFERS];
|
||||
struct trace_iterator *iter = filp->private_data;
|
||||
struct splice_pipe_desc spd = {
|
||||
.pages = pages,
|
||||
.partial = partial,
|
||||
.pages = pages_def,
|
||||
.partial = partial_def,
|
||||
.nr_pages = 0, /* This gets updated below. */
|
||||
.flags = flags,
|
||||
.ops = &tracing_pipe_buf_ops,
|
||||
@@ -3285,6 +3285,9 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
|
||||
size_t rem;
|
||||
unsigned int i;
|
||||
|
||||
if (splice_grow_spd(pipe, &spd))
|
||||
return -ENOMEM;
|
||||
|
||||
/* copy the tracer to avoid using a global lock all around */
|
||||
mutex_lock(&trace_types_lock);
|
||||
if (unlikely(old_tracer != current_trace && current_trace)) {
|
||||
@@ -3315,23 +3318,23 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
|
||||
trace_access_lock(iter->cpu_file);
|
||||
|
||||
/* Fill as many pages as possible. */
|
||||
for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) {
|
||||
pages[i] = alloc_page(GFP_KERNEL);
|
||||
if (!pages[i])
|
||||
for (i = 0, rem = len; i < pipe->buffers && rem; i++) {
|
||||
spd.pages[i] = alloc_page(GFP_KERNEL);
|
||||
if (!spd.pages[i])
|
||||
break;
|
||||
|
||||
rem = tracing_fill_pipe_page(rem, iter);
|
||||
|
||||
/* Copy the data into the page, so we can start over. */
|
||||
ret = trace_seq_to_buffer(&iter->seq,
|
||||
page_address(pages[i]),
|
||||
page_address(spd.pages[i]),
|
||||
iter->seq.len);
|
||||
if (ret < 0) {
|
||||
__free_page(pages[i]);
|
||||
__free_page(spd.pages[i]);
|
||||
break;
|
||||
}
|
||||
partial[i].offset = 0;
|
||||
partial[i].len = iter->seq.len;
|
||||
spd.partial[i].offset = 0;
|
||||
spd.partial[i].len = iter->seq.len;
|
||||
|
||||
trace_seq_init(&iter->seq);
|
||||
}
|
||||
@@ -3342,12 +3345,14 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
|
||||
|
||||
spd.nr_pages = i;
|
||||
|
||||
return splice_to_pipe(pipe, &spd);
|
||||
ret = splice_to_pipe(pipe, &spd);
|
||||
out:
|
||||
splice_shrink_spd(pipe, &spd);
|
||||
return ret;
|
||||
|
||||
out_err:
|
||||
mutex_unlock(&iter->mutex);
|
||||
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
@@ -3746,11 +3751,11 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct ftrace_buffer_info *info = file->private_data;
|
||||
struct partial_page partial[PIPE_BUFFERS];
|
||||
struct page *pages[PIPE_BUFFERS];
|
||||
struct partial_page partial_def[PIPE_DEF_BUFFERS];
|
||||
struct page *pages_def[PIPE_DEF_BUFFERS];
|
||||
struct splice_pipe_desc spd = {
|
||||
.pages = pages,
|
||||
.partial = partial,
|
||||
.pages = pages_def,
|
||||
.partial = partial_def,
|
||||
.flags = flags,
|
||||
.ops = &buffer_pipe_buf_ops,
|
||||
.spd_release = buffer_spd_release,
|
||||
@@ -3759,22 +3764,28 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
|
||||
int entries, size, i;
|
||||
size_t ret;
|
||||
|
||||
if (splice_grow_spd(pipe, &spd))
|
||||
return -ENOMEM;
|
||||
|
||||
if (*ppos & (PAGE_SIZE - 1)) {
|
||||
WARN_ONCE(1, "Ftrace: previous read must page-align\n");
|
||||
return -EINVAL;
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (len & (PAGE_SIZE - 1)) {
|
||||
WARN_ONCE(1, "Ftrace: splice_read should page-align\n");
|
||||
if (len < PAGE_SIZE)
|
||||
return -EINVAL;
|
||||
if (len < PAGE_SIZE) {
|
||||
ret = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
len &= PAGE_MASK;
|
||||
}
|
||||
|
||||
trace_access_lock(info->cpu);
|
||||
entries = ring_buffer_entries_cpu(info->tr->buffer, info->cpu);
|
||||
|
||||
for (i = 0; i < PIPE_BUFFERS && len && entries; i++, len -= PAGE_SIZE) {
|
||||
for (i = 0; i < pipe->buffers && len && entries; i++, len -= PAGE_SIZE) {
|
||||
struct page *page;
|
||||
int r;
|
||||
|
||||
@@ -3829,11 +3840,12 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
|
||||
else
|
||||
ret = 0;
|
||||
/* TODO: block */
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = splice_to_pipe(pipe, &spd);
|
||||
|
||||
splice_shrink_spd(pipe, &spd);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user