Commit 3a0782d0 authored by Mark Fasheh's avatar Mark Fasheh

ocfs2: teach extend/truncate about sparse files

For ocfs2_truncate_file(), we eliminate the "simple" truncate case which no
longer exists since i_size is not tied to i_clusters. In
ocfs2_extend_file(), we skip the allocation / page zeroing code for file
systems which understand sparse files.

The core truncate code is changed to do a bottom up tree traversal. This
gets abstracted out into it's own function. To make things more readable,
most of the special case handling for in-inode extents from
ocfs2_do_truncate() is also removed.

Though write support for sparse files comes in a later patch, we at least
update ocfs2_prepare_inode_for_write() to skip allocation for sparse files.
Signed-off-by: default avatarMark Fasheh <mark.fasheh@oracle.com>
parent 363041a5
This diff is collapsed.
...@@ -344,18 +344,6 @@ static int ocfs2_truncate_file(struct inode *inode, ...@@ -344,18 +344,6 @@ static int ocfs2_truncate_file(struct inode *inode,
} }
ocfs2_data_unlock(inode, 1); ocfs2_data_unlock(inode, 1);
if (le32_to_cpu(fe->i_clusters) ==
ocfs2_clusters_for_bytes(osb->sb, new_i_size)) {
mlog(0, "fe->i_clusters = %u, so we do a simple truncate\n",
fe->i_clusters);
/* No allocation change is required, so lets fast path
* this truncate. */
status = ocfs2_simple_size_update(inode, di_bh, new_i_size);
if (status < 0)
mlog_errno(status);
goto bail;
}
/* alright, we're going to need to do a full blown alloc size /* alright, we're going to need to do a full blown alloc size
* change. Orphan the inode so that recovery can complete the * change. Orphan the inode so that recovery can complete the
* truncate if necessary. This does the task of marking * truncate if necessary. This does the task of marking
...@@ -785,7 +773,7 @@ static int ocfs2_extend_file(struct inode *inode, ...@@ -785,7 +773,7 @@ static int ocfs2_extend_file(struct inode *inode,
size_t tail_to_skip) size_t tail_to_skip)
{ {
int ret = 0; int ret = 0;
u32 clusters_to_add; u32 clusters_to_add = 0;
BUG_ON(!tail_to_skip && !di_bh); BUG_ON(!tail_to_skip && !di_bh);
...@@ -797,6 +785,11 @@ static int ocfs2_extend_file(struct inode *inode, ...@@ -797,6 +785,11 @@ static int ocfs2_extend_file(struct inode *inode,
goto out; goto out;
BUG_ON(new_i_size < i_size_read(inode)); BUG_ON(new_i_size < i_size_read(inode));
if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb))) {
BUG_ON(tail_to_skip != 0);
goto out_update_size;
}
clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) - clusters_to_add = ocfs2_clusters_for_bytes(inode->i_sb, new_i_size) -
OCFS2_I(inode)->ip_clusters; OCFS2_I(inode)->ip_clusters;
...@@ -832,6 +825,7 @@ static int ocfs2_extend_file(struct inode *inode, ...@@ -832,6 +825,7 @@ static int ocfs2_extend_file(struct inode *inode,
goto out_unlock; goto out_unlock;
} }
out_update_size:
if (!tail_to_skip) { if (!tail_to_skip) {
/* We're being called from ocfs2_setattr() which wants /* We're being called from ocfs2_setattr() which wants
* us to update i_size */ * us to update i_size */
...@@ -841,6 +835,7 @@ static int ocfs2_extend_file(struct inode *inode, ...@@ -841,6 +835,7 @@ static int ocfs2_extend_file(struct inode *inode,
} }
out_unlock: out_unlock:
if (!ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
ocfs2_data_unlock(inode, 1); ocfs2_data_unlock(inode, 1);
out: out:
...@@ -1097,6 +1092,14 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry, ...@@ -1097,6 +1092,14 @@ static int ocfs2_prepare_inode_for_write(struct dentry *dentry,
} else { } else {
saved_pos = *ppos; saved_pos = *ppos;
} }
/*
* The rest of this loop is concerned with legacy file
* systems which don't support sparse files.
*/
if (ocfs2_sparse_alloc(OCFS2_SB(inode->i_sb)))
break;
newsize = count + saved_pos; newsize = count + saved_pos;
mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", mlog(0, "pos=%lld newsize=%lld cursize=%lld\n",
......
...@@ -487,7 +487,6 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, ...@@ -487,7 +487,6 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
struct buffer_head *fe_bh) struct buffer_head *fe_bh)
{ {
int status = 0; int status = 0;
handle_t *handle = NULL;
struct ocfs2_truncate_context *tc = NULL; struct ocfs2_truncate_context *tc = NULL;
struct ocfs2_dinode *fe; struct ocfs2_dinode *fe;
...@@ -495,41 +494,20 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb, ...@@ -495,41 +494,20 @@ static int ocfs2_truncate_for_delete(struct ocfs2_super *osb,
fe = (struct ocfs2_dinode *) fe_bh->b_data; fe = (struct ocfs2_dinode *) fe_bh->b_data;
/* zero allocation, zero truncate :) */ if (fe->i_clusters) {
if (!fe->i_clusters)
goto bail;
handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS);
if (IS_ERR(handle)) {
status = PTR_ERR(handle);
handle = NULL;
mlog_errno(status);
goto bail;
}
status = ocfs2_set_inode_size(handle, inode, fe_bh, 0ULL);
if (status < 0) {
mlog_errno(status);
goto bail;
}
ocfs2_commit_trans(osb, handle);
handle = NULL;
status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc); status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto out;
} }
status = ocfs2_commit_truncate(osb, inode, fe_bh, tc); status = ocfs2_commit_truncate(osb, inode, fe_bh, tc);
if (status < 0) { if (status < 0) {
mlog_errno(status); mlog_errno(status);
goto bail; goto out;
} }
bail: }
if (handle) out:
ocfs2_commit_trans(osb, handle);
mlog_exit(status); mlog_exit(status);
return status; return status;
......
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