diff options
Diffstat (limited to 'fs/splice.c')
| -rw-r--r-- | fs/splice.c | 272 |
1 files changed, 230 insertions, 42 deletions
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 | } | ||
