diff options
Diffstat (limited to 'fs')
-rw-r--r-- | fs/splice.c | 12 |
1 files changed, 8 insertions, 4 deletions
diff --git a/fs/splice.c b/fs/splice.c index 78150038b584..a048ad2130c3 100644 --- a/fs/splice.c +++ b/fs/splice.c | |||
@@ -983,7 +983,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
983 | 983 | ||
984 | while (len) { | 984 | while (len) { |
985 | size_t read_len; | 985 | size_t read_len; |
986 | loff_t pos = sd->pos; | 986 | loff_t pos = sd->pos, prev_pos = pos; |
987 | 987 | ||
988 | ret = do_splice_to(in, &pos, pipe, len, flags); | 988 | ret = do_splice_to(in, &pos, pipe, len, flags); |
989 | if (unlikely(ret <= 0)) | 989 | if (unlikely(ret <= 0)) |
@@ -998,15 +998,19 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd, | |||
998 | * could get stuck data in the internal pipe: | 998 | * could get stuck data in the internal pipe: |
999 | */ | 999 | */ |
1000 | ret = actor(pipe, sd); | 1000 | ret = actor(pipe, sd); |
1001 | if (unlikely(ret <= 0)) | 1001 | if (unlikely(ret <= 0)) { |
1002 | sd->pos = prev_pos; | ||
1002 | goto out_release; | 1003 | goto out_release; |
1004 | } | ||
1003 | 1005 | ||
1004 | bytes += ret; | 1006 | bytes += ret; |
1005 | len -= ret; | 1007 | len -= ret; |
1006 | sd->pos = pos; | 1008 | sd->pos = pos; |
1007 | 1009 | ||
1008 | if (ret < read_len) | 1010 | if (ret < read_len) { |
1011 | sd->pos = prev_pos + ret; | ||
1009 | goto out_release; | 1012 | goto out_release; |
1013 | } | ||
1010 | } | 1014 | } |
1011 | 1015 | ||
1012 | done: | 1016 | done: |
@@ -1072,7 +1076,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out, | |||
1072 | 1076 | ||
1073 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); | 1077 | ret = splice_direct_to_actor(in, &sd, direct_splice_actor); |
1074 | if (ret > 0) | 1078 | if (ret > 0) |
1075 | *ppos += ret; | 1079 | *ppos = sd.pos; |
1076 | 1080 | ||
1077 | return ret; | 1081 | return ret; |
1078 | } | 1082 | } |