[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>

+48 -18
-1
fs/pipe.c
··· 124 static int anon_pipe_buf_steal(struct pipe_inode_info *info, 125 struct pipe_buffer *buf) 126 { 127 - buf->stolen = 1; 128 return 0; 129 } 130
··· 124 static int anon_pipe_buf_steal(struct pipe_inode_info *info, 125 struct pipe_buffer *buf) 126 { 127 return 0; 128 } 129
+48 -16
fs/splice.c
··· 22 #include <linux/pipe_fs_i.h> 23 #include <linux/mm_inline.h> 24 #include <linux/swap.h> 25 #include <linux/module.h> 26 27 /* 28 * Passed to the actors ··· 41 struct pipe_buffer *buf) 42 { 43 struct page *page = buf->page; 44 45 WARN_ON(!PageLocked(page)); 46 WARN_ON(!PageUptodate(page)); 47 48 - if (!remove_mapping(page_mapping(page), page)) 49 return 1; 50 51 if (PageLRU(page)) { ··· 62 spin_unlock_irq(&zone->lru_lock); 63 } 64 65 - buf->stolen = 1; 66 return 0; 67 } 68 ··· 70 { 71 page_cache_release(buf->page); 72 buf->page = NULL; 73 - buf->stolen = 0; 74 } 75 76 static void *page_cache_pipe_buf_map(struct file *file, ··· 96 static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, 97 struct pipe_buffer *buf) 98 { 99 - if (!buf->stolen) 100 - unlock_page(buf->page); 101 kunmap(buf->page); 102 } 103 ··· 323 } 324 325 /* 326 - * Send 'len' bytes to socket from 'file' at position 'pos' using sendpage(). 327 */ 328 static int pipe_to_sendpage(struct pipe_inode_info *info, 329 struct pipe_buffer *buf, struct splice_desc *sd) ··· 384 struct page *page; 385 pgoff_t index; 386 char *src; 387 - int ret; 388 389 /* 390 * after this, page will be locked and unmapped ··· 395 396 index = sd->pos >> PAGE_CACHE_SHIFT; 397 offset = sd->pos & ~PAGE_CACHE_MASK; 398 399 /* 400 * reuse buf page, if SPLICE_F_MOVE is set ··· 405 goto find_page; 406 407 page = buf->page; 408 if (add_to_page_cache_lru(page, mapping, index, 409 mapping_gfp_mask(mapping))) 410 goto find_page; ··· 450 } 451 452 ret = mapping->a_ops->prepare_write(file, page, 0, sd->len); 453 - if (ret) 454 goto out; 455 456 - if (!buf->stolen) { 457 char *dst = kmap_atomic(page, KM_USER0); 458 459 memcpy(dst + offset, src + buf->offset, sd->len); ··· 465 } 466 467 ret = mapping->a_ops->commit_write(file, page, 0, sd->len); 468 - if (ret < 0) 469 goto out; 470 471 - set_page_dirty(page); 472 - ret = write_one_page(page, 0); 473 out: 474 - if (ret < 0) 475 - unlock_page(page); 476 - if (!buf->stolen) 477 page_cache_release(page); 478 buf->ops->unmap(info, buf); 479 return ret; 480 } ··· 588 ssize_t generic_file_splice_write(struct inode *inode, struct file *out, 589 size_t len, unsigned int flags) 590 { 591 - return move_from_pipe(inode, out, len, flags, pipe_to_file); 592 } 593 594 ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,
··· 22 #include <linux/pipe_fs_i.h> 23 #include <linux/mm_inline.h> 24 #include <linux/swap.h> 25 + #include <linux/writeback.h> 26 + #include <linux/buffer_head.h> 27 #include <linux/module.h> 28 + #include <linux/syscalls.h> 29 30 /* 31 * Passed to the actors ··· 38 struct pipe_buffer *buf) 39 { 40 struct page *page = buf->page; 41 + struct address_space *mapping = page_mapping(page); 42 43 WARN_ON(!PageLocked(page)); 44 WARN_ON(!PageUptodate(page)); 45 46 + if (PagePrivate(page)) 47 + try_to_release_page(page, mapping_gfp_mask(mapping)); 48 + 49 + if (!remove_mapping(mapping, page)) 50 return 1; 51 52 if (PageLRU(page)) { ··· 55 spin_unlock_irq(&zone->lru_lock); 56 } 57 58 return 0; 59 } 60 ··· 64 { 65 page_cache_release(buf->page); 66 buf->page = NULL; 67 } 68 69 static void *page_cache_pipe_buf_map(struct file *file, ··· 91 static void page_cache_pipe_buf_unmap(struct pipe_inode_info *info, 92 struct pipe_buffer *buf) 93 { 94 + unlock_page(buf->page); 95 kunmap(buf->page); 96 } 97 ··· 319 } 320 321 /* 322 + * Send 'sd->len' bytes to socket from 'sd->file' at position 'sd->pos' 323 + * using sendpage(). 324 */ 325 static int pipe_to_sendpage(struct pipe_inode_info *info, 326 struct pipe_buffer *buf, struct splice_desc *sd) ··· 379 struct page *page; 380 pgoff_t index; 381 char *src; 382 + int ret, stolen; 383 384 /* 385 * after this, page will be locked and unmapped ··· 390 391 index = sd->pos >> PAGE_CACHE_SHIFT; 392 offset = sd->pos & ~PAGE_CACHE_MASK; 393 + stolen = 0; 394 395 /* 396 * reuse buf page, if SPLICE_F_MOVE is set ··· 399 goto find_page; 400 401 page = buf->page; 402 + stolen = 1; 403 if (add_to_page_cache_lru(page, mapping, index, 404 mapping_gfp_mask(mapping))) 405 goto find_page; ··· 443 } 444 445 ret = mapping->a_ops->prepare_write(file, page, 0, sd->len); 446 + if (ret == AOP_TRUNCATED_PAGE) { 447 + page_cache_release(page); 448 + goto find_page; 449 + } else if (ret) 450 goto out; 451 452 + if (!stolen) { 453 char *dst = kmap_atomic(page, KM_USER0); 454 455 memcpy(dst + offset, src + buf->offset, sd->len); ··· 455 } 456 457 ret = mapping->a_ops->commit_write(file, page, 0, sd->len); 458 + if (ret == AOP_TRUNCATED_PAGE) { 459 + page_cache_release(page); 460 + goto find_page; 461 + } else if (ret) 462 goto out; 463 464 + balance_dirty_pages_ratelimited(mapping); 465 out: 466 + if (!stolen) { 467 page_cache_release(page); 468 + unlock_page(page); 469 + } 470 buf->ops->unmap(info, buf); 471 return ret; 472 } ··· 576 ssize_t generic_file_splice_write(struct inode *inode, struct file *out, 577 size_t len, unsigned int flags) 578 { 579 + struct address_space *mapping = out->f_mapping; 580 + ssize_t ret = move_from_pipe(inode, out, len, flags, pipe_to_file); 581 + 582 + /* 583 + * if file or inode is SYNC and we actually wrote some data, sync it 584 + */ 585 + if (unlikely((out->f_flags & O_SYNC) || IS_SYNC(mapping->host)) 586 + && ret > 0) { 587 + struct inode *inode = mapping->host; 588 + int err; 589 + 590 + mutex_lock(&inode->i_mutex); 591 + err = generic_osync_inode(mapping->host, mapping, 592 + OSYNC_METADATA|OSYNC_DATA); 593 + mutex_unlock(&inode->i_mutex); 594 + 595 + if (err) 596 + ret = err; 597 + } 598 + 599 + return ret; 600 } 601 602 ssize_t generic_splice_sendpage(struct inode *inode, struct file *out,
-1
include/linux/pipe_fs_i.h
··· 9 struct page *page; 10 unsigned int offset, len; 11 struct pipe_buf_operations *ops; 12 - unsigned int stolen; 13 }; 14 15 struct pipe_buf_operations {
··· 9 struct page *page; 10 unsigned int offset, len; 11 struct pipe_buf_operations *ops; 12 }; 13 14 struct pipe_buf_operations {