aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c17
1 files changed, 11 insertions, 6 deletions
diff --git a/fs/splice.c b/fs/splice.c
index 78150038b584..aa5f6f60b305 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -58,8 +58,8 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
58 */ 58 */
59 wait_on_page_writeback(page); 59 wait_on_page_writeback(page);
60 60
61 if (PagePrivate(page)) 61 if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
62 try_to_release_page(page, GFP_KERNEL); 62 goto out_unlock;
63 63
64 /* 64 /*
65 * If we succeeded in removing the mapping, set LRU flag 65 * If we succeeded in removing the mapping, set LRU flag
@@ -75,6 +75,7 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *pipe,
75 * Raced with truncate or failed to remove page from current 75 * Raced with truncate or failed to remove page from current
76 * address space, unlock and return failure. 76 * address space, unlock and return failure.
77 */ 77 */
78out_unlock:
78 unlock_page(page); 79 unlock_page(page);
79 return 1; 80 return 1;
80} 81}
@@ -983,7 +984,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
983 984
984 while (len) { 985 while (len) {
985 size_t read_len; 986 size_t read_len;
986 loff_t pos = sd->pos; 987 loff_t pos = sd->pos, prev_pos = pos;
987 988
988 ret = do_splice_to(in, &pos, pipe, len, flags); 989 ret = do_splice_to(in, &pos, pipe, len, flags);
989 if (unlikely(ret <= 0)) 990 if (unlikely(ret <= 0))
@@ -998,15 +999,19 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
998 * could get stuck data in the internal pipe: 999 * could get stuck data in the internal pipe:
999 */ 1000 */
1000 ret = actor(pipe, sd); 1001 ret = actor(pipe, sd);
1001 if (unlikely(ret <= 0)) 1002 if (unlikely(ret <= 0)) {
1003 sd->pos = prev_pos;
1002 goto out_release; 1004 goto out_release;
1005 }
1003 1006
1004 bytes += ret; 1007 bytes += ret;
1005 len -= ret; 1008 len -= ret;
1006 sd->pos = pos; 1009 sd->pos = pos;
1007 1010
1008 if (ret < read_len) 1011 if (ret < read_len) {
1012 sd->pos = prev_pos + ret;
1009 goto out_release; 1013 goto out_release;
1014 }
1010 } 1015 }
1011 1016
1012done: 1017done:
@@ -1072,7 +1077,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
1072 1077
1073 ret = splice_direct_to_actor(in, &sd, direct_splice_actor); 1078 ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
1074 if (ret > 0) 1079 if (ret > 0)
1075 *ppos += ret; 1080 *ppos = sd.pos;
1076 1081
1077 return ret; 1082 return ret;
1078} 1083}