aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJens Axboe <jens.axboe@oracle.com>2007-07-16 08:41:49 -0400
committerJens Axboe <jens.axboe@oracle.com>2007-07-16 09:02:48 -0400
commitbcd4f3acbaec102e2b8000c977ecc38dcd0fe367 (patch)
tree03134513c5f47540814ee2d86cbb31523f722efa
parent56a68a500fcab9e3a9a49ca7fbef14230ab7d144 (diff)
splice: direct splicing updates ppos twice
OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> reported that he's noticed nfsd read corruption in recent kernels, and did the hard work of discovering that it's due to splice updating the file position twice. This means that the next operation would start further ahead than it should. nfsd_vfs_read() splice_direct_to_actor() while(len) { do_splice_to() [update sd->pos] -> generic_file_splice_read() [read from sd->pos] nfsd_direct_splice_actor() -> __splice_from_pipe() [update sd->pos] There's nothing wrong with the core splice code, but the direct splicing is an addon that calls both input and output paths. So it has to take care in locally caching offset so it remains correct. Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
-rw-r--r--fs/splice.c4
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 6c9828651e6f..53fc2082a468 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -1061,8 +1061,9 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
1061 1061
1062 while (len) { 1062 while (len) {
1063 size_t read_len; 1063 size_t read_len;
1064 loff_t pos = sd->pos;
1064 1065
1065 ret = do_splice_to(in, &sd->pos, pipe, len, flags); 1066 ret = do_splice_to(in, &pos, pipe, len, flags);
1066 if (unlikely(ret <= 0)) 1067 if (unlikely(ret <= 0))
1067 goto out_release; 1068 goto out_release;
1068 1069
@@ -1080,6 +1081,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
1080 1081
1081 bytes += ret; 1082 bytes += ret;
1082 len -= ret; 1083 len -= ret;
1084 sd->pos = pos;
1083 1085
1084 if (ret < read_len) 1086 if (ret < read_len)
1085 goto out_release; 1087 goto out_release;