[RFC] [PATCH] splice: add ->splice_read support for /dev/zero

From: Octavian Purdila
Date: Wed Aug 06 2008 - 22:04:20 EST


Useful for testing.

Preallocating the zero page is simpler and faster with the relatively
small (?) drawback of using an extra page of memory.

Maybe when CONFIG_EMBEDED is selected we can switch to dynamically
allocating the page?

Signed-off-by: Octavian Purdila <opurdila@xxxxxxxxxxx>
---
drivers/char/mem.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 68 insertions(+), 0 deletions(-)

diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 934ffaf..fb33f9a 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -737,6 +737,69 @@ static int mmap_zero(struct file * file, struct vm_area_struct * vma)
return 0;
}

+static void zero_pipe_buf_release(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+}
+
+static void zero_pipe_buf_get(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+}
+
+static int zero_pipe_buf_steal(struct pipe_inode_info *pipe,
+ struct pipe_buffer *buf)
+{
+ return 1;
+}
+
+static struct pipe_buf_operations zero_pipe_buf_ops = {
+ .can_merge = 0,
+ .map = generic_pipe_buf_map,
+ .unmap = generic_pipe_buf_unmap,
+ .confirm = generic_pipe_buf_confirm,
+ .release = zero_pipe_buf_release,
+ .steal = zero_pipe_buf_steal,
+ .get = zero_pipe_buf_get,
+};
+
+static void zero_spd_release(struct splice_pipe_desc *spd, unsigned int nr)
+{
+}
+
+static struct page *zero_page;
+
+ssize_t splice_read_zero(struct file *in, loff_t *ppos,
+ struct pipe_inode_info *pipe, size_t size,
+ unsigned int flags)
+{
+ struct partial_page partial[PIPE_BUFFERS];
+ struct page *pages[PIPE_BUFFERS];
+ struct splice_pipe_desc spd = {
+ .pages = pages,
+ .partial = partial,
+ .flags = flags,
+ .ops = &zero_pipe_buf_ops,
+ .spd_release = zero_spd_release
+ };
+ int last_page_len = PAGE_SIZE, i;
+
+ spd.nr_pages = size/PAGE_SIZE;
+ if (spd.nr_pages > PIPE_BUFFERS)
+ spd.nr_pages = PIPE_BUFFERS;
+ if (size < PAGE_SIZE*PIPE_BUFFERS)
+ last_page_len = size % PAGE_SIZE;
+
+ for (i = 0; i < spd.nr_pages; i++) {
+ pages[i] = zero_page;
+ partial[i].len = PAGE_SIZE;
+ partial[i].offset = 0;
+ }
+ partial[spd.nr_pages].len = last_page_len;
+
+ return splice_to_pipe(pipe, &spd);
+}
+
static ssize_t write_full(struct file * file, const char __user * buf,
size_t count, loff_t *ppos)
{
@@ -839,6 +902,7 @@ static const struct file_operations zero_fops = {
.read = read_zero,
.write = write_zero,
.mmap = mmap_zero,
+ .splice_read = splice_read_zero,
};

/*
@@ -974,6 +1038,10 @@ static int __init chr_dev_init(void)
int i;
int err;

+ zero_page = alloc_pages(GFP_KERNEL | __GFP_ZERO, 0);
+ if (!zero_page)
+ return -ENOMEM;
+
err = bdi_init(&zero_bdi);
if (err)
return err;
--
1.5.6.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/