diff options
author | Mark Fasheh <mark.fasheh@oracle.com> | 2007-07-06 17:41:18 -0400 |
---|---|---|
committer | Mark Fasheh <mark.fasheh@oracle.com> | 2007-07-10 20:32:07 -0400 |
commit | 35edec1d52c075975991471d624b33b9336226f2 (patch) | |
tree | 4fc59b9d60826b8eb44bc5c1e558a15bea171193 /fs | |
parent | d0c7d7082ee1ec4f95ee57bf86ed39d1a27c4037 (diff) |
ocfs2: update truncate handling of partial clusters
The partial cluster zeroing code used during truncate usually assumes that
the rightmost byte in the range to be zeroed lies on a cluster boundary.
This makes sense for truncate, but punching holes might require zeroing on
non-aligned rightmost boundaries.
Signed-off-by: Mark Fasheh <mark.fasheh@oracle.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ocfs2/alloc.c | 72 | ||||
-rw-r--r-- | fs/ocfs2/alloc.h | 4 | ||||
-rw-r--r-- | fs/ocfs2/file.c | 5 |
3 files changed, 35 insertions, 46 deletions
diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index fac1adb3880a..df186d2e8248 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c | |||
@@ -5668,9 +5668,9 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) | |||
5668 | return ocfs2_journal_dirty_data(handle, bh); | 5668 | return ocfs2_journal_dirty_data(handle, bh); |
5669 | } | 5669 | } |
5670 | 5670 | ||
5671 | static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, | 5671 | static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start, |
5672 | struct page **pages, int numpages, | 5672 | loff_t end, struct page **pages, |
5673 | u64 phys, handle_t *handle) | 5673 | int numpages, u64 phys, handle_t *handle) |
5674 | { | 5674 | { |
5675 | int i, ret, partial = 0; | 5675 | int i, ret, partial = 0; |
5676 | void *kaddr; | 5676 | void *kaddr; |
@@ -5683,26 +5683,14 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, | |||
5683 | if (numpages == 0) | 5683 | if (numpages == 0) |
5684 | goto out; | 5684 | goto out; |
5685 | 5685 | ||
5686 | from = isize & (PAGE_CACHE_SIZE - 1); /* 1st page offset */ | 5686 | to = PAGE_CACHE_SIZE; |
5687 | if (PAGE_CACHE_SHIFT > OCFS2_SB(sb)->s_clustersize_bits) { | ||
5688 | /* | ||
5689 | * Since 'from' has been capped to a value below page | ||
5690 | * size, this calculation won't be able to overflow | ||
5691 | * 'to' | ||
5692 | */ | ||
5693 | to = ocfs2_align_bytes_to_clusters(sb, from); | ||
5694 | |||
5695 | /* | ||
5696 | * The truncate tail in this case should never contain | ||
5697 | * more than one page at maximum. The loop below also | ||
5698 | * assumes this. | ||
5699 | */ | ||
5700 | BUG_ON(numpages != 1); | ||
5701 | } | ||
5702 | |||
5703 | for(i = 0; i < numpages; i++) { | 5687 | for(i = 0; i < numpages; i++) { |
5704 | page = pages[i]; | 5688 | page = pages[i]; |
5705 | 5689 | ||
5690 | from = start & (PAGE_CACHE_SIZE - 1); | ||
5691 | if ((end >> PAGE_CACHE_SHIFT) == page->index) | ||
5692 | to = end & (PAGE_CACHE_SIZE - 1); | ||
5693 | |||
5706 | BUG_ON(from > PAGE_CACHE_SIZE); | 5694 | BUG_ON(from > PAGE_CACHE_SIZE); |
5707 | BUG_ON(to > PAGE_CACHE_SIZE); | 5695 | BUG_ON(to > PAGE_CACHE_SIZE); |
5708 | 5696 | ||
@@ -5739,10 +5727,7 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, | |||
5739 | 5727 | ||
5740 | flush_dcache_page(page); | 5728 | flush_dcache_page(page); |
5741 | 5729 | ||
5742 | /* | 5730 | start = (page->index + 1) << PAGE_CACHE_SHIFT; |
5743 | * Every page after the 1st one should be completely zero'd. | ||
5744 | */ | ||
5745 | from = 0; | ||
5746 | } | 5731 | } |
5747 | out: | 5732 | out: |
5748 | if (pages) { | 5733 | if (pages) { |
@@ -5755,24 +5740,26 @@ out: | |||
5755 | } | 5740 | } |
5756 | } | 5741 | } |
5757 | 5742 | ||
5758 | static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page **pages, | 5743 | static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end, |
5759 | int *num, u64 *phys) | 5744 | struct page **pages, int *num, u64 *phys) |
5760 | { | 5745 | { |
5761 | int i, numpages = 0, ret = 0; | 5746 | int i, numpages = 0, ret = 0; |
5762 | unsigned int csize = OCFS2_SB(inode->i_sb)->s_clustersize; | ||
5763 | unsigned int ext_flags; | 5747 | unsigned int ext_flags; |
5764 | struct super_block *sb = inode->i_sb; | 5748 | struct super_block *sb = inode->i_sb; |
5765 | struct address_space *mapping = inode->i_mapping; | 5749 | struct address_space *mapping = inode->i_mapping; |
5766 | unsigned long index; | 5750 | unsigned long index; |
5767 | u64 next_cluster_bytes; | 5751 | loff_t last_page_bytes; |
5768 | 5752 | ||
5769 | BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); | 5753 | BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); |
5754 | BUG_ON(start > end); | ||
5770 | 5755 | ||
5771 | /* Cluster boundary, so we don't need to grab any pages. */ | 5756 | if (start == end) |
5772 | if ((isize & (csize - 1)) == 0) | ||
5773 | goto out; | 5757 | goto out; |
5774 | 5758 | ||
5775 | ret = ocfs2_extent_map_get_blocks(inode, isize >> sb->s_blocksize_bits, | 5759 | BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits != |
5760 | (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits); | ||
5761 | |||
5762 | ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits, | ||
5776 | phys, NULL, &ext_flags); | 5763 | phys, NULL, &ext_flags); |
5777 | if (ret) { | 5764 | if (ret) { |
5778 | mlog_errno(ret); | 5765 | mlog_errno(ret); |
@@ -5788,8 +5775,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page * | |||
5788 | if (ext_flags & OCFS2_EXT_UNWRITTEN) | 5775 | if (ext_flags & OCFS2_EXT_UNWRITTEN) |
5789 | goto out; | 5776 | goto out; |
5790 | 5777 | ||
5791 | next_cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, isize); | 5778 | last_page_bytes = PAGE_ALIGN(end); |
5792 | index = isize >> PAGE_CACHE_SHIFT; | 5779 | index = start >> PAGE_CACHE_SHIFT; |
5793 | do { | 5780 | do { |
5794 | pages[numpages] = grab_cache_page(mapping, index); | 5781 | pages[numpages] = grab_cache_page(mapping, index); |
5795 | if (!pages[numpages]) { | 5782 | if (!pages[numpages]) { |
@@ -5800,7 +5787,7 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page * | |||
5800 | 5787 | ||
5801 | numpages++; | 5788 | numpages++; |
5802 | index++; | 5789 | index++; |
5803 | } while (index < (next_cluster_bytes >> PAGE_CACHE_SHIFT)); | 5790 | } while (index < (last_page_bytes >> PAGE_CACHE_SHIFT)); |
5804 | 5791 | ||
5805 | out: | 5792 | out: |
5806 | if (ret != 0) { | 5793 | if (ret != 0) { |
@@ -5829,11 +5816,10 @@ out: | |||
5829 | * otherwise block_write_full_page() will skip writeout of pages past | 5816 | * otherwise block_write_full_page() will skip writeout of pages past |
5830 | * i_size. The new_i_size parameter is passed for this reason. | 5817 | * i_size. The new_i_size parameter is passed for this reason. |
5831 | */ | 5818 | */ |
5832 | int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, | 5819 | int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, |
5833 | u64 new_i_size) | 5820 | u64 range_start, u64 range_end) |
5834 | { | 5821 | { |
5835 | int ret, numpages; | 5822 | int ret, numpages; |
5836 | loff_t endbyte; | ||
5837 | struct page **pages = NULL; | 5823 | struct page **pages = NULL; |
5838 | u64 phys; | 5824 | u64 phys; |
5839 | 5825 | ||
@@ -5852,7 +5838,8 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, | |||
5852 | goto out; | 5838 | goto out; |
5853 | } | 5839 | } |
5854 | 5840 | ||
5855 | ret = ocfs2_grab_eof_pages(inode, new_i_size, pages, &numpages, &phys); | 5841 | ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages, |
5842 | &numpages, &phys); | ||
5856 | if (ret) { | 5843 | if (ret) { |
5857 | mlog_errno(ret); | 5844 | mlog_errno(ret); |
5858 | goto out; | 5845 | goto out; |
@@ -5861,17 +5848,16 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, | |||
5861 | if (numpages == 0) | 5848 | if (numpages == 0) |
5862 | goto out; | 5849 | goto out; |
5863 | 5850 | ||
5864 | ocfs2_zero_cluster_pages(inode, new_i_size, pages, numpages, phys, | 5851 | ocfs2_zero_cluster_pages(inode, range_start, range_end, pages, |
5865 | handle); | 5852 | numpages, phys, handle); |
5866 | 5853 | ||
5867 | /* | 5854 | /* |
5868 | * Initiate writeout of the pages we zero'd here. We don't | 5855 | * Initiate writeout of the pages we zero'd here. We don't |
5869 | * wait on them - the truncate_inode_pages() call later will | 5856 | * wait on them - the truncate_inode_pages() call later will |
5870 | * do that for us. | 5857 | * do that for us. |
5871 | */ | 5858 | */ |
5872 | endbyte = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size); | 5859 | ret = do_sync_mapping_range(inode->i_mapping, range_start, |
5873 | ret = do_sync_mapping_range(inode->i_mapping, new_i_size, | 5860 | range_end - 1, SYNC_FILE_RANGE_WRITE); |
5874 | endbyte - 1, SYNC_FILE_RANGE_WRITE); | ||
5875 | if (ret) | 5861 | if (ret) |
5876 | mlog_errno(ret); | 5862 | mlog_errno(ret); |
5877 | 5863 | ||
diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index e3284f3eb6b9..752ef860873d 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h | |||
@@ -95,8 +95,8 @@ struct ocfs2_truncate_context { | |||
95 | struct buffer_head *tc_last_eb_bh; | 95 | struct buffer_head *tc_last_eb_bh; |
96 | }; | 96 | }; |
97 | 97 | ||
98 | int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, | 98 | int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle, |
99 | u64 new_i_size); | 99 | u64 range_start, u64 range_end); |
100 | int ocfs2_prepare_truncate(struct ocfs2_super *osb, | 100 | int ocfs2_prepare_truncate(struct ocfs2_super *osb, |
101 | struct inode *inode, | 101 | struct inode *inode, |
102 | struct buffer_head *fe_bh, | 102 | struct buffer_head *fe_bh, |
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 3e21ad9a6dde..f0a6b1330a6e 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c | |||
@@ -263,6 +263,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, | |||
263 | int status; | 263 | int status; |
264 | handle_t *handle; | 264 | handle_t *handle; |
265 | struct ocfs2_dinode *di; | 265 | struct ocfs2_dinode *di; |
266 | u64 cluster_bytes; | ||
266 | 267 | ||
267 | mlog_entry_void(); | 268 | mlog_entry_void(); |
268 | 269 | ||
@@ -286,7 +287,9 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, | |||
286 | /* | 287 | /* |
287 | * Do this before setting i_size. | 288 | * Do this before setting i_size. |
288 | */ | 289 | */ |
289 | status = ocfs2_zero_tail_for_truncate(inode, handle, new_i_size); | 290 | cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size); |
291 | status = ocfs2_zero_range_for_truncate(inode, handle, new_i_size, | ||
292 | cluster_bytes); | ||
290 | if (status) { | 293 | if (status) { |
291 | mlog_errno(status); | 294 | mlog_errno(status); |
292 | goto out_commit; | 295 | goto out_commit; |