Commit 35edec1d authored by Mark Fasheh's avatar Mark Fasheh

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: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent d0c7d708
...@@ -5668,9 +5668,9 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh) ...@@ -5668,9 +5668,9 @@ static int ocfs2_ordered_zero_func(handle_t *handle, struct buffer_head *bh)
return ocfs2_journal_dirty_data(handle, bh); return ocfs2_journal_dirty_data(handle, bh);
} }
static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t start,
struct page **pages, int numpages, loff_t end, struct page **pages,
u64 phys, handle_t *handle) int numpages, u64 phys, handle_t *handle)
{ {
int i, ret, partial = 0; int i, ret, partial = 0;
void *kaddr; void *kaddr;
...@@ -5683,26 +5683,14 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, ...@@ -5683,26 +5683,14 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
if (numpages == 0) if (numpages == 0)
goto out; goto out;
from = isize & (PAGE_CACHE_SIZE - 1); /* 1st page offset */ to = PAGE_CACHE_SIZE;
if (PAGE_CACHE_SHIFT > OCFS2_SB(sb)->s_clustersize_bits) {
/*
* Since 'from' has been capped to a value below page
* size, this calculation won't be able to overflow
* 'to'
*/
to = ocfs2_align_bytes_to_clusters(sb, from);
/*
* The truncate tail in this case should never contain
* more than one page at maximum. The loop below also
* assumes this.
*/
BUG_ON(numpages != 1);
}
for(i = 0; i < numpages; i++) { for(i = 0; i < numpages; i++) {
page = pages[i]; page = pages[i];
from = start & (PAGE_CACHE_SIZE - 1);
if ((end >> PAGE_CACHE_SHIFT) == page->index)
to = end & (PAGE_CACHE_SIZE - 1);
BUG_ON(from > PAGE_CACHE_SIZE); BUG_ON(from > PAGE_CACHE_SIZE);
BUG_ON(to > PAGE_CACHE_SIZE); BUG_ON(to > PAGE_CACHE_SIZE);
...@@ -5739,10 +5727,7 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, ...@@ -5739,10 +5727,7 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
flush_dcache_page(page); flush_dcache_page(page);
/* start = (page->index + 1) << PAGE_CACHE_SHIFT;
* Every page after the 1st one should be completely zero'd.
*/
from = 0;
} }
out: out:
if (pages) { if (pages) {
...@@ -5755,24 +5740,26 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize, ...@@ -5755,24 +5740,26 @@ static void ocfs2_zero_cluster_pages(struct inode *inode, loff_t isize,
} }
} }
static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page **pages, static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
int *num, u64 *phys) struct page **pages, int *num, u64 *phys)
{ {
int i, numpages = 0, ret = 0; int i, numpages = 0, ret = 0;
unsigned int csize = OCFS2_SB(inode->i_sb)->s_clustersize;
unsigned int ext_flags; unsigned int ext_flags;
struct super_block *sb = inode->i_sb; struct super_block *sb = inode->i_sb;
struct address_space *mapping = inode->i_mapping; struct address_space *mapping = inode->i_mapping;
unsigned long index; unsigned long index;
u64 next_cluster_bytes; loff_t last_page_bytes;
BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb))); BUG_ON(!ocfs2_sparse_alloc(OCFS2_SB(sb)));
BUG_ON(start > end);
/* Cluster boundary, so we don't need to grab any pages. */ if (start == end)
if ((isize & (csize - 1)) == 0)
goto out; goto out;
ret = ocfs2_extent_map_get_blocks(inode, isize >> sb->s_blocksize_bits, BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
(end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
ret = ocfs2_extent_map_get_blocks(inode, start >> sb->s_blocksize_bits,
phys, NULL, &ext_flags); phys, NULL, &ext_flags);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
...@@ -5788,8 +5775,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page * ...@@ -5788,8 +5775,8 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page *
if (ext_flags & OCFS2_EXT_UNWRITTEN) if (ext_flags & OCFS2_EXT_UNWRITTEN)
goto out; goto out;
next_cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, isize); last_page_bytes = PAGE_ALIGN(end);
index = isize >> PAGE_CACHE_SHIFT; index = start >> PAGE_CACHE_SHIFT;
do { do {
pages[numpages] = grab_cache_page(mapping, index); pages[numpages] = grab_cache_page(mapping, index);
if (!pages[numpages]) { if (!pages[numpages]) {
...@@ -5800,7 +5787,7 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page * ...@@ -5800,7 +5787,7 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page *
numpages++; numpages++;
index++; index++;
} while (index < (next_cluster_bytes >> PAGE_CACHE_SHIFT)); } while (index < (last_page_bytes >> PAGE_CACHE_SHIFT));
out: out:
if (ret != 0) { if (ret != 0) {
...@@ -5829,11 +5816,10 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page * ...@@ -5829,11 +5816,10 @@ static int ocfs2_grab_eof_pages(struct inode *inode, loff_t isize, struct page *
* otherwise block_write_full_page() will skip writeout of pages past * otherwise block_write_full_page() will skip writeout of pages past
* i_size. The new_i_size parameter is passed for this reason. * i_size. The new_i_size parameter is passed for this reason.
*/ */
int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
u64 new_i_size) u64 range_start, u64 range_end)
{ {
int ret, numpages; int ret, numpages;
loff_t endbyte;
struct page **pages = NULL; struct page **pages = NULL;
u64 phys; u64 phys;
...@@ -5852,7 +5838,8 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, ...@@ -5852,7 +5838,8 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
goto out; goto out;
} }
ret = ocfs2_grab_eof_pages(inode, new_i_size, pages, &numpages, &phys); ret = ocfs2_grab_eof_pages(inode, range_start, range_end, pages,
&numpages, &phys);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out; goto out;
...@@ -5861,17 +5848,16 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, ...@@ -5861,17 +5848,16 @@ int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle,
if (numpages == 0) if (numpages == 0)
goto out; goto out;
ocfs2_zero_cluster_pages(inode, new_i_size, pages, numpages, phys, ocfs2_zero_cluster_pages(inode, range_start, range_end, pages,
handle); numpages, phys, handle);
/* /*
* Initiate writeout of the pages we zero'd here. We don't * Initiate writeout of the pages we zero'd here. We don't
* wait on them - the truncate_inode_pages() call later will * wait on them - the truncate_inode_pages() call later will
* do that for us. * do that for us.
*/ */
endbyte = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size); ret = do_sync_mapping_range(inode->i_mapping, range_start,
ret = do_sync_mapping_range(inode->i_mapping, new_i_size, range_end - 1, SYNC_FILE_RANGE_WRITE);
endbyte - 1, SYNC_FILE_RANGE_WRITE);
if (ret) if (ret)
mlog_errno(ret); mlog_errno(ret);
......
...@@ -95,8 +95,8 @@ struct ocfs2_truncate_context { ...@@ -95,8 +95,8 @@ struct ocfs2_truncate_context {
struct buffer_head *tc_last_eb_bh; struct buffer_head *tc_last_eb_bh;
}; };
int ocfs2_zero_tail_for_truncate(struct inode *inode, handle_t *handle, int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
u64 new_i_size); u64 range_start, u64 range_end);
int ocfs2_prepare_truncate(struct ocfs2_super *osb, int ocfs2_prepare_truncate(struct ocfs2_super *osb,
struct inode *inode, struct inode *inode,
struct buffer_head *fe_bh, struct buffer_head *fe_bh,
......
...@@ -263,6 +263,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, ...@@ -263,6 +263,7 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
int status; int status;
handle_t *handle; handle_t *handle;
struct ocfs2_dinode *di; struct ocfs2_dinode *di;
u64 cluster_bytes;
mlog_entry_void(); mlog_entry_void();
...@@ -286,7 +287,9 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb, ...@@ -286,7 +287,9 @@ static int ocfs2_orphan_for_truncate(struct ocfs2_super *osb,
/* /*
* Do this before setting i_size. * Do this before setting i_size.
*/ */
status = ocfs2_zero_tail_for_truncate(inode, handle, new_i_size); cluster_bytes = ocfs2_align_bytes_to_clusters(inode->i_sb, new_i_size);
status = ocfs2_zero_range_for_truncate(inode, handle, new_i_size,
cluster_bytes);
if (status) { if (status) {
mlog_errno(status); mlog_errno(status);
goto out_commit; goto out_commit;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment