diff options
Diffstat (limited to 'fs/splice.c')
| -rw-r--r-- | fs/splice.c | 17 | 
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 | */ | 
| 78 | out_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 | ||
| 1012 | done: | 1017 | done: | 
| @@ -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 | } | 
