aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2008-05-28 08:00:51 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2008-05-28 08:00:51 -0700
commitb4412323cc954bd0a2144b1c2ed573dd2eddb32c (patch)
treea0dd14e6d46efbb36a0898c158e8efb49e4a22ef /fs
parentFRV: Specify the minimum slab/kmalloc alignment (diff)
parentcfq-iosched: fix RCU problem in cfq_cic_lookup() (diff)
downloadlinux-dev-b4412323cc954bd0a2144b1c2ed573dd2eddb32c.tar.xz
linux-dev-b4412323cc954bd0a2144b1c2ed573dd2eddb32c.zip
Merge branch 'for-linus' of git://git.kernel.dk/linux-2.6-block
* 'for-linus' of git://git.kernel.dk/linux-2.6-block: cfq-iosched: fix RCU problem in cfq_cic_lookup() block: make blktrace use per-cpu buffers for message notes Added in elevator switch message to blktrace stream Added in MESSAGE notes for blktraces block: reorder cfq_queue to save space on 64bit builds block: Move the second call to get_request to the end of the loop splice: handle try_to_release_page() failure splice: fix sendfile() issue with relay
Diffstat (limited to 'fs')
-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,
*/
wait_on_page_writeback(page);
- if (PagePrivate(page))
- try_to_release_page(page, GFP_KERNEL);
+ if (PagePrivate(page) && !try_to_release_page(page, GFP_KERNEL))
+ goto out_unlock;
/*
* 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,
* Raced with truncate or failed to remove page from current
* address space, unlock and return failure.
*/
+out_unlock:
unlock_page(page);
return 1;
}
@@ -983,7 +984,7 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
while (len) {
size_t read_len;
- loff_t pos = sd->pos;
+ loff_t pos = sd->pos, prev_pos = pos;
ret = do_splice_to(in, &pos, pipe, len, flags);
if (unlikely(ret <= 0))
@@ -998,15 +999,19 @@ ssize_t splice_direct_to_actor(struct file *in, struct splice_desc *sd,
* could get stuck data in the internal pipe:
*/
ret = actor(pipe, sd);
- if (unlikely(ret <= 0))
+ if (unlikely(ret <= 0)) {
+ sd->pos = prev_pos;
goto out_release;
+ }
bytes += ret;
len -= ret;
sd->pos = pos;
- if (ret < read_len)
+ if (ret < read_len) {
+ sd->pos = prev_pos + ret;
goto out_release;
+ }
}
done:
@@ -1072,7 +1077,7 @@ long do_splice_direct(struct file *in, loff_t *ppos, struct file *out,
ret = splice_direct_to_actor(in, &sd, direct_splice_actor);
if (ret > 0)
- *ppos += ret;
+ *ppos = sd.pos;
return ret;
}