aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <miklos@szeredi.hu>2009-05-07 09:37:36 -0400
committerJens Axboe <jens.axboe@oracle.com>2009-05-11 08:13:10 -0400
commit6818173bd658439b83896a2a7586f64ab51bf29c (patch)
tree17d25ee77485af18da1a80cb7f1d8ec581c6abfc
parent7c77f0b3f9208c339a4b40737bb2cb0f0319bb8d (diff)
splice: implement default splice_read method
If f_op->splice_read() is not implemented, fall back to a plain read. Use vfs_readv() to read into previously allocated pages. This will allow splice and functions using splice, such as the loop device, to work on all filesystems. This includes "direct_io" files in fuse which bypass the page cache. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--drivers/block/loop.c11
-rw-r--r--fs/coda/file.c9
-rw-r--r--fs/pipe.c14
-rw-r--r--fs/read_write.c7
-rw-r--r--fs/splice.c120
-rw-r--r--include/linux/fs.h2
-rw-r--r--include/linux/pipe_fs_i.h1
7 files changed, 140 insertions, 24 deletions
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 9ca4bb014657..801f4ab83302 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -709,10 +709,6 @@ static int loop_change_fd(struct loop_device *lo, struct block_device *bdev,
709 if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode)) 709 if (!S_ISREG(inode->i_mode) && !S_ISBLK(inode->i_mode))
710 goto out_putf; 710 goto out_putf;
711 711
712 /* new backing store needs to support loop (eg splice_read) */
713 if (!inode->i_fop->splice_read)
714 goto out_putf;
715
716 /* size of the new backing store needs to be the same */ 712 /* size of the new backing store needs to be the same */
717 if (get_loop_size(lo, file) != get_loop_size(lo, old_file)) 713 if (get_loop_size(lo, file) != get_loop_size(lo, old_file))
718 goto out_putf; 714 goto out_putf;
@@ -788,12 +784,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
788 error = -EINVAL; 784 error = -EINVAL;
789 if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) { 785 if (S_ISREG(inode->i_mode) || S_ISBLK(inode->i_mode)) {
790 const struct address_space_operations *aops = mapping->a_ops; 786 const struct address_space_operations *aops = mapping->a_ops;
791 /* 787
792 * If we can't read - sorry. If we only can't write - well,
793 * it's going to be read-only.
794 */
795 if (!file->f_op->splice_read)
796 goto out_putf;
797 if (aops->write_begin) 788 if (aops->write_begin)
798 lo_flags |= LO_FLAGS_USE_AOPS; 789 lo_flags |= LO_FLAGS_USE_AOPS;
799 if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write) 790 if (!(lo_flags & LO_FLAGS_USE_AOPS) && !file->f_op->write)
diff --git a/fs/coda/file.c b/fs/coda/file.c
index 6a347fbc998a..ffd42815fda1 100644
--- a/fs/coda/file.c
+++ b/fs/coda/file.c
@@ -47,6 +47,8 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos,
47 struct pipe_inode_info *pipe, size_t count, 47 struct pipe_inode_info *pipe, size_t count,
48 unsigned int flags) 48 unsigned int flags)
49{ 49{
50 ssize_t (*splice_read)(struct file *, loff_t *,
51 struct pipe_inode_info *, size_t, unsigned int);
50 struct coda_file_info *cfi; 52 struct coda_file_info *cfi;
51 struct file *host_file; 53 struct file *host_file;
52 54
@@ -54,10 +56,11 @@ coda_file_splice_read(struct file *coda_file, loff_t *ppos,
54 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 56 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC);
55 host_file = cfi->cfi_container; 57 host_file = cfi->cfi_container;
56 58
57 if (!host_file->f_op || !host_file->f_op->splice_read) 59 splice_read = host_file->f_op->splice_read;
58 return -EINVAL; 60 if (!splice_read)
61 splice_read = default_file_splice_read;
59 62
60 return host_file->f_op->splice_read(host_file, ppos, pipe, count,flags); 63 return splice_read(host_file, ppos, pipe, count, flags);
61} 64}
62 65
63static ssize_t 66static ssize_t
diff --git a/fs/pipe.c b/fs/pipe.c
index 13414ec45b8d..f7dd21ad85a6 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -302,6 +302,20 @@ int generic_pipe_buf_confirm(struct pipe_inode_info *info,
302 return 0; 302 return 0;
303} 303}
304 304
305/**
306 * generic_pipe_buf_release - put a reference to a &struct pipe_buffer
307 * @pipe: the pipe that the buffer belongs to
308 * @buf: the buffer to put a reference to
309 *
310 * Description:
311 * This function releases a reference to @buf.
312 */
313void generic_pipe_buf_release(struct pipe_inode_info *pipe,
314 struct pipe_buffer *buf)
315{
316 page_cache_release(buf->page);
317}
318
305static const struct pipe_buf_operations anon_pipe_buf_ops = { 319static const struct pipe_buf_operations anon_pipe_buf_ops = {
306 .can_merge = 1, 320 .can_merge = 1,
307 .map = generic_pipe_buf_map, 321 .map = generic_pipe_buf_map,
diff --git a/fs/read_write.c b/fs/read_write.c
index 9d1e76bb9ee1..6c8c55dec2bc 100644
--- a/fs/read_write.c
+++ b/fs/read_write.c
@@ -805,12 +805,6 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
805 goto out; 805 goto out;
806 if (!(in_file->f_mode & FMODE_READ)) 806 if (!(in_file->f_mode & FMODE_READ))
807 goto fput_in; 807 goto fput_in;
808 retval = -EINVAL;
809 in_inode = in_file->f_path.dentry->d_inode;
810 if (!in_inode)
811 goto fput_in;
812 if (!in_file->f_op || !in_file->f_op->splice_read)
813 goto fput_in;
814 retval = -ESPIPE; 808 retval = -ESPIPE;
815 if (!ppos) 809 if (!ppos)
816 ppos = &in_file->f_pos; 810 ppos = &in_file->f_pos;
@@ -834,6 +828,7 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos,
834 retval = -EINVAL; 828 retval = -EINVAL;
835 if (!out_file->f_op || !out_file->f_op->sendpage) 829 if (!out_file->f_op || !out_file->f_op->sendpage)
836 goto fput_out; 830 goto fput_out;
831 in_inode = in_file->f_path.dentry->d_inode;
837 out_inode = out_file->f_path.dentry->d_inode; 832 out_inode = out_file->f_path.dentry->d_inode;
838 retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count); 833 retval = rw_verify_area(WRITE, out_file, &out_file->f_pos, count);
839 if (retval < 0) 834 if (retval < 0)
diff --git a/fs/splice.c b/fs/splice.c
index e405cf552f5c..3bd9cb21b38e 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -507,9 +507,116 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos,
507 507
508 return ret; 508 return ret;
509} 509}
510
511EXPORT_SYMBOL(generic_file_splice_read); 510EXPORT_SYMBOL(generic_file_splice_read);
512 511
512static const struct pipe_buf_operations default_pipe_buf_ops = {
513 .can_merge = 0,
514 .map = generic_pipe_buf_map,
515 .unmap = generic_pipe_buf_unmap,
516 .confirm = generic_pipe_buf_confirm,
517 .release = generic_pipe_buf_release,
518 .steal = generic_pipe_buf_steal,
519 .get = generic_pipe_buf_get,
520};
521
522static ssize_t kernel_readv(struct file *file, const struct iovec *vec,
523 unsigned long vlen, loff_t offset)
524{
525 mm_segment_t old_fs;
526 loff_t pos = offset;
527 ssize_t res;
528
529 old_fs = get_fs();
530 set_fs(get_ds());
531 /* The cast to a user pointer is valid due to the set_fs() */
532 res = vfs_readv(file, (const struct iovec __user *)vec, vlen, &pos);
533 set_fs(old_fs);
534
535 return res;
536}
537
538ssize_t default_file_splice_read(struct file *in, loff_t *ppos,
539 struct pipe_inode_info *pipe, size_t len,
540 unsigned int flags)
541{
542 unsigned int nr_pages;
543 unsigned int nr_freed;
544 size_t offset;
545 struct page *pages[PIPE_BUFFERS];
546 struct partial_page partial[PIPE_BUFFERS];
547 struct iovec vec[PIPE_BUFFERS];
548 pgoff_t index;
549 ssize_t res;
550 size_t this_len;
551 int error;
552 int i;
553 struct splice_pipe_desc spd = {
554 .pages = pages,
555 .partial = partial,
556 .flags = flags,
557 .ops = &default_pipe_buf_ops,
558 .spd_release = spd_release_page,
559 };
560
561 index = *ppos >> PAGE_CACHE_SHIFT;
562 offset = *ppos & ~PAGE_CACHE_MASK;
563 nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
564
565 for (i = 0; i < nr_pages && i < PIPE_BUFFERS && len; i++) {
566 struct page *page;
567
568 page = alloc_page(GFP_HIGHUSER);
569 error = -ENOMEM;
570 if (!page)
571 goto err;
572
573 this_len = min_t(size_t, len, PAGE_CACHE_SIZE - offset);
574 vec[i].iov_base = (void __user *) kmap(page);
575 vec[i].iov_len = this_len;
576 pages[i] = page;
577 spd.nr_pages++;
578 len -= this_len;
579 offset = 0;
580 }
581
582 res = kernel_readv(in, vec, spd.nr_pages, *ppos);
583 if (res < 0)
584 goto err;
585
586 error = 0;
587 if (!res)
588 goto err;
589
590 nr_freed = 0;
591 for (i = 0; i < spd.nr_pages; i++) {
592 kunmap(pages[i]);
593 this_len = min_t(size_t, vec[i].iov_len, res);
594 partial[i].offset = 0;
595 partial[i].len = this_len;
596 if (!this_len) {
597 __free_page(pages[i]);
598 pages[i] = NULL;
599 nr_freed++;
600 }
601 res -= this_len;
602 }
603 spd.nr_pages -= nr_freed;
604
605 res = splice_to_pipe(pipe, &spd);
606 if (res > 0)
607 *ppos += res;
608
609 return res;
610
611err:
612 for (i = 0; i < spd.nr_pages; i++) {
613 kunmap(pages[i]);
614 __free_page(pages[i]);
615 }
616 return error;
617}
618EXPORT_SYMBOL(default_file_splice_read);
619
513/* 620/*
514 * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' 621 * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
515 * using sendpage(). Return the number of bytes sent. 622 * using sendpage(). Return the number of bytes sent.
@@ -933,11 +1040,10 @@ static long do_splice_to(struct file *in, loff_t *ppos,
933 struct pipe_inode_info *pipe, size_t len, 1040 struct pipe_inode_info *pipe, size_t len,
934 unsigned int flags) 1041 unsigned int flags)
935{ 1042{
1043 ssize_t (*splice_read)(struct file *, loff_t *,
1044 struct pipe_inode_info *, size_t, unsigned int);
936 int ret; 1045 int ret;
937 1046
938 if (unlikely(!in->f_op || !in->f_op->splice_read))
939 return -EINVAL;
940
941 if (unlikely(!(in->f_mode & FMODE_READ))) 1047 if (unlikely(!(in->f_mode & FMODE_READ)))
942 return -EBADF; 1048 return -EBADF;
943 1049
@@ -945,7 +1051,11 @@ static long do_splice_to(struct file *in, loff_t *ppos,
945 if (unlikely(ret < 0)) 1051 if (unlikely(ret < 0))
946 return ret; 1052 return ret;
947 1053
948 return in->f_op->splice_read(in, ppos, pipe, len, flags); 1054 splice_read = in->f_op->splice_read;
1055 if (!splice_read)
1056 splice_read = default_file_splice_read;
1057
1058 return splice_read(in, ppos, pipe, len, flags);
949} 1059}
950 1060
951/** 1061/**
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 5bed436f4353..d926c2bea166 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -2204,6 +2204,8 @@ extern int generic_segment_checks(const struct iovec *iov,
2204/* fs/splice.c */ 2204/* fs/splice.c */
2205extern ssize_t generic_file_splice_read(struct file *, loff_t *, 2205extern ssize_t generic_file_splice_read(struct file *, loff_t *,
2206 struct pipe_inode_info *, size_t, unsigned int); 2206 struct pipe_inode_info *, size_t, unsigned int);
2207extern ssize_t default_file_splice_read(struct file *, loff_t *,
2208 struct pipe_inode_info *, size_t, unsigned int);
2207extern ssize_t generic_file_splice_write(struct pipe_inode_info *, 2209extern ssize_t generic_file_splice_write(struct pipe_inode_info *,
2208 struct file *, loff_t *, size_t, unsigned int); 2210 struct file *, loff_t *, size_t, unsigned int);
2209extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, 2211extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe,
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h
index c8f038554e80..b43a9e039059 100644
--- a/include/linux/pipe_fs_i.h
+++ b/include/linux/pipe_fs_i.h
@@ -152,5 +152,6 @@ void generic_pipe_buf_unmap(struct pipe_inode_info *, struct pipe_buffer *, void
152void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *); 152void generic_pipe_buf_get(struct pipe_inode_info *, struct pipe_buffer *);
153int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *); 153int generic_pipe_buf_confirm(struct pipe_inode_info *, struct pipe_buffer *);
154int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *); 154int generic_pipe_buf_steal(struct pipe_inode_info *, struct pipe_buffer *);
155void generic_pipe_buf_release(struct pipe_inode_info *, struct pipe_buffer *);
155 156
156#endif 157#endif