diff options
| author | Jens Axboe <jens.axboe@oracle.com> | 2007-06-12 15:17:17 -0400 |
|---|---|---|
| committer | Jens Axboe <jens.axboe@oracle.com> | 2007-07-10 02:04:12 -0400 |
| commit | c66ab6fa705e1b2887a6d9246b798bdc526839e2 (patch) | |
| tree | 764ece0ee44f937012dfaa1657709da548ed5b16 | |
| parent | 71780f59e127bb281a9302d430495ca9586c14e7 (diff) | |
splice: abstract out actor data
For direct splicing (or private splicing), the output may not be a file.
So abstract out the handling into a specified actor function and put
the data in the splice_desc structure earlier, so we can build on top
of that.
This is the first step in better splice handling for drivers, and also
for implementing vmsplice _to_ user memory.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
| -rw-r--r-- | fs/ocfs2/file.c | 11 | ||||
| -rw-r--r-- | fs/splice.c | 99 | ||||
| -rw-r--r-- | include/linux/pipe_fs_i.h | 10 |
3 files changed, 84 insertions, 36 deletions
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index ac6c96431bbc..93565c03d315 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
| @@ -1636,9 +1636,14 @@ static ssize_t __ocfs2_file_splice_write(struct pipe_inode_info *pipe, | |||
| 1636 | int ret, err; | 1636 | int ret, err; |
| 1637 | struct address_space *mapping = out->f_mapping; | 1637 | struct address_space *mapping = out->f_mapping; |
| 1638 | struct inode *inode = mapping->host; | 1638 | struct inode *inode = mapping->host; |
| 1639 | 1639 | struct splice_desc sd = { | |
| 1640 | ret = __splice_from_pipe(pipe, out, ppos, len, flags, | 1640 | .total_len = len, |
| 1641 | ocfs2_splice_write_actor); | 1641 | .flags = flags, |
| 1642 | .pos = *ppos, | ||
| 1643 | .file = out, | ||
| 1644 | }; | ||
| 1645 | |||
| 1646 | ret = __splice_from_pipe(pipe, &sd, ocfs2_splice_write_actor); | ||
| 1642 | if (ret > 0) { | 1647 | if (ret > 0) { |
| 1643 | *ppos += ret; | 1648 | *ppos += ret; |
| 1644 | 1649 | ||
diff --git a/fs/splice.c b/fs/splice.c index e7d7080de2f9..68f6328236a6 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
| @@ -668,31 +668,24 @@ out_ret: | |||
| 668 | * key here is the 'actor' worker passed in that actually moves the data | 668 | * key here is the 'actor' worker passed in that actually moves the data |
| 669 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. | 669 | * to the wanted destination. See pipe_to_file/pipe_to_sendpage above. |
| 670 | */ | 670 | */ |
| 671 | ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, | 671 | ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, struct splice_desc *sd, |
| 672 | struct file *out, loff_t *ppos, size_t len, | 672 | splice_actor *actor) |
| 673 | unsigned int flags, splice_actor *actor) | ||
| 674 | { | 673 | { |
| 675 | int ret, do_wakeup, err; | 674 | int ret, do_wakeup, err; |
| 676 | struct splice_desc sd; | ||
| 677 | 675 | ||
| 678 | ret = 0; | 676 | ret = 0; |
| 679 | do_wakeup = 0; | 677 | do_wakeup = 0; |
| 680 | 678 | ||
| 681 | sd.total_len = len; | ||
| 682 | sd.flags = flags; | ||
| 683 | sd.file = out; | ||
| 684 | sd.pos = *ppos; | ||
| 685 | |||
| 686 | for (;;) { | 679 | for (;;) { |
| 687 | if (pipe->nrbufs) { | 680 | if (pipe->nrbufs) { |
| 688 | struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; | 681 | struct pipe_buffer *buf = pipe->bufs + pipe->curbuf; |
| 689 | const struct pipe_buf_operations *ops = buf->ops; | 682 | const struct pipe_buf_operations *ops = buf->ops; |
| 690 | 683 | ||
| 691 | sd.len = buf->len; | 684 | sd->len = buf->len; |
| 692 | if (sd.len > sd.total_len) | 685 | if (sd->len > sd->total_len) |
| 693 | sd.len = sd.total_len; | 686 | sd->len = sd->total_len; |
| 694 | 687 | ||
| 695 | err = actor(pipe, buf, &sd); | 688 | err = actor(pipe, buf, sd); |
| 696 | if (err <= 0) { | 689 | if (err <= 0) { |
| 697 | if (!ret && err != -ENODATA) | 690 | if (!ret && err != -ENODATA) |
| 698 | ret = err; | 691 | ret = err; |
| @@ -704,10 +697,10 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, | |||
| 704 | buf->offset += err; | 697 | buf->offset += err; |
| 705 | buf->len -= err; | 698 | buf->len -= err; |
| 706 | 699 | ||
| 707 | sd.len -= err; | 700 | sd->len -= err; |
| 708 | sd.pos += err; | 701 | sd->pos += err; |
| 709 | sd.total_len -= err; | 702 | sd->total_len -= err; |
| 710 | if (sd.len) | 703 | if (sd->len) |
| 711 | continue; | 704 | continue; |
| 712 | 705 | ||
| 713 | if (!buf->len) { | 706 | if (!buf->len) { |
| @@ -719,7 +712,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, | |||
| 719 | do_wakeup = 1; | 712 | do_wakeup = 1; |
| 720 | } | 713 | } |
| 721 | 714 | ||
| 722 | if (!sd.total_len) | 715 | if (!sd->total_len) |
| 723 | break; | 716 | break; |
| 724 | } | 717 | } |
| 725 | 718 | ||
| @@ -732,7 +725,7 @@ ssize_t __splice_from_pipe(struct pipe_inode_info *pipe, | |||
| 732 | break; | 725 | break; |
| 733 | } | 726 | } |
| 734 | 727 | ||
| 735 | if (flags & SPLICE_F_NONBLOCK) { | 728 | if (sd->flags & SPLICE_F_NONBLOCK) { |
| 736 | if (!ret) | 729 | if (!ret) |
| 737 | ret = -EAGAIN; | 730 | ret = -EAGAIN; |
| 738 | break; | 731 | break; |
| @@ -772,6 +765,12 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
| 772 | { | 765 | { |
| 773 | ssize_t ret; | 766 | ssize_t ret; |
| 774 | struct inode *inode = out->f_mapping->host; | 767 | struct inode *inode = out->f_mapping->host; |
| 768 | struct splice_desc sd = { | ||
| 769 | .total_len = len, | ||
| 770 | .flags = flags, | ||
| 771 | .pos = *ppos, | ||
| 772 | .file = out, | ||
| 773 | }; | ||
| 775 | 774 | ||
| 776 | /* | 775 | /* |
| 777 | * The actor worker might be calling ->prepare_write and | 776 | * The actor worker might be calling ->prepare_write and |
| @@ -780,7 +779,7 @@ ssize_t splice_from_pipe(struct pipe_inode_info *pipe, struct file *out, | |||
| 780 | * pipe->inode, we have to order lock acquiry here. | 779 | * pipe->inode, we have to order lock acquiry here. |
| 781 | */ | 780 | */ |
| 782 | inode_double_lock(inode, pipe->inode); | 781 | inode_double_lock(inode, pipe->inode); |
| 783 | ret = __splice_from_pipe(pipe, out, ppos, len, flags, actor); | 782 | ret = __splice_from_pipe(pipe, &sd, actor); |
| 784 | inode_double_unlock(inode, pipe->inode); | 783 | inode_double_unlock(inode, pipe->inode); |
| 785 | 784 | ||
| 786 | return ret; | 785 | return ret; |
| @@ -804,6 +803,12 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, | |||
| 804 | { | 803 | { |
| 805 | struct address_space *mapping = out->f_mapping; | 804 | struct address_space *mapping = out->f_mapping; |
| 806 | struct inode *inode = mapping->host; | 805 | struct inode *inode = mapping->host; |
| 806 | struct splice_desc sd = { | ||
| 807 | .total_len = len, | ||
| 808 | .flags = flags, | ||
| 809 | .pos = *ppos, | ||
| 810 | .file = out, | ||
| 811 | }; | ||
| 807 | ssize_t ret; | 812 | ssize_t ret; |
| 808 | int err; | 813 | int err; |
| 809 | 814 | ||
| @@ -811,7 +816,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, | |||
| 811 | if (unlikely(err)) | 816 | if (unlikely(err)) |
| 812 | return err; | 817 | return err; |
| 813 | 818 | ||
| 814 | ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); | 819 | ret = __splice_from_pipe(pipe, &sd, pipe_to_file); |
| 815 | if (ret > 0) { | 820 | if (ret > 0) { |
| 816 | unsigned long nr_pages; | 821 | unsigned long nr_pages; |
| 817 | 822 | ||
| @@ -956,14 +961,17 @@ static long do_splice_to(struct file *in, loff_t *ppos, | |||
| 956 | return in->f_op->splice_read(in, ppos, pipe, len, flags); | 961 | return in->f_op->splice_read(in, ppos, pipe, len, flags); |
| 957 | } | 962 | } |
| 958 | 963 | ||
| 959 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | 964 | /* |
| 960 | size_t len, unsigned int flags) | 965 | * Splices from an input file to an actor, using a 'direct' pipe. |
| 966 | */ | ||
| 967 | ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | ||
| 968 | splice_direct_actor *actor) | ||
| 961 | { | 969 | { |
| 962 | struct pipe_inode_info *pipe; | 970 | struct pipe_inode_info *pipe; |
| 963 | long ret, bytes; | 971 | long ret, bytes; |
| 964 | loff_t out_off; | ||
| 965 | umode_t i_mode; | 972 | umode_t i_mode; |
| 966 | int i; | 973 | size_t len; |
| 974 | int i, flags; | ||
| 967 | 975 | ||
| 968 | /* | 976 | /* |
| 969 | * We require the input being a regular file, as we don't want to | 977 | * We require the input being a regular file, as we don't want to |
| @@ -999,7 +1007,13 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
| 999 | */ | 1007 | */ |
| 1000 | ret = 0; | 1008 | ret = 0; |
| 1001 | bytes = 0; | 1009 | bytes = 0; |
| 1002 | out_off = 0; | 1010 | len = sd->total_len; |
| 1011 | flags = sd->flags; | ||
| 1012 | |||
| 1013 | /* | ||
| 1014 | * Don't block on output, we have to drain the direct pipe. | ||
| 1015 | */ | ||
| 1016 | sd->flags &= ~SPLICE_F_NONBLOCK; | ||
| 1003 | 1017 | ||
| 1004 | while (len) { | 1018 | while (len) { |
| 1005 | size_t read_len, max_read_len; | 1019 | size_t read_len, max_read_len; |
| @@ -1009,19 +1023,19 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
| 1009 | */ | 1023 | */ |
| 1010 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); | 1024 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); |
| 1011 | 1025 | ||
| 1012 | ret = do_splice_to(in, ppos, pipe, max_read_len, flags); | 1026 | ret = do_splice_to(in, &sd->pos, pipe, max_read_len, flags); |
| 1013 | if (unlikely(ret < 0)) | 1027 | if (unlikely(ret < 0)) |
| 1014 | goto out_release; | 1028 | goto out_release; |
| 1015 | 1029 | ||
| 1016 | read_len = ret; | 1030 | read_len = ret; |
| 1031 | sd->total_len = read_len; | ||
| 1017 | 1032 | ||
| 1018 | /* | 1033 | /* |
| 1019 | * NOTE: nonblocking mode only applies to the input. We | 1034 | * NOTE: nonblocking mode only applies to the input. We |
| 1020 | * must not do the output in nonblocking mode as then we | 1035 | * must not do the output in nonblocking mode as then we |
| 1021 | * could get stuck data in the internal pipe: | 1036 | * could get stuck data in the internal pipe: |
| 1022 | */ | 1037 | */ |
| 1023 | ret = do_splice_from(pipe, out, &out_off, read_len, | 1038 | ret = actor(pipe, sd); |
| 1024 | flags & ~SPLICE_F_NONBLOCK); | ||
| 1025 | if (unlikely(ret < 0)) | 1039 | if (unlikely(ret < 0)) |
| 1026 | goto out_release; | 1040 | goto out_release; |
| 1027 | 1041 | ||
| @@ -1066,6 +1080,33 @@ out_release: | |||
| 1066 | return bytes; | 1080 | return bytes; |
| 1067 | 1081 | ||
| 1068 | return ret; | 1082 | return ret; |
| 1083 | |||
| 1084 | } | ||
| 1085 | EXPORT_SYMBOL(splice_direct_to_actor); | ||
| 1086 | |||
| 1087 | static int direct_splice_actor(struct pipe_inode_info *pipe, | ||
| 1088 | struct splice_desc *sd) | ||
| 1089 | { | ||
| 1090 | struct file *file = sd->file; | ||
| 1091 | |||
| 1092 | return do_splice_from(pipe, file, &sd->pos, sd->total_len, sd->flags); | ||
| 1093 | } | ||
| 1094 | |||
| 1095 | long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | ||
| 1096 | size_t len, unsigned int flags) | ||
| 1097 | { | ||
| 1098 | struct splice_desc sd = { | ||
| 1099 | .len = len, | ||
| 1100 | .total_len = len, | ||
| 1101 | .flags = flags, | ||
| 1102 | .pos = *ppos, | ||
| 1103 | .file = out, | ||
| 1104 | }; | ||
| 1105 | size_t ret; | ||
| 1106 | |||
| 1107 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); | ||
| 1108 | *ppos = sd.pos; | ||
| 1109 | return ret; | ||
| 1069 | } | 1110 | } |
| 1070 | 1111 | ||
| 1071 | /* | 1112 | /* |
diff --git a/include/linux/pipe_fs_i.h b/include/linux/pipe_fs_i.h index c8884f971228..883ba9b78d3f 100644 --- a/include/linux/pipe_fs_i.h +++ b/include/linux/pipe_fs_i.h | |||
| @@ -94,13 +94,15 @@ struct splice_desc { | |||
| 94 | 94 | ||
| 95 | typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, | 95 | typedef int (splice_actor)(struct pipe_inode_info *, struct pipe_buffer *, |
| 96 | struct splice_desc *); | 96 | struct splice_desc *); |
| 97 | typedef int (splice_direct_actor)(struct pipe_inode_info *, | ||
| 98 | struct splice_desc *); | ||
| 97 | 99 | ||
| 98 | extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *, | 100 | extern ssize_t splice_from_pipe(struct pipe_inode_info *, struct file *, |
| 99 | loff_t *, size_t, unsigned int, | 101 | loff_t *, size_t, unsigned int, |
| 100 | splice_actor *); | 102 | splice_actor *); |
| 101 | 103 | extern ssize_t __splice_from_pipe(struct pipe_inode_info *, | |
| 102 | extern ssize_t __splice_from_pipe(struct pipe_inode_info *, struct file *, | 104 | struct splice_desc *, splice_actor *); |
| 103 | loff_t *, size_t, unsigned int, | 105 | extern ssize_t splice_direct_to_actor(struct file *, struct splice_desc *, |
| 104 | splice_actor *); | 106 | splice_direct_actor *); |
| 105 | 107 | ||
| 106 | #endif | 108 | #endif |
