diff options
-rw-r--r-- | arch/i386/kernel/syscall_table.S | 1 | ||||
-rw-r--r-- | arch/ia64/kernel/entry.S | 1 | ||||
-rw-r--r-- | arch/powerpc/kernel/systbl.S | 1 | ||||
-rw-r--r-- | fs/pipe.c | 7 | ||||
-rw-r--r-- | fs/splice.c | 272 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_file.c | 12 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.c | 14 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_lrw.h | 4 | ||||
-rw-r--r-- | fs/xfs/linux-2.6/xfs_vnode.h | 12 | ||||
-rw-r--r-- | include/asm-i386/unistd.h | 3 | ||||
-rw-r--r-- | include/asm-ia64/unistd.h | 3 | ||||
-rw-r--r-- | include/asm-powerpc/unistd.h | 3 | ||||
-rw-r--r-- | include/asm-x86_64/unistd.h | 4 | ||||
-rw-r--r-- | include/linux/fs.h | 12 | ||||
-rw-r--r-- | include/linux/pipe_fs_i.h | 1 | ||||
-rw-r--r-- | include/linux/syscalls.h | 2 |
16 files changed, 282 insertions, 70 deletions
diff --git a/arch/i386/kernel/syscall_table.S b/arch/i386/kernel/syscall_table.S index 4f58b9c0efe3..f48bef15b4f0 100644 --- a/arch/i386/kernel/syscall_table.S +++ b/arch/i386/kernel/syscall_table.S | |||
@@ -314,3 +314,4 @@ ENTRY(sys_call_table) | |||
314 | .long sys_get_robust_list | 314 | .long sys_get_robust_list |
315 | .long sys_splice | 315 | .long sys_splice |
316 | .long sys_sync_file_range | 316 | .long sys_sync_file_range |
317 | .long sys_tee /* 315 */ | ||
diff --git a/arch/ia64/kernel/entry.S b/arch/ia64/kernel/entry.S index 6e16f6b35bd3..e30798811216 100644 --- a/arch/ia64/kernel/entry.S +++ b/arch/ia64/kernel/entry.S | |||
@@ -1609,5 +1609,6 @@ sys_call_table: | |||
1609 | data8 sys_set_robust_list | 1609 | data8 sys_set_robust_list |
1610 | data8 sys_get_robust_list | 1610 | data8 sys_get_robust_list |
1611 | data8 sys_sync_file_range // 1300 | 1611 | data8 sys_sync_file_range // 1300 |
1612 | data8 sys_tee | ||
1612 | 1613 | ||
1613 | .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls | 1614 | .org sys_call_table + 8*NR_syscalls // guard against failures to increase NR_syscalls |
diff --git a/arch/powerpc/kernel/systbl.S b/arch/powerpc/kernel/systbl.S index 1424eab450ee..a14c96403840 100644 --- a/arch/powerpc/kernel/systbl.S +++ b/arch/powerpc/kernel/systbl.S | |||
@@ -323,3 +323,4 @@ COMPAT_SYS(pselect6) | |||
323 | COMPAT_SYS(ppoll) | 323 | COMPAT_SYS(ppoll) |
324 | SYSCALL(unshare) | 324 | SYSCALL(unshare) |
325 | SYSCALL(splice) | 325 | SYSCALL(splice) |
326 | SYSCALL(tee) | ||
@@ -131,12 +131,19 @@ static int anon_pipe_buf_steal(struct pipe_inode_info *pipe, | |||
131 | return 0; | 131 | return 0; |
132 | } | 132 | } |
133 | 133 | ||
134 | static void anon_pipe_buf_get(struct pipe_inode_info *info, | ||
135 | struct pipe_buffer *buf) | ||
136 | { | ||
137 | page_cache_get(buf->page); | ||
138 | } | ||
139 | |||
134 | static struct pipe_buf_operations anon_pipe_buf_ops = { | 140 | static struct pipe_buf_operations anon_pipe_buf_ops = { |
135 | .can_merge = 1, | 141 | .can_merge = 1, |
136 | .map = anon_pipe_buf_map, | 142 | .map = anon_pipe_buf_map, |
137 | .unmap = anon_pipe_buf_unmap, | 143 | .unmap = anon_pipe_buf_unmap, |
138 | .release = anon_pipe_buf_release, | 144 | .release = anon_pipe_buf_release, |
139 | .steal = anon_pipe_buf_steal, | 145 | .steal = anon_pipe_buf_steal, |
146 | .get = anon_pipe_buf_get, | ||
140 | }; | 147 | }; |
141 | 148 | ||
142 | static ssize_t | 149 | static ssize_t |
diff --git a/fs/splice.c b/fs/splice.c index e50a460239dd..8d57e89924a6 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -125,12 +125,19 @@ static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, | |||
125 | kunmap(buf->page); | 125 | kunmap(buf->page); |
126 | } | 126 | } |
127 | 127 | ||
128 | static void page_cache_pipe_buf_get(struct pipe_inode_info *info, | ||
129 | struct pipe_buffer *buf) | ||
130 | { | ||
131 | page_cache_get(buf->page); | ||
132 | } | ||
133 | |||
128 | static struct pipe_buf_operations page_cache_pipe_buf_ops = { | 134 | static struct pipe_buf_operations page_cache_pipe_buf_ops = { |
129 | .can_merge = 0, | 135 | .can_merge = 0, |
130 | .map = page_cache_pipe_buf_map, | 136 | .map = page_cache_pipe_buf_map, |
131 | .unmap = page_cache_pipe_buf_unmap, | 137 | .unmap = page_cache_pipe_buf_unmap, |
132 | .release = page_cache_pipe_buf_release, | 138 | .release = page_cache_pipe_buf_release, |
133 | .steal = page_cache_pipe_buf_steal, | 139 | .steal = page_cache_pipe_buf_steal, |
140 | .get = page_cache_pipe_buf_get, | ||
134 | }; | 141 | }; |
135 | 142 | ||
136 | /* | 143 | /* |
@@ -231,8 +238,9 @@ static ssize_t move_to_pipe(struct pipe_inode_info *pipe, struct page **pages, | |||
231 | } | 238 | } |
232 | 239 | ||
233 | static int | 240 | static int |
234 | __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | 241 | __generic_file_splice_read(struct file *in, loff_t *ppos, |
235 | size_t len, unsigned int flags) | 242 | struct pipe_inode_info *pipe, size_t len, |
243 | unsigned int flags) | ||
236 | { | 244 | { |
237 | struct address_space *mapping = in->f_mapping; | 245 | struct address_space *mapping = in->f_mapping; |
238 | unsigned int offset, nr_pages; | 246 | unsigned int offset, nr_pages; |
@@ -241,8 +249,8 @@ __generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | |||
241 | pgoff_t index; | 249 | pgoff_t index; |
242 | int i, error; | 250 | int i, error; |
243 | 251 | ||
244 | index = in->f_pos >> PAGE_CACHE_SHIFT; | 252 | index = *ppos >> PAGE_CACHE_SHIFT; |
245 | offset = in->f_pos & ~PAGE_CACHE_MASK; | 253 | offset = *ppos & ~PAGE_CACHE_MASK; |
246 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; | 254 | nr_pages = (len + offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; |
247 | 255 | ||
248 | if (nr_pages > PIPE_BUFFERS) | 256 | if (nr_pages > PIPE_BUFFERS) |
@@ -348,8 +356,9 @@ fill_it: | |||
348 | * | 356 | * |
349 | * Will read pages from given file and fill them into a pipe. | 357 | * Will read pages from given file and fill them into a pipe. |
350 | */ | 358 | */ |
351 | ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | 359 | ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, |
352 | size_t len, unsigned int flags) | 360 | struct pipe_inode_info *pipe, size_t len, |
361 | unsigned int flags) | ||
353 | { | 362 | { |
354 | ssize_t spliced; | 363 | ssize_t spliced; |
355 | int ret; | 364 | int ret; |
@@ -358,12 +367,12 @@ ssize_t generic_file_splice_read(struct file *in, struct pipe_inode_info *pipe, | |||
358 | spliced = 0; | 367 | spliced = 0; |
359 | 368 | ||
360 | while (len) { | 369 | while (len) { |
361 | ret = __generic_file_splice_read(in, pipe, len, flags); | 370 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
362 | 371 | ||
363 | if (ret <= 0) | 372 | if (ret <= 0) |
364 | break; | 373 | break; |
365 | 374 | ||
366 | in->f_pos += ret; | 375 | *ppos += ret; |
367 | len -= ret; | 376 | len -= ret; |
368 | spliced += ret; | 377 | spliced += ret; |
369 | 378 | ||
@@ -561,7 +570,7 @@ typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, | |||
561 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. | 570 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. |
562 | */ | 571 | */ |
563 | static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | 572 | static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, |
564 | size_t len, unsigned int flags, | 573 | loff_t *ppos, size_t len, unsigned int flags, |
565 | splice_actor *actor) | 574 | splice_actor *actor) |
566 | { | 575 | { |
567 | int ret, do_wakeup, err; | 576 | int ret, do_wakeup, err; |
@@ -573,7 +582,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
573 | sd.total_len = len; | 582 | sd.total_len = len; |
574 | sd.flags = flags; | 583 | sd.flags = flags; |
575 | sd.file = out; | 584 | sd.file = out; |
576 | sd.pos = out->f_pos; | 585 | sd.pos = *ppos; |
577 | 586 | ||
578 | if (pipe->inode) | 587 | if (pipe->inode) |
579 | mutex_lock(&pipe->inode->i_mutex); | 588 | mutex_lock(&pipe->inode->i_mutex); |
@@ -656,9 +665,7 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
656 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); | 665 | kill_fasync(&pipe->fasync_writers, SIGIO, POLL_OUT); |
657 | } | 666 | } |
658 | 667 | ||
659 | out->f_pos = sd.pos; | ||
660 | return ret; | 668 | return ret; |
661 | |||
662 | } | 669 | } |
663 | 670 | ||
664 | /** | 671 | /** |
@@ -674,12 +681,12 @@ static ssize_t move_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
674 | */ | 681 | */ |
675 | ssize_t | 682 | ssize_t |
676 | generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, | 683 | generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, |
677 | size_t len, unsigned int flags) | 684 | loff_t *ppos, size_t len, unsigned int flags) |
678 | { | 685 | { |
679 | struct address_space *mapping = out->f_mapping; | 686 | struct address_space *mapping = out->f_mapping; |
680 | ssize_t ret; | 687 | ssize_t ret; |
681 | 688 | ||
682 | ret = move_from_pipe(pipe, out, len, flags, pipe_to_file); | 689 | ret = move_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); |
683 | 690 | ||
684 | /* | 691 | /* |
685 | * If file or inode is SYNC and we actually wrote some data, sync it. | 692 | * If file or inode is SYNC and we actually wrote some data, sync it. |
@@ -715,9 +722,9 @@ EXPORT_SYMBOL(generic_file_splice_write); | |||
715 | * | 722 | * |
716 | */ | 723 | */ |
717 | ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, | 724 | ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, struct file *out, |
718 | size_t len, unsigned int flags) | 725 | loff_t *ppos, size_t len, unsigned int flags) |
719 | { | 726 | { |
720 | return move_from_pipe(pipe, out, len, flags, pipe_to_sendpage); | 727 | return move_from_pipe(pipe, out, ppos, len, flags, pipe_to_sendpage); |
721 | } | 728 | } |
722 | 729 | ||
723 | EXPORT_SYMBOL(generic_splice_sendpage); | 730 | EXPORT_SYMBOL(generic_splice_sendpage); |
@@ -726,9 +733,8 @@ EXPORT_SYMBOL(generic_splice_sendpage); | |||
726 | * Attempt to initiate a splice from pipe to file. | 733 | * Attempt to initiate a splice from pipe to file. |
727 | */ | 734 | */ |
728 | static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | 735 | static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, |
729 | size_t len, unsigned int flags) | 736 | loff_t *ppos, size_t len, unsigned int flags) |
730 | { | 737 | { |
731 | loff_t pos; | ||
732 | int ret; | 738 | int ret; |
733 | 739 | ||
734 | if (unlikely(!out->f_op || !out->f_op->splice_write)) | 740 | if (unlikely(!out->f_op || !out->f_op->splice_write)) |
@@ -737,22 +743,21 @@ static long do_splice_from(struct pipe_inode_info *pipe, struct file *out, | |||
737 | if (unlikely(!(out->f_mode & FMODE_WRITE))) | 743 | if (unlikely(!(out->f_mode & FMODE_WRITE))) |
738 | return -EBADF; | 744 | return -EBADF; |
739 | 745 | ||
740 | pos = out->f_pos; | 746 | ret = rw_verify_area(WRITE, out, ppos, len); |
741 | |||
742 | ret = rw_verify_area(WRITE, out, &pos, len); | ||
743 | if (unlikely(ret < 0)) | 747 | if (unlikely(ret < 0)) |
744 | return ret; | 748 | return ret; |
745 | 749 | ||
746 | return out->f_op->splice_write(pipe, out, len, flags); | 750 | return out->f_op->splice_write(pipe, out, ppos, len, flags); |
747 | } | 751 | } |
748 | 752 | ||
749 | /* | 753 | /* |
750 | * Attempt to initiate a splice from a file to a pipe. | 754 | * Attempt to initiate a splice from a file to a pipe. |
751 | */ | 755 | */ |
752 | static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, | 756 | static long do_splice_to(struct file *in, loff_t *ppos, |
753 | size_t len, unsigned int flags) | 757 | struct pipe_inode_info *pipe, size_t len, |
758 | unsigned int flags) | ||
754 | { | 759 | { |
755 | loff_t pos, isize, left; | 760 | loff_t isize, left; |
756 | int ret; | 761 | int ret; |
757 | 762 | ||
758 | if (unlikely(!in->f_op || !in->f_op->splice_read)) | 763 | if (unlikely(!in->f_op || !in->f_op->splice_read)) |
@@ -761,28 +766,27 @@ static long do_splice_to(struct file *in, struct pipe_inode_info *pipe, | |||
761 | if (unlikely(!(in->f_mode & FMODE_READ))) | 766 | if (unlikely(!(in->f_mode & FMODE_READ))) |
762 | return -EBADF; | 767 | return -EBADF; |
763 | 768 | ||
764 | pos = in->f_pos; | 769 | ret = rw_verify_area(READ, in, ppos, len); |
765 | |||
766 | ret = rw_verify_area(READ, in, &pos, len); | ||
767 | if (unlikely(ret < 0)) | 770 | if (unlikely(ret < 0)) |
768 | return ret; | 771 | return ret; |
769 | 772 | ||
770 | isize = i_size_read(in->f_mapping->host); | 773 | isize = i_size_read(in->f_mapping->host); |
771 | if (unlikely(in->f_pos >= isize)) | 774 | if (unlikely(*ppos >= isize)) |
772 | return 0; | 775 | return 0; |
773 | 776 | ||
774 | left = isize - in->f_pos; | 777 | left = isize - *ppos; |
775 | if (unlikely(left < len)) | 778 | if (unlikely(left < len)) |
776 | len = left; | 779 | len = left; |
777 | 780 | ||
778 | return in->f_op->splice_read(in, pipe, len, flags); | 781 | return in->f_op->splice_read(in, ppos, pipe, len, flags); |
779 | } | 782 | } |
780 | 783 | ||
781 | long do_splice_direct(struct file *in, struct file *out, size_t len, | 784 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, |
782 | unsigned int flags) | 785 | size_t len, unsigned int flags) |
783 | { | 786 | { |
784 | struct pipe_inode_info *pipe; | 787 | struct pipe_inode_info *pipe; |
785 | long ret, bytes; | 788 | long ret, bytes; |
789 | loff_t out_off; | ||
786 | umode_t i_mode; | 790 | umode_t i_mode; |
787 | int i; | 791 | int i; |
788 | 792 | ||
@@ -820,6 +824,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
820 | */ | 824 | */ |
821 | ret = 0; | 825 | ret = 0; |
822 | bytes = 0; | 826 | bytes = 0; |
827 | out_off = 0; | ||
823 | 828 | ||
824 | while (len) { | 829 | while (len) { |
825 | size_t read_len, max_read_len; | 830 | size_t read_len, max_read_len; |
@@ -829,7 +834,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
829 | */ | 834 | */ |
830 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); | 835 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); |
831 | 836 | ||
832 | ret = do_splice_to(in, pipe, max_read_len, flags); | 837 | ret = do_splice_to(in, ppos, pipe, max_read_len, flags); |
833 | if (unlikely(ret < 0)) | 838 | if (unlikely(ret < 0)) |
834 | goto out_release; | 839 | goto out_release; |
835 | 840 | ||
@@ -840,7 +845,7 @@ long do_splice_direct(struct file *in, struct file *out, size_t len, | |||
840 | * must not do the output in nonblocking mode as then we | 845 | * must not do the output in nonblocking mode as then we |
841 | * could get stuck data in the internal pipe: | 846 | * could get stuck data in the internal pipe: |
842 | */ | 847 | */ |
843 | ret = do_splice_from(pipe, out, read_len, | 848 | ret = do_splice_from(pipe, out, &out_off, read_len, |
844 | flags & ~SPLICE_F_NONBLOCK); | 849 | flags & ~SPLICE_F_NONBLOCK); |
845 | if (unlikely(ret < 0)) | 850 | if (unlikely(ret < 0)) |
846 | goto out_release; | 851 | goto out_release; |
@@ -898,6 +903,7 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
898 | size_t len, unsigned int flags) | 903 | size_t len, unsigned int flags) |
899 | { | 904 | { |
900 | struct pipe_inode_info *pipe; | 905 | struct pipe_inode_info *pipe; |
906 | loff_t offset, *off; | ||
901 | 907 | ||
902 | pipe = in->f_dentry->d_inode->i_pipe; | 908 | pipe = in->f_dentry->d_inode->i_pipe; |
903 | if (pipe) { | 909 | if (pipe) { |
@@ -906,12 +912,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
906 | if (off_out) { | 912 | if (off_out) { |
907 | if (out->f_op->llseek == no_llseek) | 913 | if (out->f_op->llseek == no_llseek) |
908 | return -EINVAL; | 914 | return -EINVAL; |
909 | if (copy_from_user(&out->f_pos, off_out, | 915 | if (copy_from_user(&offset, off_out, sizeof(loff_t))) |
910 | sizeof(loff_t))) | ||
911 | return -EFAULT; | 916 | return -EFAULT; |
912 | } | 917 | off = &offset; |
918 | } else | ||
919 | off = &out->f_pos; | ||
913 | 920 | ||
914 | return do_splice_from(pipe, out, len, flags); | 921 | return do_splice_from(pipe, out, off, len, flags); |
915 | } | 922 | } |
916 | 923 | ||
917 | pipe = out->f_dentry->d_inode->i_pipe; | 924 | pipe = out->f_dentry->d_inode->i_pipe; |
@@ -921,11 +928,13 @@ static long do_splice(struct file *in, loff_t __user *off_in, | |||
921 | if (off_in) { | 928 | if (off_in) { |
922 | if (in->f_op->llseek == no_llseek) | 929 | if (in->f_op->llseek == no_llseek) |
923 | return -EINVAL; | 930 | return -EINVAL; |
924 | if (copy_from_user(&in->f_pos, off_in, sizeof(loff_t))) | 931 | if (copy_from_user(&offset, off_in, sizeof(loff_t))) |
925 | return -EFAULT; | 932 | return -EFAULT; |
926 | } | 933 | off = &offset; |
934 | } else | ||
935 | off = &in->f_pos; | ||
927 | 936 | ||
928 | return do_splice_to(in, pipe, len, flags); | 937 | return do_splice_to(in, off, pipe, len, flags); |
929 | } | 938 | } |
930 | 939 | ||
931 | return -EINVAL; | 940 | return -EINVAL; |
@@ -961,3 +970,182 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, | |||
961 | 970 | ||
962 | return error; | 971 | return error; |
963 | } | 972 | } |
973 | |||
974 | /* | ||
975 | * Link contents of ipipe to opipe. | ||
976 | */ | ||
977 | static int link_pipe(struct pipe_inode_info *ipipe, | ||
978 | struct pipe_inode_info *opipe, | ||
979 | size_t len, unsigned int flags) | ||
980 | { | ||
981 | struct pipe_buffer *ibuf, *obuf; | ||
982 | int ret = 0, do_wakeup = 0, i; | ||
983 | |||
984 | /* | ||
985 | * Potential ABBA deadlock, work around it by ordering lock | ||
986 | * grabbing by inode address. Otherwise two different processes | ||
987 | * could deadlock (one doing tee from A -> B, the other from B -> A). | ||
988 | */ | ||
989 | if (ipipe->inode < opipe->inode) { | ||
990 | mutex_lock(&ipipe->inode->i_mutex); | ||
991 | mutex_lock(&opipe->inode->i_mutex); | ||
992 | } else { | ||
993 | mutex_lock(&opipe->inode->i_mutex); | ||
994 | mutex_lock(&ipipe->inode->i_mutex); | ||
995 | } | ||
996 | |||
997 | for (i = 0;; i++) { | ||
998 | if (!opipe->readers) { | ||
999 | send_sig(SIGPIPE, current, 0); | ||
1000 | if (!ret) | ||
1001 | ret = -EPIPE; | ||
1002 | break; | ||
1003 | } | ||
1004 | if (ipipe->nrbufs - i) { | ||
1005 | ibuf = ipipe->bufs + ((ipipe->curbuf + i) & (PIPE_BUFFERS - 1)); | ||
1006 | |||
1007 | /* | ||
1008 | * If we have room, fill this buffer | ||
1009 | */ | ||
1010 | if (opipe->nrbufs < PIPE_BUFFERS) { | ||
1011 | int nbuf = (opipe->curbuf + opipe->nrbufs) & (PIPE_BUFFERS - 1); | ||
1012 | |||
1013 | /* | ||
1014 | * Get a reference to this pipe buffer, | ||
1015 | * so we can copy the contents over. | ||
1016 | */ | ||
1017 | ibuf->ops->get(ipipe, ibuf); | ||
1018 | |||
1019 | obuf = opipe->bufs + nbuf; | ||
1020 | *obuf = *ibuf; | ||
1021 | |||
1022 | if (obuf->len > len) | ||
1023 | obuf->len = len; | ||
1024 | |||
1025 | opipe->nrbufs++; | ||
1026 | do_wakeup = 1; | ||
1027 | ret += obuf->len; | ||
1028 | len -= obuf->len; | ||
1029 | |||
1030 | if (!len) | ||
1031 | break; | ||
1032 | if (opipe->nrbufs < PIPE_BUFFERS) | ||
1033 | continue; | ||
1034 | } | ||
1035 | |||
1036 | /* | ||
1037 | * We have input available, but no output room. | ||
1038 | * If we already copied data, return that. | ||
1039 | */ | ||
1040 | if (flags & SPLICE_F_NONBLOCK) { | ||
1041 | if (!ret) | ||
1042 | ret = -EAGAIN; | ||
1043 | break; | ||
1044 | } | ||
1045 | if (signal_pending(current)) { | ||
1046 | if (!ret) | ||
1047 | ret = -ERESTARTSYS; | ||
1048 | break; | ||
1049 | } | ||
1050 | if (do_wakeup) { | ||
1051 | smp_mb(); | ||
1052 | if (waitqueue_active(&opipe->wait)) | ||
1053 | wake_up_interruptible(&opipe->wait); | ||
1054 | kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); | ||
1055 | do_wakeup = 0; | ||
1056 | } | ||
1057 | |||
1058 | opipe->waiting_writers++; | ||
1059 | pipe_wait(opipe); | ||
1060 | opipe->waiting_writers--; | ||
1061 | continue; | ||
1062 | } | ||
1063 | |||
1064 | /* | ||
1065 | * No input buffers, do the usual checks for available | ||
1066 | * writers and blocking and wait if necessary | ||
1067 | */ | ||
1068 | if (!ipipe->writers) | ||
1069 | break; | ||
1070 | if (!ipipe->waiting_writers) { | ||
1071 | if (ret) | ||
1072 | break; | ||
1073 | } | ||
1074 | if (flags & SPLICE_F_NONBLOCK) { | ||
1075 | if (!ret) | ||
1076 | ret = -EAGAIN; | ||
1077 | break; | ||
1078 | } | ||
1079 | if (signal_pending(current)) { | ||
1080 | if (!ret) | ||
1081 | ret = -ERESTARTSYS; | ||
1082 | break; | ||
1083 | } | ||
1084 | |||
1085 | if (waitqueue_active(&ipipe->wait)) | ||
1086 | wake_up_interruptible_sync(&ipipe->wait); | ||
1087 | kill_fasync(&ipipe->fasync_writers, SIGIO, POLL_OUT); | ||
1088 | |||
1089 | pipe_wait(ipipe); | ||
1090 | } | ||
1091 | |||
1092 | mutex_unlock(&ipipe->inode->i_mutex); | ||
1093 | mutex_unlock(&opipe->inode->i_mutex); | ||
1094 | |||
1095 | if (do_wakeup) { | ||
1096 | smp_mb(); | ||
1097 | if (waitqueue_active(&opipe->wait)) | ||
1098 | wake_up_interruptible(&opipe->wait); | ||
1099 | kill_fasync(&opipe->fasync_readers, SIGIO, POLL_IN); | ||
1100 | } | ||
1101 | |||
1102 | return ret; | ||
1103 | } | ||
1104 | |||
1105 | /* | ||
1106 | * This is a tee(1) implementation that works on pipes. It doesn't copy | ||
1107 | * any data, it simply references the 'in' pages on the 'out' pipe. | ||
1108 | * The 'flags' used are the SPLICE_F_* variants, currently the only | ||
1109 | * applicable one is SPLICE_F_NONBLOCK. | ||
1110 | */ | ||
1111 | static long do_tee(struct file *in, struct file *out, size_t len, | ||
1112 | unsigned int flags) | ||
1113 | { | ||
1114 | struct pipe_inode_info *ipipe = in->f_dentry->d_inode->i_pipe; | ||
1115 | struct pipe_inode_info *opipe = out->f_dentry->d_inode->i_pipe; | ||
1116 | |||
1117 | /* | ||
1118 | * Link ipipe to the two output pipes, consuming as we go along. | ||
1119 | */ | ||
1120 | if (ipipe && opipe) | ||
1121 | return link_pipe(ipipe, opipe, len, flags); | ||
1122 | |||
1123 | return -EINVAL; | ||
1124 | } | ||
1125 | |||
1126 | asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags) | ||
1127 | { | ||
1128 | struct file *in; | ||
1129 | int error, fput_in; | ||
1130 | |||
1131 | if (unlikely(!len)) | ||
1132 | return 0; | ||
1133 | |||
1134 | error = -EBADF; | ||
1135 | in = fget_light(fdin, &fput_in); | ||
1136 | if (in) { | ||
1137 | if (in->f_mode & FMODE_READ) { | ||
1138 | int fput_out; | ||
1139 | struct file *out = fget_light(fdout, &fput_out); | ||
1140 | |||
1141 | if (out) { | ||
1142 | if (out->f_mode & FMODE_WRITE) | ||
1143 | error = do_tee(in, out, len, flags); | ||
1144 | fput_light(out, fput_out); | ||
1145 | } | ||
1146 | } | ||
1147 | fput_light(in, fput_in); | ||
1148 | } | ||
1149 | |||
1150 | return error; | ||
1151 | } | ||
diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index 269721af02f3..c847416f6d10 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c | |||
@@ -252,6 +252,7 @@ xfs_file_sendfile_invis( | |||
252 | STATIC ssize_t | 252 | STATIC ssize_t |
253 | xfs_file_splice_read( | 253 | xfs_file_splice_read( |
254 | struct file *infilp, | 254 | struct file *infilp, |
255 | loff_t *ppos, | ||
255 | struct pipe_inode_info *pipe, | 256 | struct pipe_inode_info *pipe, |
256 | size_t len, | 257 | size_t len, |
257 | unsigned int flags) | 258 | unsigned int flags) |
@@ -259,13 +260,14 @@ xfs_file_splice_read( | |||
259 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 260 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); |
260 | ssize_t rval; | 261 | ssize_t rval; |
261 | 262 | ||
262 | VOP_SPLICE_READ(vp, infilp, pipe, len, flags, 0, NULL, rval); | 263 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, 0, NULL, rval); |
263 | return rval; | 264 | return rval; |
264 | } | 265 | } |
265 | 266 | ||
266 | STATIC ssize_t | 267 | STATIC ssize_t |
267 | xfs_file_splice_read_invis( | 268 | xfs_file_splice_read_invis( |
268 | struct file *infilp, | 269 | struct file *infilp, |
270 | loff_t *ppos, | ||
269 | struct pipe_inode_info *pipe, | 271 | struct pipe_inode_info *pipe, |
270 | size_t len, | 272 | size_t len, |
271 | unsigned int flags) | 273 | unsigned int flags) |
@@ -273,7 +275,7 @@ xfs_file_splice_read_invis( | |||
273 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); | 275 | vnode_t *vp = vn_from_inode(infilp->f_dentry->d_inode); |
274 | ssize_t rval; | 276 | ssize_t rval; |
275 | 277 | ||
276 | VOP_SPLICE_READ(vp, infilp, pipe, len, flags, IO_INVIS, NULL, rval); | 278 | VOP_SPLICE_READ(vp, infilp, ppos, pipe, len, flags, IO_INVIS, NULL, rval); |
277 | return rval; | 279 | return rval; |
278 | } | 280 | } |
279 | 281 | ||
@@ -281,13 +283,14 @@ STATIC ssize_t | |||
281 | xfs_file_splice_write( | 283 | xfs_file_splice_write( |
282 | struct pipe_inode_info *pipe, | 284 | struct pipe_inode_info *pipe, |
283 | struct file *outfilp, | 285 | struct file *outfilp, |
286 | loff_t *ppos, | ||
284 | size_t len, | 287 | size_t len, |
285 | unsigned int flags) | 288 | unsigned int flags) |
286 | { | 289 | { |
287 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 290 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); |
288 | ssize_t rval; | 291 | ssize_t rval; |
289 | 292 | ||
290 | VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, 0, NULL, rval); | 293 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, 0, NULL, rval); |
291 | return rval; | 294 | return rval; |
292 | } | 295 | } |
293 | 296 | ||
@@ -295,13 +298,14 @@ STATIC ssize_t | |||
295 | xfs_file_splice_write_invis( | 298 | xfs_file_splice_write_invis( |
296 | struct pipe_inode_info *pipe, | 299 | struct pipe_inode_info *pipe, |
297 | struct file *outfilp, | 300 | struct file *outfilp, |
301 | loff_t *ppos, | ||
298 | size_t len, | 302 | size_t len, |
299 | unsigned int flags) | 303 | unsigned int flags) |
300 | { | 304 | { |
301 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); | 305 | vnode_t *vp = vn_from_inode(outfilp->f_dentry->d_inode); |
302 | ssize_t rval; | 306 | ssize_t rval; |
303 | 307 | ||
304 | VOP_SPLICE_WRITE(vp, pipe, outfilp, len, flags, IO_INVIS, NULL, rval); | 308 | VOP_SPLICE_WRITE(vp, pipe, outfilp, ppos, len, flags, IO_INVIS, NULL, rval); |
305 | return rval; | 309 | return rval; |
306 | } | 310 | } |
307 | 311 | ||
diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 74a52937f208..67efe3308980 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c | |||
@@ -338,6 +338,7 @@ ssize_t | |||
338 | xfs_splice_read( | 338 | xfs_splice_read( |
339 | bhv_desc_t *bdp, | 339 | bhv_desc_t *bdp, |
340 | struct file *infilp, | 340 | struct file *infilp, |
341 | loff_t *ppos, | ||
341 | struct pipe_inode_info *pipe, | 342 | struct pipe_inode_info *pipe, |
342 | size_t count, | 343 | size_t count, |
343 | int flags, | 344 | int flags, |
@@ -360,7 +361,7 @@ xfs_splice_read( | |||
360 | int error; | 361 | int error; |
361 | 362 | ||
362 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), | 363 | error = XFS_SEND_DATA(mp, DM_EVENT_READ, BHV_TO_VNODE(bdp), |
363 | infilp->f_pos, count, | 364 | *ppos, count, |
364 | FILP_DELAY_FLAG(infilp), &locktype); | 365 | FILP_DELAY_FLAG(infilp), &locktype); |
365 | if (error) { | 366 | if (error) { |
366 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); | 367 | xfs_iunlock(ip, XFS_IOLOCK_SHARED); |
@@ -368,8 +369,8 @@ xfs_splice_read( | |||
368 | } | 369 | } |
369 | } | 370 | } |
370 | xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, | 371 | xfs_rw_enter_trace(XFS_SPLICE_READ_ENTER, &ip->i_iocore, |
371 | pipe, count, infilp->f_pos, ioflags); | 372 | pipe, count, *ppos, ioflags); |
372 | ret = generic_file_splice_read(infilp, pipe, count, flags); | 373 | ret = generic_file_splice_read(infilp, ppos, pipe, count, flags); |
373 | if (ret > 0) | 374 | if (ret > 0) |
374 | XFS_STATS_ADD(xs_read_bytes, ret); | 375 | XFS_STATS_ADD(xs_read_bytes, ret); |
375 | 376 | ||
@@ -382,6 +383,7 @@ xfs_splice_write( | |||
382 | bhv_desc_t *bdp, | 383 | bhv_desc_t *bdp, |
383 | struct pipe_inode_info *pipe, | 384 | struct pipe_inode_info *pipe, |
384 | struct file *outfilp, | 385 | struct file *outfilp, |
386 | loff_t *ppos, | ||
385 | size_t count, | 387 | size_t count, |
386 | int flags, | 388 | int flags, |
387 | int ioflags, | 389 | int ioflags, |
@@ -403,7 +405,7 @@ xfs_splice_write( | |||
403 | int error; | 405 | int error; |
404 | 406 | ||
405 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), | 407 | error = XFS_SEND_DATA(mp, DM_EVENT_WRITE, BHV_TO_VNODE(bdp), |
406 | outfilp->f_pos, count, | 408 | *ppos, count, |
407 | FILP_DELAY_FLAG(outfilp), &locktype); | 409 | FILP_DELAY_FLAG(outfilp), &locktype); |
408 | if (error) { | 410 | if (error) { |
409 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); | 411 | xfs_iunlock(ip, XFS_IOLOCK_EXCL); |
@@ -411,8 +413,8 @@ xfs_splice_write( | |||
411 | } | 413 | } |
412 | } | 414 | } |
413 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, | 415 | xfs_rw_enter_trace(XFS_SPLICE_WRITE_ENTER, &ip->i_iocore, |
414 | pipe, count, outfilp->f_pos, ioflags); | 416 | pipe, count, *ppos, ioflags); |
415 | ret = generic_file_splice_write(pipe, outfilp, count, flags); | 417 | ret = generic_file_splice_write(pipe, outfilp, ppos, count, flags); |
416 | if (ret > 0) | 418 | if (ret > 0) |
417 | XFS_STATS_ADD(xs_write_bytes, ret); | 419 | XFS_STATS_ADD(xs_write_bytes, ret); |
418 | 420 | ||
diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index 55c689a86ad2..8f4539952350 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h | |||
@@ -93,11 +93,11 @@ extern ssize_t xfs_write(struct bhv_desc *, struct kiocb *, | |||
93 | extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, | 93 | extern ssize_t xfs_sendfile(struct bhv_desc *, struct file *, |
94 | loff_t *, int, size_t, read_actor_t, | 94 | loff_t *, int, size_t, read_actor_t, |
95 | void *, struct cred *); | 95 | void *, struct cred *); |
96 | extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, | 96 | extern ssize_t xfs_splice_read(struct bhv_desc *, struct file *, loff_t *, |
97 | struct pipe_inode_info *, size_t, int, int, | 97 | struct pipe_inode_info *, size_t, int, int, |
98 | struct cred *); | 98 | struct cred *); |
99 | extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, | 99 | extern ssize_t xfs_splice_write(struct bhv_desc *, struct pipe_inode_info *, |
100 | struct file *, size_t, int, int, | 100 | struct file *, loff_t *, size_t, int, int, |
101 | struct cred *); | 101 | struct cred *); |
102 | 102 | ||
103 | #endif /* __XFS_LRW_H__ */ | 103 | #endif /* __XFS_LRW_H__ */ |
diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 88b09f186289..2a8e16c22353 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h | |||
@@ -173,11 +173,11 @@ typedef ssize_t (*vop_write_t)(bhv_desc_t *, struct kiocb *, | |||
173 | typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, | 173 | typedef ssize_t (*vop_sendfile_t)(bhv_desc_t *, struct file *, |
174 | loff_t *, int, size_t, read_actor_t, | 174 | loff_t *, int, size_t, read_actor_t, |
175 | void *, struct cred *); | 175 | void *, struct cred *); |
176 | typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, | 176 | typedef ssize_t (*vop_splice_read_t)(bhv_desc_t *, struct file *, loff_t *, |
177 | struct pipe_inode_info *, size_t, int, int, | 177 | struct pipe_inode_info *, size_t, int, int, |
178 | struct cred *); | 178 | struct cred *); |
179 | typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, | 179 | typedef ssize_t (*vop_splice_write_t)(bhv_desc_t *, struct pipe_inode_info *, |
180 | struct file *, size_t, int, int, | 180 | struct file *, loff_t *, size_t, int, int, |
181 | struct cred *); | 181 | struct cred *); |
182 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, | 182 | typedef int (*vop_ioctl_t)(bhv_desc_t *, struct inode *, struct file *, |
183 | int, unsigned int, void __user *); | 183 | int, unsigned int, void __user *); |
@@ -284,10 +284,10 @@ typedef struct vnodeops { | |||
284 | rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) | 284 | rv = _VOP_(vop_write, vp)((vp)->v_fbhv,file,iov,segs,offset,ioflags,cr) |
285 | #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ | 285 | #define VOP_SENDFILE(vp,f,off,ioflags,cnt,act,targ,cr,rv) \ |
286 | rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) | 286 | rv = _VOP_(vop_sendfile, vp)((vp)->v_fbhv,f,off,ioflags,cnt,act,targ,cr) |
287 | #define VOP_SPLICE_READ(vp,f,pipe,cnt,fl,iofl,cr,rv) \ | 287 | #define VOP_SPLICE_READ(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ |
288 | rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) | 288 | rv = _VOP_(vop_splice_read, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) |
289 | #define VOP_SPLICE_WRITE(vp,f,pipe,cnt,fl,iofl,cr,rv) \ | 289 | #define VOP_SPLICE_WRITE(vp,f,o,pipe,cnt,fl,iofl,cr,rv) \ |
290 | rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,pipe,cnt,fl,iofl,cr) | 290 | rv = _VOP_(vop_splice_write, vp)((vp)->v_fbhv,f,o,pipe,cnt,fl,iofl,cr) |
291 | #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ | 291 | #define VOP_BMAP(vp,of,sz,rw,b,n,rv) \ |
292 | rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) | 292 | rv = _VOP_(vop_bmap, vp)((vp)->v_fbhv,of,sz,rw,b,n) |
293 | #define VOP_OPEN(vp, cr, rv) \ | 293 | #define VOP_OPEN(vp, cr, rv) \ |
diff --git a/include/asm-i386/unistd.h b/include/asm-i386/unistd.h index 6a8dd83c350f..d81d6cfc1bb4 100644 --- a/include/asm-i386/unistd.h +++ b/include/asm-i386/unistd.h | |||
@@ -320,8 +320,9 @@ | |||
320 | #define __NR_get_robust_list 312 | 320 | #define __NR_get_robust_list 312 |
321 | #define __NR_splice 313 | 321 | #define __NR_splice 313 |
322 | #define __NR_sync_file_range 314 | 322 | #define __NR_sync_file_range 314 |
323 | #define __NR_tee 315 | ||
323 | 324 | ||
324 | #define NR_syscalls 315 | 325 | #define NR_syscalls 316 |
325 | 326 | ||
326 | /* | 327 | /* |
327 | * user-visible error numbers are in the range -1 - -128: see | 328 | * user-visible error numbers are in the range -1 - -128: see |
diff --git a/include/asm-ia64/unistd.h b/include/asm-ia64/unistd.h index 1c749acca021..a40ebec6aeeb 100644 --- a/include/asm-ia64/unistd.h +++ b/include/asm-ia64/unistd.h | |||
@@ -289,12 +289,13 @@ | |||
289 | #define __NR_set_robust_list 1298 | 289 | #define __NR_set_robust_list 1298 |
290 | #define __NR_get_robust_list 1299 | 290 | #define __NR_get_robust_list 1299 |
291 | #define __NR_sync_file_range 1300 | 291 | #define __NR_sync_file_range 1300 |
292 | #define __NR_tee 1301 | ||
292 | 293 | ||
293 | #ifdef __KERNEL__ | 294 | #ifdef __KERNEL__ |
294 | 295 | ||
295 | #include <linux/config.h> | 296 | #include <linux/config.h> |
296 | 297 | ||
297 | #define NR_syscalls 277 /* length of syscall table */ | 298 | #define NR_syscalls 278 /* length of syscall table */ |
298 | 299 | ||
299 | #define __ARCH_WANT_SYS_RT_SIGACTION | 300 | #define __ARCH_WANT_SYS_RT_SIGACTION |
300 | 301 | ||
diff --git a/include/asm-powerpc/unistd.h b/include/asm-powerpc/unistd.h index 536ba0873052..c612f1a62772 100644 --- a/include/asm-powerpc/unistd.h +++ b/include/asm-powerpc/unistd.h | |||
@@ -302,8 +302,9 @@ | |||
302 | #define __NR_ppoll 281 | 302 | #define __NR_ppoll 281 |
303 | #define __NR_unshare 282 | 303 | #define __NR_unshare 282 |
304 | #define __NR_splice 283 | 304 | #define __NR_splice 283 |
305 | #define __NR_tee 284 | ||
305 | 306 | ||
306 | #define __NR_syscalls 284 | 307 | #define __NR_syscalls 285 |
307 | 308 | ||
308 | #ifdef __KERNEL__ | 309 | #ifdef __KERNEL__ |
309 | #define __NR__exit __NR_exit | 310 | #define __NR__exit __NR_exit |
diff --git a/include/asm-x86_64/unistd.h b/include/asm-x86_64/unistd.h index f21ff2c1e960..d86494e23b63 100644 --- a/include/asm-x86_64/unistd.h +++ b/include/asm-x86_64/unistd.h | |||
@@ -611,8 +611,10 @@ __SYSCALL(__NR_set_robust_list, sys_set_robust_list) | |||
611 | __SYSCALL(__NR_get_robust_list, sys_get_robust_list) | 611 | __SYSCALL(__NR_get_robust_list, sys_get_robust_list) |
612 | #define __NR_splice 275 | 612 | #define __NR_splice 275 |
613 | __SYSCALL(__NR_splice, sys_splice) | 613 | __SYSCALL(__NR_splice, sys_splice) |
614 | #define __NR_tee 276 | ||
615 | __SYSCALL(__NR_tee, sys_tee) | ||
614 | 616 | ||
615 | #define __NR_syscall_max __NR_splice | 617 | #define __NR_syscall_max __NR_tee |
616 | 618 | ||
617 | #ifndef __NO_STUBS | 619 | #ifndef __NO_STUBS |
618 | 620 | ||
diff --git a/include/linux/fs.h b/include/linux/fs.h index 162c6e57307a..3de2bfb2410f 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -1039,8 +1039,8 @@ struct file_operations { | |||
1039 | int (*check_flags)(int); | 1039 | int (*check_flags)(int); |
1040 | int (*dir_notify)(struct file *filp, unsigned long arg); | 1040 | int (*dir_notify)(struct file *filp, unsigned long arg); |
1041 | int (*flock) (struct file *, int, struct file_lock *); | 1041 | int (*flock) (struct file *, int, struct file_lock *); |
1042 | ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, size_t, unsigned int); | 1042 | ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int); |
1043 | ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int); | 1043 | ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); |
1044 | }; | 1044 | }; |
1045 | 1045 | ||
1046 | struct inode_operations { | 1046 | struct inode_operations { |
@@ -1613,13 +1613,13 @@ extern void do_generic_mapping_read(struct address_space *mapping, | |||
1613 | loff_t *, read_descriptor_t *, read_actor_t); | 1613 | loff_t *, read_descriptor_t *, read_actor_t); |
1614 | 1614 | ||
1615 | /* fs/splice.c */ | 1615 | /* fs/splice.c */ |
1616 | extern ssize_t generic_file_splice_read(struct file *, | 1616 | extern ssize_t generic_file_splice_read(struct file *, loff_t *, |
1617 | struct pipe_inode_info *, size_t, unsigned int); | 1617 | struct pipe_inode_info *, size_t, unsigned int); |
1618 | extern ssize_t generic_file_splice_write(struct pipe_inode_info *, | 1618 | extern ssize_t generic_file_splice_write(struct pipe_inode_info *, |
1619 | struct file *, size_t, unsigned int); | 1619 | struct file *, loff_t *, size_t, unsigned int); |
1620 | extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, | 1620 | extern ssize_t generic_splice_sendpage(struct pipe_inode_info *pipe, |
1621 | struct file *out, size_t len, unsigned int flags); | 1621 | struct file *out, loff_t *, size_t len, unsigned int flags); |
1622 | extern long do_splice_direct(struct file *in, struct file *out, | 1622 | extern long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, |
1623 | size_t len, unsigned int flags); | 1623 | size_t len, unsigned int flags); |
1624 | 1624 | ||
1625 | extern void | 1625 | extern void |
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index 123a7c24bc72..ef7f33c0be19 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h | |||
@@ -21,6 +21,7 @@ struct pipe_buf_operations { | |||
21 | void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *); | 21 | void (*unmap)(struct pipe_inode_info *, struct pipe_buffer *); |
22 | void (*release)(struct pipe_inode_info *, struct pipe_buffer *); | 22 | void (*release)(struct pipe_inode_info *, struct pipe_buffer *); |
23 | int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); | 23 | int (*steal)(struct pipe_inode_info *, struct pipe_buffer *); |
24 | void (*get)(struct pipe_inode_info *, struct pipe_buffer *); | ||
24 | }; | 25 | }; |
25 | 26 | ||
26 | struct pipe_inode_info { | 27 | struct pipe_inode_info { |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index f001bad28d9a..d3ebc0e68b2b 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
@@ -574,6 +574,8 @@ asmlinkage long sys_splice(int fd_in, loff_t __user *off_in, | |||
574 | int fd_out, loff_t __user *off_out, | 574 | int fd_out, loff_t __user *off_out, |
575 | size_t len, unsigned int flags); | 575 | size_t len, unsigned int flags); |
576 | 576 | ||
577 | asmlinkage long sys_tee(int fdin, int fdout, size_t len, unsigned int flags); | ||
578 | |||
577 | asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, | 579 | asmlinkage long sys_sync_file_range(int fd, loff_t offset, loff_t nbytes, |
578 | unsigned int flags); | 580 | unsigned int flags); |
579 | 581 | ||