From 17ee4f49ab2c802c7818fa71c4e7e351a7230b86 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 15 Jun 2007 13:10:37 +0200 Subject: splice: adjust balance_dirty_pages_ratelimited() call As we have potentially dirtied more than 1 page, we should indicate as such to the dirty page balancing. So call balance_dirty_pages_ratelimited_nr() and pass in the approximate number of pages we dirtied. Signed-off-by: Jens Axboe --- fs/splice.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index cb211360273..12d247f6ece 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -811,7 +811,10 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, ret = __splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); if (ret > 0) { + unsigned long nr_pages; + *ppos += ret; + nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* * If file or inode is SYNC and we actually wrote some data, @@ -824,7 +827,7 @@ generic_file_splice_write_nolock(struct pipe_inode_info *pipe, struct file *out, if (err) ret = err; } - balance_dirty_pages_ratelimited(mapping); + balance_dirty_pages_ratelimited_nr(mapping, nr_pages); } return ret; @@ -863,7 +866,10 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, ret = splice_from_pipe(pipe, out, ppos, len, flags, pipe_to_file); if (ret > 0) { + unsigned long nr_pages; + *ppos += ret; + nr_pages = (ret + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT; /* * If file or inode is SYNC and we actually wrote some data, @@ -878,7 +884,7 @@ generic_file_splice_write(struct pipe_inode_info *pipe, struct file *out, if (err) ret = err; } - balance_dirty_pages_ratelimited(mapping); + balance_dirty_pages_ratelimited_nr(mapping, nr_pages); } return ret; -- cgit v1.2.3 From 00de00bdad278783b3664ad2969954a707f5944a Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 15 Jun 2007 13:14:22 +0200 Subject: splice: fix leak of pages on short splice to pipe If the destination pipe is full and we already transferred data, we break out instead of waiting for more pipe room. The exit logic looks at spd->nr_pages to see if we moved everything inside the spd container, but we decrement that variable in the loop to decide when spd has emptied. Instead we want to compare to the original page count in the spd, so cache that in a local variable. Signed-off-by: Jens Axboe --- fs/splice.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/splice.c b/fs/splice.c index 12d247f6ece..186fad463c4 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -176,6 +176,7 @@ static const struct pipe_buf_operations user_page_pipe_buf_ops = { static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, struct splice_pipe_desc *spd) { + unsigned int spd_pages = spd->nr_pages; int ret, do_wakeup, page_nr; ret = 0; @@ -254,7 +255,7 @@ static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); } - while (page_nr < spd->nr_pages) + while (page_nr < spd_pages) page_cache_release(spd->pages[page_nr++]); return ret; -- cgit v1.2.3 From 02676e5aee271c1f20d7d44249d26741aef1e846 Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 15 Jun 2007 13:16:13 +0200 Subject: splice: only check do_wakeup in splice_to_pipe() for a real pipe We only ever set do_wakeup to non-zero if the pipe has an inode backing, so it's pointless to check outside the pipe->inode check. Signed-off-by: Jens Axboe --- fs/splice.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/fs/splice.c b/fs/splice.c index 186fad463c4..e7d7080de2f 100644 --- a/fs/splice.c +++ b/fs/splice.c @@ -245,14 +245,15 @@ static ssize_t splice_to_pipe(struct pipe_inode_info *pipe, pipe->waiting_writers--; } - if (pipe->inode) + if (pipe->inode) { mutex_unlock(&pipe->inode->i_mutex); - if (do_wakeup) { - smp_mb(); - if (waitqueue_active(&pipe->wait)) - wake_up_interruptible(&pipe->wait); - kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + if (do_wakeup) { + smp_mb(); + if (waitqueue_active(&pipe->wait)) + wake_up_interruptible(&pipe->wait); + kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN); + } } while (page_nr < spd_pages) -- cgit v1.2.3