aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2006-04-10 09:18:58 -0400
committerJens Axboe <axboe@suse.de>2006-04-10 09:18:58 -0400
commit529565dcb1581c9a1e3f6df1c1763ca3e0f0d512 (patch)
treee8069cc17f887ad86f8dee0d96640a2f19bf4112 /fs/splice.c
parent3a326a2ce88e71d00ac0d133e314a3342a7709f8 (diff)
[PATCH] splice: add optional input and output offsets
add optional input and output offsets to sys_splice(), for seekable file descriptors: asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, int fd_out, loff_t __user *off_out, size_t len, unsigned int flags); semantics are straightforward: f_pos will be updated with the offset provided by user-space, before the splice transfer is about to begin. Providing a NULL offset pointer means the existing f_pos will be used (and updated in situ). Providing an offset for a pipe results in -ESPIPE. Providing an invalid offset pointer results in -EFAULT. Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c54
1 files changed, 41 insertions, 13 deletions
diff --git a/fs/splice.c b/fs/splice.c
index ed91a62402e0..a5326127aad5 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -680,7 +680,8 @@ EXPORT_SYMBOL(generic_splice_sendpage);
680 * Attempt to initiate a splice from pipe to file. 680 * Attempt to initiate a splice from pipe to file.
681 */ 681 */
682static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, 682static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
683 size_t len, unsigned int flags) 683 loff_t __user *off_out, size_t len,
684 unsigned int flags)
684{ 685{
685 loff_t pos; 686 loff_t pos;
686 int ret; 687 int ret;
@@ -691,7 +692,11 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
691 if (!(out->f_mode & FMODE_WRITE)) 692 if (!(out->f_mode & FMODE_WRITE))
692 return -EBADF; 693 return -EBADF;
693 694
695 if (off_out && copy_from_user(&out->f_pos, off_out, sizeof(loff_t)))
696 return -EFAULT;
697
694 pos = out->f_pos; 698 pos = out->f_pos;
699
695 ret = rw_verify_area(WRITE, out, &pos, len); 700 ret = rw_verify_area(WRITE, out, &pos, len);
696 if (unlikely(ret < 0)) 701 if (unlikely(ret < 0))
697 return ret; 702 return ret;
@@ -702,8 +707,9 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out,
702/* 707/*
703 * Attempt to initiate a splice from a file to a pipe. 708 * Attempt to initiate a splice from a file to a pipe.
704 */ 709 */
705static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, 710static long do_splice_to(struct file *in, loff_t __user *off_in,
706 size_t len, unsigned int flags) 711 struct pipe_inode_info *pipe, size_t len,
712 unsigned int flags)
707{ 713{
708 loff_t pos, isize, left; 714 loff_t pos, isize, left;
709 int ret; 715 int ret;
@@ -714,7 +720,11 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
714 if (!(in->f_mode & FMODE_READ)) 720 if (!(in->f_mode & FMODE_READ))
715 return -EBADF; 721 return -EBADF;
716 722
723 if (off_in && copy_from_user(&in->f_pos, off_in, sizeof(loff_t)))
724 return -EFAULT;
725
717 pos = in->f_pos; 726 pos = in->f_pos;
727
718 ret = rw_verify_area(READ, in, &pos, len); 728 ret = rw_verify_area(READ, in, &pos, len);
719 if (unlikely(ret < 0)) 729 if (unlikely(ret < 0))
720 return ret; 730 return ret;
@@ -733,23 +743,39 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe,
733/* 743/*
734 * Determine where to splice to/from. 744 * Determine where to splice to/from.
735 */ 745 */
736static long do_splice(struct file *in, struct file *out, size_t len, 746static long do_splice(struct file *in, loff_t __user *off_in,
737 unsigned int flags) 747 struct file *out, loff_t __user *off_out,
748 size_t len, unsigned int flags)
738{ 749{
739 struct pipe_inode_info *pipe; 750 struct pipe_inode_info *pipe;
740 751
752 if (off_out && out->f_op->llseek == no_llseek)
753 return -EINVAL;
754 if (off_in && in->f_op->llseek == no_llseek)
755 return -EINVAL;
756
741 pipe = in->f_dentry->d_inode->i_pipe; 757 pipe = in->f_dentry->d_inode->i_pipe;
742 if (pipe) 758 if (pipe) {
743 return do_splice_from(pipe, out, len, flags); 759 if (off_in)
760 return -ESPIPE;
761
762 return do_splice_from(pipe, out, off_out, len, flags);
763 }
744 764
745 pipe = out->f_dentry->d_inode->i_pipe; 765 pipe = out->f_dentry->d_inode->i_pipe;
746 if (pipe) 766 if (pipe) {
747 return do_splice_to(in, pipe, len, flags); 767 if (off_out)
768 return -ESPIPE;
769
770 return do_splice_to(in, off_in, pipe, len, flags);
771 }
748 772
749 return -EINVAL; 773 return -EINVAL;
750} 774}
751 775
752asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags) 776asmlinkage long sys_splice(int fd_in, loff_t __user *off_in,
777 int fd_out, loff_t __user *off_out,
778 size_t len, unsigned int flags)
753{ 779{
754 long error; 780 long error;
755 struct file *in, *out; 781 struct file *in, *out;
@@ -759,13 +785,15 @@ asmlinkage long sys_splice(int fdin, int fdout, size_t len, unsigned int flags)
759 return 0; 785 return 0;
760 786
761 error = -EBADF; 787 error = -EBADF;
762 in = fget_light(fdin, &fput_in); 788 in = fget_light(fd_in, &fput_in);
763 if (in) { 789 if (in) {
764 if (in->f_mode & FMODE_READ) { 790 if (in->f_mode & FMODE_READ) {
765 out = fget_light(fdout, &fput_out); 791 out = fget_light(fd_out, &fput_out);
766 if (out) { 792 if (out) {
767 if (out->f_mode & FMODE_WRITE) 793 if (out->f_mode & FMODE_WRITE)
768 error = do_splice(in, out, len, flags); 794 error = do_splice(in, off_in,
795 out, off_out,
796 len, flags);
769 fput_light(out, fput_out); 797 fput_light(out, fput_out);
770 } 798 }
771 } 799 }