aboutsummaryrefslogtreecommitdiffstats
path: root/fs/splice.c
diff options
context:
space:
mode:
authorJens Axboe <axboe@suse.de>2006-04-02 17:04:46 -0400
committerJens Axboe <axboe@suse.de>2006-04-02 17:04:46 -0400
commit4f6f0bd2ffa4e31c3524f5e65c84a29b6ab73307 (patch)
tree682ab1b41c3ee799d37bfa1874c79ae92b3755fd /fs/splice.c
parent53cd9ae886273d6c2b8ba4aa63d6cd6b1217b57f (diff)
[PATCH] splice: improve writeback and clean up page stealing
By cleaning up the writeback logic (killing write_one_page() and the manual set_page_dirty()), we can get rid of ->stolen inside the pipe_buffer and just keep it local in pipe_to_file(). This also adds dirty page balancing logic and O_SYNC handling. Signed-off-by: Jens Axboe <axboe@suse.de>
Diffstat (limited to 'fs/splice.c')
-rw-r--r--fs/splice.c64
1 files changed, 48 insertions, 16 deletions
diff --git a/fs/splice.c b/fs/splice.c
index a555d0a83fe9..07f4d863c2d4 100644
--- a/fs/splice.c
+++ b/fs/splice.c
@@ -22,7 +22,10 @@
22#include <linux/pipe_fs_i.h> 22#include <linux/pipe_fs_i.h>
23#include <linux/mm_inline.h> 23#include <linux/mm_inline.h>
24#include <linux/swap.h> 24#include <linux/swap.h>
25#include <linux/writeback.h>
26#include <linux/buffer_head.h>
25#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/syscalls.h>
26 29
27/* 30/*
28 * Passed to the actors 31 * Passed to the actors
@@ -38,11 +41,15 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
38 struct pipe_buffer *buf) 41 struct pipe_buffer *buf)
39{ 42{
40 struct page *page = buf->page; 43 struct page *page = buf->page;
44 struct address_space *mapping = page_mapping(page);
41 45
42 WARN_ON(!PageLocked(page)); 46 WARN_ON(!PageLocked(page));
43 WARN_ON(!PageUptodate(page)); 47 WARN_ON(!PageUptodate(page));
44 48
45 if (!remove_mapping(page_mapping(page), page)) 49 if (PagePrivate(page))
50 try_to_release_page(page, mapping_gfp_mask(mapping));
51
52 if (!remove_mapping(mapping, page))
46 return 1; 53 return 1;
47 54
48 if (PageLRU(page)) { 55 if (PageLRU(page)) {
@@ -55,7 +62,6 @@ static int page_cache_pipe_buf_steal(struct pipe_inode_info *info,
55 spin_unlock_irq(&zone->lru_lock); 62 spin_unlock_irq(&zone->lru_lock);
56 } 63 }
57 64
58 buf->stolen = 1;
59 return 0; 65 return 0;
60} 66}
61 67
@@ -64,7 +70,6 @@ static void page_cache_pipe_buf_release(struct pipe_inode_info *info,
64{ 70{
65 page_cache_release(buf->page); 71 page_cache_release(buf->page);
66 buf->page = NULL; 72 buf->page = NULL;
67 buf->stolen = 0;
68} 73}
69 74
70static void *page_cache_pipe_buf_map(struct file *file, 75static void *page_cache_pipe_buf_map(struct file *file,
@@ -91,8 +96,7 @@ static void *page_cache_pipe_buf_map(struct file *file,
91static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, 96static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info,
92 struct pipe_buffer *buf) 97 struct pipe_buffer *buf)
93{ 98{
94 if (!buf->stolen) 99 unlock_page(buf->page);
95 unlock_page(buf->page);
96 kunmap(buf->page); 100 kunmap(buf->page);
97} 101}
98 102
@@ -319,7 +323,8 @@ ssize_t generic_file_splice_read(struct file *in, struct inode *pipe,
319} 323}
320 324
321/* 325/*
322 * Send 'len' bytes to socket from 'file' at position 'pos' using sendpage(). 326 * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos'
327 * using sendpage().
323 */ 328 */
324static int pipe_to_sendpage(struct pipe_inode_info *info, 329static int pipe_to_sendpage(struct pipe_inode_info *info,
325 struct pipe_buffer *buf, struct splice_desc *sd) 330 struct pipe_buffer *buf, struct splice_desc *sd)
@@ -379,7 +384,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
379 struct page *page; 384 struct page *page;
380 pgoff_t index; 385 pgoff_t index;
381 char *src; 386 char *src;
382 int ret; 387 int ret, stolen;
383 388
384 /* 389 /*
385 * after this, page will be locked and unmapped 390 * after this, page will be locked and unmapped
@@ -390,6 +395,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
390 395
391 index = sd->pos >> PAGE_CACHE_SHIFT; 396 index = sd->pos >> PAGE_CACHE_SHIFT;
392 offset = sd->pos & ~PAGE_CACHE_MASK; 397 offset = sd->pos & ~PAGE_CACHE_MASK;
398 stolen = 0;
393 399
394 /* 400 /*
395 * reuse buf page, if SPLICE_F_MOVE is set 401 * reuse buf page, if SPLICE_F_MOVE is set
@@ -399,6 +405,7 @@ static int pipe_to_file(struct pipe_inode_info *info, struct pipe_buffer *buf,
399 goto find_page; 405 goto find_page;
400 406
401 page = buf->page; 407 page = buf->page;
408 stolen = 1;
402 if (add_to_page_cache_lru(page, mapping, index, 409 if (add_to_page_cache_lru(page, mapping, index,
403 mapping_gfp_mask(mapping))) 410 mapping_gfp_mask(mapping)))
404 goto find_page; 411 goto find_page;
@@ -443,10 +450,13 @@ find_page:
443 } 450 }
444 451
445 ret = mapping->a_ops->prepare_write(file, page, 0, sd->len); 452 ret = mapping->a_ops->prepare_write(file, page, 0, sd->len);
446 if (ret) 453 if (ret == AOP_TRUNCATED_PAGE) {
454 page_cache_release(page);
455 goto find_page;
456 } else if (ret)
447 goto out; 457 goto out;
448 458
449 if (!buf->stolen) { 459 if (!stolen) {
450 char *dst = kmap_atomic(page, KM_USER0); 460 char *dst = kmap_atomic(page, KM_USER0);
451 461
452 memcpy(dst + offset, src + buf->offset, sd->len); 462 memcpy(dst + offset, src + buf->offset, sd->len);
@@ -455,16 +465,18 @@ find_page:
455 } 465 }
456 466
457 ret = mapping->a_ops->commit_write(file, page, 0, sd->len); 467 ret = mapping->a_ops->commit_write(file, page, 0, sd->len);
458 if (ret < 0) 468 if (ret == AOP_TRUNCATED_PAGE) {
469 page_cache_release(page);
470 goto find_page;
471 } else if (ret)
459 goto out; 472 goto out;
460 473
461 set_page_dirty(page); 474 balance_dirty_pages_ratelimited(mapping);
462 ret = write_one_page(page, 0);
463out: 475out:
464 if (ret < 0) 476 if (!stolen) {
465 unlock_page(page);
466 if (!buf->stolen)
467 page_cache_release(page); 477 page_cache_release(page);
478 unlock_page(page);
479 }
468 buf->ops->unmap(info, buf); 480 buf->ops->unmap(info, buf);
469 return ret; 481 return ret;
470} 482}
@@ -576,7 +588,27 @@ static ssize_t move_from_pipe(struct inode *inode, struct file *out,
576ssize_t generic_file_splice_write(struct inode *inode, struct file *out, 588ssize_t generic_file_splice_write(struct inode *inode, struct file *out,
577 size_t len, unsigned int flags) 589 size_t len, unsigned int flags)
578{ 590{
579 return move_from_pipe(inode, out, len, flags, pipe_to_file); 591 struct address_space *mapping = out->f_mapping;
592 ssize_t ret = move_from_pipe(inode, out, len, flags, pipe_to_file);
593
594 /*
595 * if file or inode is SYNC and we actually wrote some data, sync it
596 */
597 if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(mapping->host))
598 && ret > 0) {
599 struct inode *inode = mapping->host;
600 int err;
601
602 mutex_lock(&inode->i_mutex);
603 err = generic_osync_inode(mapping->host, mapping,
604 OSYNC_METADATA|OSYNC_DATA);
605 mutex_unlock(&inode->i_mutex);
606
607 if (err)
608 ret = err;
609 }
610
611 return ret;
580} 612}
581 613
582ssize_t generic_splice_sendpage(struct inode *inode, struct file *out, 614ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,