Commit e7432675 authored by Sunil Mushran's avatar Sunil Mushran Committed by Joel Becker

ocfs2: Initialize the cluster we're writing to in a non-sparse extend

In a non-sparse extend, we correctly allocate (and zero) the clusters between
the old_i_size and pos, but we don't zero the portions of the cluster we're
writing to outside of pos<->len.

It handles clustersize > pagesize and blocksize < pagesize.

[Cleaned up by Joel Becker.]
Signed-off-by: default avatarSunil Mushran <sunil.mushran@oracle.com>
Signed-off-by: default avatarJoel Becker <joel.becker@oracle.com>
parent ab57a408
...@@ -895,18 +895,17 @@ struct ocfs2_write_cluster_desc { ...@@ -895,18 +895,17 @@ struct ocfs2_write_cluster_desc {
*/ */
unsigned c_new; unsigned c_new;
unsigned c_unwritten; unsigned c_unwritten;
unsigned c_needs_zero;
}; };
static inline int ocfs2_should_zero_cluster(struct ocfs2_write_cluster_desc *d)
{
return d->c_new || d->c_unwritten;
}
struct ocfs2_write_ctxt { struct ocfs2_write_ctxt {
/* Logical cluster position / len of write */ /* Logical cluster position / len of write */
u32 w_cpos; u32 w_cpos;
u32 w_clen; u32 w_clen;
/* First cluster allocated in a nonsparse extend */
u32 w_first_new_cpos;
struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE]; struct ocfs2_write_cluster_desc w_desc[OCFS2_MAX_CLUSTERS_PER_PAGE];
/* /*
...@@ -984,6 +983,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp, ...@@ -984,6 +983,7 @@ static int ocfs2_alloc_write_ctxt(struct ocfs2_write_ctxt **wcp,
return -ENOMEM; return -ENOMEM;
wc->w_cpos = pos >> osb->s_clustersize_bits; wc->w_cpos = pos >> osb->s_clustersize_bits;
wc->w_first_new_cpos = UINT_MAX;
cend = (pos + len - 1) >> osb->s_clustersize_bits; cend = (pos + len - 1) >> osb->s_clustersize_bits;
wc->w_clen = cend - wc->w_cpos + 1; wc->w_clen = cend - wc->w_cpos + 1;
get_bh(di_bh); get_bh(di_bh);
...@@ -1218,20 +1218,18 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping, ...@@ -1218,20 +1218,18 @@ static int ocfs2_grab_pages_for_write(struct address_space *mapping,
*/ */
static int ocfs2_write_cluster(struct address_space *mapping, static int ocfs2_write_cluster(struct address_space *mapping,
u32 phys, unsigned int unwritten, u32 phys, unsigned int unwritten,
unsigned int should_zero,
struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *data_ac,
struct ocfs2_alloc_context *meta_ac, struct ocfs2_alloc_context *meta_ac,
struct ocfs2_write_ctxt *wc, u32 cpos, struct ocfs2_write_ctxt *wc, u32 cpos,
loff_t user_pos, unsigned user_len) loff_t user_pos, unsigned user_len)
{ {
int ret, i, new, should_zero = 0; int ret, i, new;
u64 v_blkno, p_blkno; u64 v_blkno, p_blkno;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
struct ocfs2_extent_tree et; struct ocfs2_extent_tree et;
new = phys == 0 ? 1 : 0; new = phys == 0 ? 1 : 0;
if (new || unwritten)
should_zero = 1;
if (new) { if (new) {
u32 tmp_pos; u32 tmp_pos;
...@@ -1342,7 +1340,9 @@ static int ocfs2_write_cluster_by_desc(struct address_space *mapping, ...@@ -1342,7 +1340,9 @@ static int ocfs2_write_cluster_by_desc(struct address_space *mapping,
local_len = osb->s_clustersize - cluster_off; local_len = osb->s_clustersize - cluster_off;
ret = ocfs2_write_cluster(mapping, desc->c_phys, ret = ocfs2_write_cluster(mapping, desc->c_phys,
desc->c_unwritten, data_ac, meta_ac, desc->c_unwritten,
desc->c_needs_zero,
data_ac, meta_ac,
wc, desc->c_cpos, pos, local_len); wc, desc->c_cpos, pos, local_len);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
...@@ -1392,14 +1392,14 @@ static void ocfs2_set_target_boundaries(struct ocfs2_super *osb, ...@@ -1392,14 +1392,14 @@ static void ocfs2_set_target_boundaries(struct ocfs2_super *osb,
* newly allocated cluster. * newly allocated cluster.
*/ */
desc = &wc->w_desc[0]; desc = &wc->w_desc[0];
if (ocfs2_should_zero_cluster(desc)) if (desc->c_needs_zero)
ocfs2_figure_cluster_boundaries(osb, ocfs2_figure_cluster_boundaries(osb,
desc->c_cpos, desc->c_cpos,
&wc->w_target_from, &wc->w_target_from,
NULL); NULL);
desc = &wc->w_desc[wc->w_clen - 1]; desc = &wc->w_desc[wc->w_clen - 1];
if (ocfs2_should_zero_cluster(desc)) if (desc->c_needs_zero)
ocfs2_figure_cluster_boundaries(osb, ocfs2_figure_cluster_boundaries(osb,
desc->c_cpos, desc->c_cpos,
NULL, NULL,
...@@ -1467,13 +1467,28 @@ static int ocfs2_populate_write_desc(struct inode *inode, ...@@ -1467,13 +1467,28 @@ static int ocfs2_populate_write_desc(struct inode *inode,
phys++; phys++;
} }
/*
* If w_first_new_cpos is < UINT_MAX, we have a non-sparse
* file that got extended. w_first_new_cpos tells us
* where the newly allocated clusters are so we can
* zero them.
*/
if (desc->c_cpos >= wc->w_first_new_cpos) {
BUG_ON(phys == 0);
desc->c_needs_zero = 1;
}
desc->c_phys = phys; desc->c_phys = phys;
if (phys == 0) { if (phys == 0) {
desc->c_new = 1; desc->c_new = 1;
desc->c_needs_zero = 1;
*clusters_to_alloc = *clusters_to_alloc + 1; *clusters_to_alloc = *clusters_to_alloc + 1;
} }
if (ext_flags & OCFS2_EXT_UNWRITTEN)
if (ext_flags & OCFS2_EXT_UNWRITTEN) {
desc->c_unwritten = 1; desc->c_unwritten = 1;
desc->c_needs_zero = 1;
}
num_clusters--; num_clusters--;
} }
...@@ -1633,10 +1648,13 @@ static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos, ...@@ -1633,10 +1648,13 @@ static int ocfs2_expand_nonsparse_inode(struct inode *inode, loff_t pos,
if (newsize <= i_size_read(inode)) if (newsize <= i_size_read(inode))
return 0; return 0;
ret = ocfs2_extend_no_holes(inode, newsize, newsize - len); ret = ocfs2_extend_no_holes(inode, newsize, pos);
if (ret) if (ret)
mlog_errno(ret); mlog_errno(ret);
wc->w_first_new_cpos =
ocfs2_clusters_for_bytes(inode->i_sb, i_size_read(inode));
return ret; return ret;
} }
...@@ -1645,7 +1663,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -1645,7 +1663,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
struct page **pagep, void **fsdata, struct page **pagep, void **fsdata,
struct buffer_head *di_bh, struct page *mmap_page) struct buffer_head *di_bh, struct page *mmap_page)
{ {
int ret, credits = OCFS2_INODE_UPDATE_CREDITS; int ret, cluster_of_pages, credits = OCFS2_INODE_UPDATE_CREDITS;
unsigned int clusters_to_alloc, extents_to_split; unsigned int clusters_to_alloc, extents_to_split;
struct ocfs2_write_ctxt *wc; struct ocfs2_write_ctxt *wc;
struct inode *inode = mapping->host; struct inode *inode = mapping->host;
...@@ -1723,8 +1741,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -1723,8 +1741,19 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
} }
ocfs2_set_target_boundaries(osb, wc, pos, len, /*
clusters_to_alloc + extents_to_split); * We have to zero sparse allocated clusters, unwritten extent clusters,
* and non-sparse clusters we just extended. For non-sparse writes,
* we know zeros will only be needed in the first and/or last cluster.
*/
if (clusters_to_alloc || extents_to_split ||
wc->w_desc[0].c_needs_zero ||
wc->w_desc[wc->w_clen - 1].c_needs_zero)
cluster_of_pages = 1;
else
cluster_of_pages = 0;
ocfs2_set_target_boundaries(osb, wc, pos, len, cluster_of_pages);
handle = ocfs2_start_trans(osb, credits); handle = ocfs2_start_trans(osb, credits);
if (IS_ERR(handle)) { if (IS_ERR(handle)) {
...@@ -1757,8 +1786,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping, ...@@ -1757,8 +1786,7 @@ int ocfs2_write_begin_nolock(struct address_space *mapping,
* extent. * extent.
*/ */
ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos, ret = ocfs2_grab_pages_for_write(mapping, wc, wc->w_cpos, pos,
clusters_to_alloc + extents_to_split, cluster_of_pages, mmap_page);
mmap_page);
if (ret) { if (ret) {
mlog_errno(ret); mlog_errno(ret);
goto out_quota; goto out_quota;
......
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