diff options
author | Chris Mason <chris.mason@oracle.com> | 2009-04-15 13:22:38 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-04-16 10:47:49 -0400 |
commit | 35c80d5f400f68f2eccf3069d1c068e154bde9c9 (patch) | |
tree | 43dd3ebb3e654b1a1ed4210089b7dc27b1f516e9 | |
parent | f69955855eac55a048d26a1618f50dfaa160a006 (diff) |
Add block_write_full_page_endio for passing endio handler
block_write_full_page doesn't allow the caller to control what happens
when the IO is over. This adds a new call named block_write_full_page_endio
so the buffer head end_io handler can be provided by the caller.
This will be used by the ext3 data=guarded mode to do i_size updates in
a workqueue based end_io handler. end_buffer_async_write is also
exported so it can be called to do the dirty work of managing page
writeback for the higher level end_io handler.
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Acked-by: Theodore Tso <tytso@mit.edu>
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/buffer.c | 45 | ||||
-rw-r--r-- | include/linux/buffer_head.h | 3 |
2 files changed, 37 insertions, 11 deletions
diff --git a/fs/buffer.c b/fs/buffer.c index ff8bb1f2333a..b3e5be7514f5 100644 --- a/fs/buffer.c +++ b/fs/buffer.c | |||
@@ -360,7 +360,7 @@ still_busy: | |||
360 | * Completion handler for block_write_full_page() - pages which are unlocked | 360 | * Completion handler for block_write_full_page() - pages which are unlocked |
361 | * during I/O, and which have PageWriteback cleared upon I/O completion. | 361 | * during I/O, and which have PageWriteback cleared upon I/O completion. |
362 | */ | 362 | */ |
363 | static void end_buffer_async_write(struct buffer_head *bh, int uptodate) | 363 | void end_buffer_async_write(struct buffer_head *bh, int uptodate) |
364 | { | 364 | { |
365 | char b[BDEVNAME_SIZE]; | 365 | char b[BDEVNAME_SIZE]; |
366 | unsigned long flags; | 366 | unsigned long flags; |
@@ -438,11 +438,17 @@ static void mark_buffer_async_read(struct buffer_head *bh) | |||
438 | set_buffer_async_read(bh); | 438 | set_buffer_async_read(bh); |
439 | } | 439 | } |
440 | 440 | ||
441 | void mark_buffer_async_write(struct buffer_head *bh) | 441 | void mark_buffer_async_write_endio(struct buffer_head *bh, |
442 | bh_end_io_t *handler) | ||
442 | { | 443 | { |
443 | bh->b_end_io = end_buffer_async_write; | 444 | bh->b_end_io = handler; |
444 | set_buffer_async_write(bh); | 445 | set_buffer_async_write(bh); |
445 | } | 446 | } |
447 | |||
448 | void mark_buffer_async_write(struct buffer_head *bh) | ||
449 | { | ||
450 | mark_buffer_async_write_endio(bh, end_buffer_async_write); | ||
451 | } | ||
446 | EXPORT_SYMBOL(mark_buffer_async_write); | 452 | EXPORT_SYMBOL(mark_buffer_async_write); |
447 | 453 | ||
448 | 454 | ||
@@ -1615,7 +1621,8 @@ EXPORT_SYMBOL(unmap_underlying_metadata); | |||
1615 | * unplugging the device queue. | 1621 | * unplugging the device queue. |
1616 | */ | 1622 | */ |
1617 | static int __block_write_full_page(struct inode *inode, struct page *page, | 1623 | static int __block_write_full_page(struct inode *inode, struct page *page, |
1618 | get_block_t *get_block, struct writeback_control *wbc) | 1624 | get_block_t *get_block, struct writeback_control *wbc, |
1625 | bh_end_io_t *handler) | ||
1619 | { | 1626 | { |
1620 | int err; | 1627 | int err; |
1621 | sector_t block; | 1628 | sector_t block; |
@@ -1700,7 +1707,7 @@ static int __block_write_full_page(struct inode *inode, struct page *page, | |||
1700 | continue; | 1707 | continue; |
1701 | } | 1708 | } |
1702 | if (test_clear_buffer_dirty(bh)) { | 1709 | if (test_clear_buffer_dirty(bh)) { |
1703 | mark_buffer_async_write(bh); | 1710 | mark_buffer_async_write_endio(bh, handler); |
1704 | } else { | 1711 | } else { |
1705 | unlock_buffer(bh); | 1712 | unlock_buffer(bh); |
1706 | } | 1713 | } |
@@ -1753,7 +1760,7 @@ recover: | |||
1753 | if (buffer_mapped(bh) && buffer_dirty(bh) && | 1760 | if (buffer_mapped(bh) && buffer_dirty(bh) && |
1754 | !buffer_delay(bh)) { | 1761 | !buffer_delay(bh)) { |
1755 | lock_buffer(bh); | 1762 | lock_buffer(bh); |
1756 | mark_buffer_async_write(bh); | 1763 | mark_buffer_async_write_endio(bh, handler); |
1757 | } else { | 1764 | } else { |
1758 | /* | 1765 | /* |
1759 | * The buffer may have been set dirty during | 1766 | * The buffer may have been set dirty during |
@@ -2679,7 +2686,8 @@ int nobh_writepage(struct page *page, get_block_t *get_block, | |||
2679 | out: | 2686 | out: |
2680 | ret = mpage_writepage(page, get_block, wbc); | 2687 | ret = mpage_writepage(page, get_block, wbc); |
2681 | if (ret == -EAGAIN) | 2688 | if (ret == -EAGAIN) |
2682 | ret = __block_write_full_page(inode, page, get_block, wbc); | 2689 | ret = __block_write_full_page(inode, page, get_block, wbc, |
2690 | end_buffer_async_write); | ||
2683 | return ret; | 2691 | return ret; |
2684 | } | 2692 | } |
2685 | EXPORT_SYMBOL(nobh_writepage); | 2693 | EXPORT_SYMBOL(nobh_writepage); |
@@ -2837,9 +2845,10 @@ out: | |||
2837 | 2845 | ||
2838 | /* | 2846 | /* |
2839 | * The generic ->writepage function for buffer-backed address_spaces | 2847 | * The generic ->writepage function for buffer-backed address_spaces |
2848 | * this form passes in the end_io handler used to finish the IO. | ||
2840 | */ | 2849 | */ |
2841 | int block_write_full_page(struct page *page, get_block_t *get_block, | 2850 | int block_write_full_page_endio(struct page *page, get_block_t *get_block, |
2842 | struct writeback_control *wbc) | 2851 | struct writeback_control *wbc, bh_end_io_t *handler) |
2843 | { | 2852 | { |
2844 | struct inode * const inode = page->mapping->host; | 2853 | struct inode * const inode = page->mapping->host; |
2845 | loff_t i_size = i_size_read(inode); | 2854 | loff_t i_size = i_size_read(inode); |
@@ -2848,7 +2857,8 @@ int block_write_full_page(struct page *page, get_block_t *get_block, | |||
2848 | 2857 | ||
2849 | /* Is the page fully inside i_size? */ | 2858 | /* Is the page fully inside i_size? */ |
2850 | if (page->index < end_index) | 2859 | if (page->index < end_index) |
2851 | return __block_write_full_page(inode, page, get_block, wbc); | 2860 | return __block_write_full_page(inode, page, get_block, wbc, |
2861 | handler); | ||
2852 | 2862 | ||
2853 | /* Is the page fully outside i_size? (truncate in progress) */ | 2863 | /* Is the page fully outside i_size? (truncate in progress) */ |
2854 | offset = i_size & (PAGE_CACHE_SIZE-1); | 2864 | offset = i_size & (PAGE_CACHE_SIZE-1); |
@@ -2871,9 +2881,20 @@ int block_write_full_page(struct page *page, get_block_t *get_block, | |||
2871 | * writes to that region are not written out to the file." | 2881 | * writes to that region are not written out to the file." |
2872 | */ | 2882 | */ |
2873 | zero_user_segment(page, offset, PAGE_CACHE_SIZE); | 2883 | zero_user_segment(page, offset, PAGE_CACHE_SIZE); |
2874 | return __block_write_full_page(inode, page, get_block, wbc); | 2884 | return __block_write_full_page(inode, page, get_block, wbc, handler); |
2875 | } | 2885 | } |
2876 | 2886 | ||
2887 | /* | ||
2888 | * The generic ->writepage function for buffer-backed address_spaces | ||
2889 | */ | ||
2890 | int block_write_full_page(struct page *page, get_block_t *get_block, | ||
2891 | struct writeback_control *wbc) | ||
2892 | { | ||
2893 | return block_write_full_page_endio(page, get_block, wbc, | ||
2894 | end_buffer_async_write); | ||
2895 | } | ||
2896 | |||
2897 | |||
2877 | sector_t generic_block_bmap(struct address_space *mapping, sector_t block, | 2898 | sector_t generic_block_bmap(struct address_space *mapping, sector_t block, |
2878 | get_block_t *get_block) | 2899 | get_block_t *get_block) |
2879 | { | 2900 | { |
@@ -3342,9 +3363,11 @@ EXPORT_SYMBOL(block_read_full_page); | |||
3342 | EXPORT_SYMBOL(block_sync_page); | 3363 | EXPORT_SYMBOL(block_sync_page); |
3343 | EXPORT_SYMBOL(block_truncate_page); | 3364 | EXPORT_SYMBOL(block_truncate_page); |
3344 | EXPORT_SYMBOL(block_write_full_page); | 3365 | EXPORT_SYMBOL(block_write_full_page); |
3366 | EXPORT_SYMBOL(block_write_full_page_endio); | ||
3345 | EXPORT_SYMBOL(cont_write_begin); | 3367 | EXPORT_SYMBOL(cont_write_begin); |
3346 | EXPORT_SYMBOL(end_buffer_read_sync); | 3368 | EXPORT_SYMBOL(end_buffer_read_sync); |
3347 | EXPORT_SYMBOL(end_buffer_write_sync); | 3369 | EXPORT_SYMBOL(end_buffer_write_sync); |
3370 | EXPORT_SYMBOL(end_buffer_async_write); | ||
3348 | EXPORT_SYMBOL(file_fsync); | 3371 | EXPORT_SYMBOL(file_fsync); |
3349 | EXPORT_SYMBOL(generic_block_bmap); | 3372 | EXPORT_SYMBOL(generic_block_bmap); |
3350 | EXPORT_SYMBOL(generic_cont_expand_simple); | 3373 | EXPORT_SYMBOL(generic_cont_expand_simple); |
diff --git a/include/linux/buffer_head.h b/include/linux/buffer_head.h index 7b73bb8f1970..16ed0284d780 100644 --- a/include/linux/buffer_head.h +++ b/include/linux/buffer_head.h | |||
@@ -155,6 +155,7 @@ void create_empty_buffers(struct page *, unsigned long, | |||
155 | unsigned long b_state); | 155 | unsigned long b_state); |
156 | void end_buffer_read_sync(struct buffer_head *bh, int uptodate); | 156 | void end_buffer_read_sync(struct buffer_head *bh, int uptodate); |
157 | void end_buffer_write_sync(struct buffer_head *bh, int uptodate); | 157 | void end_buffer_write_sync(struct buffer_head *bh, int uptodate); |
158 | void end_buffer_async_write(struct buffer_head *bh, int uptodate); | ||
158 | 159 | ||
159 | /* Things to do with buffers at mapping->private_list */ | 160 | /* Things to do with buffers at mapping->private_list */ |
160 | void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode); | 161 | void mark_buffer_dirty_inode(struct buffer_head *bh, struct inode *inode); |
@@ -197,6 +198,8 @@ extern int buffer_heads_over_limit; | |||
197 | void block_invalidatepage(struct page *page, unsigned long offset); | 198 | void block_invalidatepage(struct page *page, unsigned long offset); |
198 | int block_write_full_page(struct page *page, get_block_t *get_block, | 199 | int block_write_full_page(struct page *page, get_block_t *get_block, |
199 | struct writeback_control *wbc); | 200 | struct writeback_control *wbc); |
201 | int block_write_full_page_endio(struct page *page, get_block_t *get_block, | ||
202 | struct writeback_control *wbc, bh_end_io_t *handler); | ||
200 | int block_read_full_page(struct page*, get_block_t*); | 203 | int block_read_full_page(struct page*, get_block_t*); |
201 | int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc, | 204 | int block_is_partially_uptodate(struct page *page, read_descriptor_t *desc, |
202 | unsigned long from); | 205 | unsigned long from); |