diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-09-07 17:20:45 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-10-12 14:54:35 -0400 |
commit | 1d410a6e337a0d2d5543ad1d9bccb670a7a05312 (patch) | |
tree | 696f70750482a4a49b61c79e6499659ddb3635b4 | |
parent | 65ed39d6ca78f07d2958814e08440e4264b6b488 (diff) |
ocfs2: Small refactor of truncate zeroing code
We'll want to reuse most of this when pushing inline data back out to an
extent. Keeping this part as a seperate patch helps to keep the upcoming
changes for write support uncluttered.
The core portion of ocfs2_zero_cluster_pages() responsible for making sure a
page is mapped and properly dirtied is abstracted out into it's own
function, ocfs2_map_and_dirty_page(). Actual functionality doesn't change,
though zeroing becomes optional.
We also turn part of ocfs2_free_write_ctxt() into a common function for
unlocking and freeing a page array. This operation is very common (and
uniform) for Ocfs2 cluster sizes greater than page size, so it makes sense
to keep the code in one place.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Reviewed-by: Joel Becker <joel.becker@oracle.com>
-rw-r--r-- | fs/ocfs2/alloc.c | 151 | ||||
-rw-r--r-- | fs/ocfs2/aops.c | 20 | ||||
-rw-r--r-- | fs/ocfs2/aops.h | 2 |
3 files changed, 86 insertions, 87 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index c91706f949ff..c81bfdfb9929 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -5633,12 +5633,50 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) | |||
5633 | return ocfs2_journal_dirty_data(handle, bh); | 5633 | return ocfs2_journal_dirty_data(handle, bh); |
5634 | } | 5634 | } |
5635 | 5635 | ||
5636 | static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle, | ||
5637 | unsigned int from, unsigned int to, | ||
5638 | struct page *page, int zero, u64 *phys) | ||
5639 | { | ||
5640 | int ret, partial = 0; | ||
5641 | |||
5642 | ret = ocfs2_map_page_blocks(page, phys, inode, from, to, 0); | ||
5643 | if (ret) | ||
5644 | mlog_errno(ret); | ||
5645 | |||
5646 | if (zero) | ||
5647 | zero_user_page(page, from, to - from, KM_USER0); | ||
5648 | |||
5649 | /* | ||
5650 | * Need to set the buffers we zero'd into uptodate | ||
5651 | * here if they aren't - ocfs2_map_page_blocks() | ||
5652 | * might've skipped some | ||
5653 | */ | ||
5654 | if (ocfs2_should_order_data(inode)) { | ||
5655 | ret = walk_page_buffers(handle, | ||
5656 | page_buffers(page), | ||
5657 | from, to, &partial, | ||
5658 | ocfs2_ordered_zero_func); | ||
5659 | if (ret < 0) | ||
5660 | mlog_errno(ret); | ||
5661 | } else { | ||
5662 | ret = walk_page_buffers(handle, page_buffers(page), | ||
5663 | from, to, &partial, | ||
5664 | ocfs2_writeback_zero_func); | ||
5665 | if (ret < 0) | ||
5666 | mlog_errno(ret); | ||
5667 | } | ||
5668 | |||
5669 | if (!partial) | ||
5670 | SetPageUptodate(page); | ||
5671 | |||
5672 | flush_dcache_page(page); | ||
5673 | } | ||
5674 | |||
5636 | static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, | 5675 | static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, |
5637 | loff_t end, struct page **pages, | 5676 | loff_t end, struct page **pages, |
5638 | int numpages, u64 phys, handle_t *handle) | 5677 | int numpages, u64 phys, handle_t *handle) |
5639 | { | 5678 | { |
5640 | int i, ret, partial = 0; | 5679 | int i; |
5641 | void *kaddr; | ||
5642 | struct page *page; | 5680 | struct page *page; |
5643 | unsigned int from, to = PAGE_CACHE_SIZE; | 5681 | unsigned int from, to = PAGE_CACHE_SIZE; |
5644 | struct super_block *sb = inode->i_sb; | 5682 | struct super_block *sb = inode->i_sb; |
@@ -5659,87 +5697,31 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, | |||
5659 | BUG_ON(from > PAGE_CACHE_SIZE); | 5697 | BUG_ON(from > PAGE_CACHE_SIZE); |
5660 | BUG_ON(to > PAGE_CACHE_SIZE); | 5698 | BUG_ON(to > PAGE_CACHE_SIZE); |
5661 | 5699 | ||
5662 | ret = ocfs2_map_page_blocks(page, &phys, inode, from, to, 0); | 5700 | ocfs2_map_and_dirty_page(inode, handle, from, to, page, 1, |
5663 | if (ret) | 5701 | &phys); |
5664 | mlog_errno(ret); | ||
5665 | |||
5666 | kaddr = kmap_atomic(page, KM_USER0); | ||
5667 | memset(kaddr + from, 0, to - from); | ||
5668 | kunmap_atomic(kaddr, KM_USER0); | ||
5669 | |||
5670 | /* | ||
5671 | * Need to set the buffers we zero'd into uptodate | ||
5672 | * here if they aren't - ocfs2_map_page_blocks() | ||
5673 | * might've skipped some | ||
5674 | */ | ||
5675 | if (ocfs2_should_order_data(inode)) { | ||
5676 | ret = walk_page_buffers(handle, | ||
5677 | page_buffers(page), | ||
5678 | from, to, &partial, | ||
5679 | ocfs2_ordered_zero_func); | ||
5680 | if (ret < 0) | ||
5681 | mlog_errno(ret); | ||
5682 | } else { | ||
5683 | ret = walk_page_buffers(handle, page_buffers(page), | ||
5684 | from, to, &partial, | ||
5685 | ocfs2_writeback_zero_func); | ||
5686 | if (ret < 0) | ||
5687 | mlog_errno(ret); | ||
5688 | } | ||
5689 | |||
5690 | if (!partial) | ||
5691 | SetPageUptodate(page); | ||
5692 | |||
5693 | flush_dcache_page(page); | ||
5694 | 5702 | ||
5695 | start = (page->index + 1) << PAGE_CACHE_SHIFT; | 5703 | start = (page->index + 1) << PAGE_CACHE_SHIFT; |
5696 | } | 5704 | } |
5697 | out: | 5705 | out: |
5698 | if (pages) { | 5706 | if (pages) |
5699 | for (i = 0; i < numpages; i++) { | 5707 | ocfs2_unlock_and_free_pages(pages, numpages); |
5700 | page = pages[i]; | ||
5701 | unlock_page(page); | ||
5702 | mark_page_accessed(page); | ||
5703 | page_cache_release(page); | ||
5704 | } | ||
5705 | } | ||
5706 | } | 5708 | } |
5707 | 5709 | ||
5708 | static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, | 5710 | static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, |
5709 | struct page **pages, int *num, u64 *phys) | 5711 | struct page **pages, int *num) |
5710 | { | 5712 | { |
5711 | int i, numpages = 0, ret = 0; | 5713 | int numpages, ret = 0; |
5712 | unsigned int ext_flags; | ||
5713 | struct super_block *sb = inode->i_sb; | 5714 | struct super_block *sb = inode->i_sb; |
5714 | struct address_space *mapping = inode->i_mapping; | 5715 | struct address_space *mapping = inode->i_mapping; |
5715 | unsigned long index; | 5716 | unsigned long index; |
5716 | loff_t last_page_bytes; | 5717 | loff_t last_page_bytes; |
5717 | 5718 | ||
5718 | BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); | ||
5719 | BUG_ON(start > end); | 5719 | BUG_ON(start > end); |
5720 | 5720 | ||
5721 | if (start == end) | ||
5722 | goto out; | ||
5723 | |||
5724 | BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits != | 5721 | BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits != |
5725 | (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits); | 5722 | (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits); |
5726 | 5723 | ||
5727 | ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits, | 5724 | numpages = 0; |
5728 | phys, NULL, &ext_flags); | ||
5729 | if (ret) { | ||
5730 | mlog_errno(ret); | ||
5731 | goto out; | ||
5732 | } | ||
5733 | |||
5734 | /* Tail is a hole. */ | ||
5735 | if (*phys == 0) | ||
5736 | goto out; | ||
5737 | |||
5738 | /* Tail is marked as unwritten, we can count on write to zero | ||
5739 | * in that case. */ | ||
5740 | if (ext_flags & OCFS2_EXT_UNWRITTEN) | ||
5741 | goto out; | ||
5742 | |||
5743 | last_page_bytes = PAGE_ALIGN(end); | 5725 | last_page_bytes = PAGE_ALIGN(end); |
5744 | index = start >> PAGE_CACHE_SHIFT; | 5726 | index = start >> PAGE_CACHE_SHIFT; |
5745 | do { | 5727 | do { |
@@ -5756,14 +5738,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, | |||
5756 | 5738 | ||
5757 | out: | 5739 | out: |
5758 | if (ret != 0) { | 5740 | if (ret != 0) { |
5759 | if (pages) { | 5741 | if (pages) |
5760 | for (i = 0; i < numpages; i++) { | 5742 | ocfs2_unlock_and_free_pages(pages, numpages); |
5761 | if (pages[i]) { | ||
5762 | unlock_page(pages[i]); | ||
5763 | page_cache_release(pages[i]); | ||
5764 | } | ||
5765 | } | ||
5766 | } | ||
5767 | numpages = 0; | 5743 | numpages = 0; |
5768 | } | 5744 | } |
5769 | 5745 | ||
@@ -5784,18 +5760,20 @@ out: | |||
5784 | int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, | 5760 | int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, |
5785 | u64 range_start, u64 range_end) | 5761 | u64 range_start, u64 range_end) |
5786 | { | 5762 | { |
5787 | int ret, numpages; | 5763 | int ret = 0, numpages; |
5788 | struct page **pages = NULL; | 5764 | struct page **pages = NULL; |
5789 | u64 phys; | 5765 | u64 phys; |
5766 | unsigned int ext_flags; | ||
5767 | struct super_block *sb = inode->i_sb; | ||
5790 | 5768 | ||
5791 | /* | 5769 | /* |
5792 | * File systems which don't support sparse files zero on every | 5770 | * File systems which don't support sparse files zero on every |
5793 | * extend. | 5771 | * extend. |
5794 | */ | 5772 | */ |
5795 | if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) | 5773 | if (!ocfs2_sparse_alloc(OCFS2_SB(sb))) |
5796 | return 0; | 5774 | return 0; |
5797 | 5775 | ||
5798 | pages = kcalloc(ocfs2_pages_per_cluster(inode->i_sb), | 5776 | pages = kcalloc(ocfs2_pages_per_cluster(sb), |
5799 | sizeof(struct page *), GFP_NOFS); | 5777 | sizeof(struct page *), GFP_NOFS); |
5800 | if (pages == NULL) { | 5778 | if (pages == NULL) { |
5801 | ret = -ENOMEM; | 5779 | ret = -ENOMEM; |
@@ -5803,15 +5781,30 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, | |||
5803 | goto out; | 5781 | goto out; |
5804 | } | 5782 | } |
5805 | 5783 | ||
5806 | ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, | 5784 | if (range_start == range_end) |
5807 | &numpages, &phys); | 5785 | goto out; |
5786 | |||
5787 | ret = ocfs2_extent_map_get_blocks(inode, | ||
5788 | range_start >> sb->s_blocksize_bits, | ||
5789 | &phys, NULL, &ext_flags); | ||
5808 | if (ret) { | 5790 | if (ret) { |
5809 | mlog_errno(ret); | 5791 | mlog_errno(ret); |
5810 | goto out; | 5792 | goto out; |
5811 | } | 5793 | } |
5812 | 5794 | ||
5813 | if (numpages == 0) | 5795 | /* |
5796 | * Tail is a hole, or is marked unwritten. In either case, we | ||
5797 | * can count on read and write to return/push zero's. | ||
5798 | */ | ||
5799 | if (phys == 0 || ext_flags & OCFS2_EXT_UNWRITTEN) | ||
5800 | goto out; | ||
5801 | |||
5802 | ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, | ||
5803 | &numpages); | ||
5804 | if (ret) { | ||
5805 | mlog_errno(ret); | ||
5814 | goto out; | 5806 | goto out; |
5807 | } | ||
5815 | 5808 | ||
5816 | ocfs2_zero_cluster_pages(inode, range_start, range_end, pages, | 5809 | ocfs2_zero_cluster_pages(inode, range_start, range_end, pages, |
5817 | numpages, phys, handle); | 5810 | numpages, phys, handle); |
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index fae07672eb18..8416e383197c 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c | |||
@@ -830,18 +830,22 @@ struct ocfs2_write_ctxt { | |||
830 | struct ocfs2_cached_dealloc_ctxt w_dealloc; | 830 | struct ocfs2_cached_dealloc_ctxt w_dealloc; |
831 | }; | 831 | }; |
832 | 832 | ||
833 | static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | 833 | void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages) |
834 | { | 834 | { |
835 | int i; | 835 | int i; |
836 | 836 | ||
837 | for(i = 0; i < wc->w_num_pages; i++) { | 837 | for(i = 0; i < num_pages; i++) { |
838 | if (wc->w_pages[i] == NULL) | 838 | if (pages[i]) { |
839 | continue; | 839 | unlock_page(pages[i]); |
840 | 840 | mark_page_accessed(pages[i]); | |
841 | unlock_page(wc->w_pages[i]); | 841 | page_cache_release(pages[i]); |
842 | mark_page_accessed(wc->w_pages[i]); | 842 | } |
843 | page_cache_release(wc->w_pages[i]); | ||
844 | } | 843 | } |
844 | } | ||
845 | |||
846 | static void ocfs2_free_write_ctxt(struct ocfs2_write_ctxt *wc) | ||
847 | { | ||
848 | ocfs2_unlock_and_free_pages(wc->w_pages, wc->w_num_pages); | ||
845 | 849 | ||
846 | brelse(wc->w_di_bh); | 850 | brelse(wc->w_di_bh); |
847 | kfree(wc); | 851 | kfree(wc); |
diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index 389579bd64e3..b4fa37d40db4 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h | |||
@@ -34,6 +34,8 @@ int ocfs2_map_page_blocks(struct page *page, u64 *p_blkno, | |||
34 | struct inode *inode, unsigned int from, | 34 | struct inode *inode, unsigned int from, |
35 | unsigned int to, int new); | 35 | unsigned int to, int new); |
36 | 36 | ||
37 | void ocfs2_unlock_and_free_pages(struct page **pages, int num_pages); | ||
38 | |||
37 | int walk_page_buffers( handle_t *handle, | 39 | int walk_page_buffers( handle_t *handle, |
38 | struct buffer_head *head, | 40 | struct buffer_head *head, |
39 | unsigned from, | 41 | unsigned from, |