diff options
author | Jens Axboe <jens.axboe@oracle.com> | 2007-07-13 08:11:43 -0400 |
---|---|---|
committer | Jens Axboe <jens.axboe@oracle.com> | 2007-07-13 08:14:31 -0400 |
commit | 51a92c0f6ce8fa85fa0e18ecda1d847e606e8066 (patch) | |
tree | b944b46d3856948931160c8a75ee27be3417c515 /fs/splice.c | |
parent | 29ce20586be54ceba49c55ae049541398cd2c416 (diff) |
splice: fix offset mangling with direct splicing (sendfile)
If the output actor doesn't transfer the full amount of data, we will
increment ppos too much. Two related bugs in there:
- We need to break out and return actor() retval if it is shorted than
what we spliced into the pipe.
- Adjust ppos only according to actor() return.
Also fix loop problem in generic_file_splice_read(), it should not keep
going when data has already been transferred.
Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
Diffstat (limited to 'fs/splice.c')
-rw-r--r-- | fs/splice.c | 34 |
1 files changed, 11 insertions, 23 deletions
diff --git a/fs/splice.c b/fs/splice.c index ef808227bc11..6c9828651e6f 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -492,7 +492,7 @@ ssize_t generic_file_splice_read(struct file *in, loff_t *ppos, | |||
492 | 492 | ||
493 | ret = 0; | 493 | ret = 0; |
494 | spliced = 0; | 494 | spliced = 0; |
495 | while (len) { | 495 | while (len && !spliced) { |
496 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); | 496 | ret = __generic_file_splice_read(in, ppos, pipe, len, flags); |
497 | 497 | ||
498 | if (ret < 0) | 498 | if (ret < 0) |
@@ -1060,15 +1060,10 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
1060 | sd->flags &= ~SPLICE_F_NONBLOCK; | 1060 | sd->flags &= ~SPLICE_F_NONBLOCK; |
1061 | 1061 | ||
1062 | while (len) { | 1062 | while (len) { |
1063 | size_t read_len, max_read_len; | 1063 | size_t read_len; |
1064 | |||
1065 | /* | ||
1066 | * Do at most PIPE_BUFFERS pages worth of transfer: | ||
1067 | */ | ||
1068 | max_read_len = min(len, (size_t)(PIPE_BUFFERS*PAGE_SIZE)); | ||
1069 | 1064 | ||
1070 | ret = do_splice_to(in, &sd->pos, pipe, max_read_len, flags); | 1065 | ret = do_splice_to(in, &sd->pos, pipe, len, flags); |
1071 | if (unlikely(ret < 0)) | 1066 | if (unlikely(ret <= 0)) |
1072 | goto out_release; | 1067 | goto out_release; |
1073 | 1068 | ||
1074 | read_len = ret; | 1069 | read_len = ret; |
@@ -1080,26 +1075,17 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
1080 | * could get stuck data in the internal pipe: | 1075 | * could get stuck data in the internal pipe: |
1081 | */ | 1076 | */ |
1082 | ret = actor(pipe, sd); | 1077 | ret = actor(pipe, sd); |
1083 | if (unlikely(ret < 0)) | 1078 | if (unlikely(ret <= 0)) |
1084 | goto out_release; | 1079 | goto out_release; |
1085 | 1080 | ||
1086 | bytes += ret; | 1081 | bytes += ret; |
1087 | len -= ret; | 1082 | len -= ret; |
1088 | 1083 | ||
1089 | /* | 1084 | if (ret < read_len) |
1090 | * In nonblocking mode, if we got back a short read then | 1085 | goto out_release; |
1091 | * that was due to either an IO error or due to the | ||
1092 | * pagecache entry not being there. In the IO error case | ||
1093 | * the _next_ splice attempt will produce a clean IO error | ||
1094 | * return value (not a short read), so in both cases it's | ||
1095 | * correct to break out of the loop here: | ||
1096 | */ | ||
1097 | if ((flags & SPLICE_F_NONBLOCK) && (read_len < max_read_len)) | ||
1098 | break; | ||
1099 | } | 1086 | } |
1100 | 1087 | ||
1101 | pipe->nrbufs = pipe->curbuf = 0; | 1088 | pipe->nrbufs = pipe->curbuf = 0; |
1102 | |||
1103 | return bytes; | 1089 | return bytes; |
1104 | 1090 | ||
1105 | out_release: | 1091 | out_release: |
@@ -1161,10 +1147,12 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
1161 | .pos = *ppos, | 1147 | .pos = *ppos, |
1162 | .u.file = out, | 1148 | .u.file = out, |
1163 | }; | 1149 | }; |
1164 | size_t ret; | 1150 | long ret; |
1165 | 1151 | ||
1166 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); | 1152 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); |
1167 | *ppos = sd.pos; | 1153 | if (ret > 0) |
1154 | *ppos += ret; | ||
1155 | |||
1168 | return ret; | 1156 | return ret; |
1169 | } | 1157 | } |
1170 | 1158 | ||