[Ocfs2-devel] [PATCH 3/3] Ocfs2: Treat ocfs2 truncate as a special case of punching holes.
TaoMa
tao.ma at oracle.com
Wed Jan 27 14:41:19 PST 2010
Tristan Ye wrote:
> As we known, truncate is just a special case of punching holes(from new i_size
> to end), we therefore could take advantage of existing ocfs2_remove_btree_range()
> codes to reduce the comlexity and redundancy in alloc.c, the goal here is to make
> truncate codes more generic and straightforward.
>
> Several former functions only used by ocfs2_commit_truncate() will be simply wiped off.
> New logic for truncating will remove extents from truncate_size to file end one by one,
> just like punching holes did.
>
> v2 patch uses former sequence of records truncating(from tail to new_i_size) which keeps
> a high efficiency in performance, also, it has the refcount support as well.
>
> Signed-off-by: Tristan Ye <tristan.ye at oracle.com>
> ---
> fs/ocfs2/alloc.c | 556 +++++------------------------------------------------
> fs/ocfs2/alloc.h | 3 +-
> fs/ocfs2/file.c | 9 +-
> fs/ocfs2/inode.c | 9 +-
> 4 files changed, 56 insertions(+), 521 deletions(-)
>
> diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c
> index 6c5f1de..0c42003 100644
> --- a/fs/ocfs2/alloc.c
> +++ b/fs/ocfs2/alloc.c
>
> @@ -7422,21 +6999,25 @@ out:
> */
> int ocfs2_commit_truncate(struct ocfs2_super *osb,
> struct inode *inode,
> - struct buffer_head *fe_bh,
> - struct ocfs2_truncate_context *tc)
> + struct buffer_head *fe_bh)
> {
> - int status, i, credits, tl_sem = 0;
> - u32 clusters_to_del, new_highest_cpos, range;
> + int status = 0, i, credits = 0, ref_blocks = 0, flags = 0;
> + u32 new_highest_cpos, range, trunc_cpos, trunc_len, phys_cpos, coff;
> u64 blkno = 0;
> struct ocfs2_extent_list *el;
> - handle_t *handle = NULL;
> - struct inode *tl_inode = osb->osb_tl_inode;
> + struct ocfs2_extent_rec *rec;
> struct ocfs2_path *path = NULL;
> struct ocfs2_dinode *di = (struct ocfs2_dinode *)fe_bh->b_data;
> - struct ocfs2_alloc_context *meta_ac = NULL;
> +
> + struct ocfs2_extent_tree et;
> + struct ocfs2_cached_dealloc_ctxt dealloc;
> +
> struct ocfs2_refcount_tree *ref_tree = NULL;
>
> mlog_entry_void();
> +
> + ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), fe_bh);
> + ocfs2_init_dealloc_ctxt(&dealloc);
>
> new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
> i_size_read(inode));
> @@ -7449,8 +7030,6 @@ int ocfs2_commit_truncate(struct ocfs2_super *osb,
> goto bail;
> }
>
> - ocfs2_extent_map_trunc(inode, new_highest_cpos);
> -
>
Please keep this line. It will truncate the extent map.
> start:
> /*
> * Check that we still have allocation to delete.
> @@ -7461,6 +7040,7 @@ start:
> }
>
> credits = 0;
> + ref_blocks = 0;
>
> /*
> * Truncate always works against the rightmost tree branch.
> @@ -7496,30 +7076,47 @@ start:
> }
>
> i = le16_to_cpu(el->l_next_free_rec) - 1;
> - range = le32_to_cpu(el->l_recs[i].e_cpos) +
> - ocfs2_rec_clusters(el, &el->l_recs[i]);
> - if (i == 0 && ocfs2_is_empty_extent(&el->l_recs[i])) {
> - clusters_to_del = 0;
> - } else if (le32_to_cpu(el->l_recs[i].e_cpos) >= new_highest_cpos) {
> - clusters_to_del = ocfs2_rec_clusters(el, &el->l_recs[i]);
> - blkno = le64_to_cpu(el->l_recs[i].e_blkno);
> + rec = &el->l_recs[i];
> + flags = rec->e_flags;
> + range = le32_to_cpu(rec->e_cpos) + ocfs2_rec_clusters(el, rec);
> +
> + if (i == 0 && ocfs2_is_empty_extent(rec)) {
> + /*
> + * Should remove this extent block.
> + */
> + trunc_cpos = le32_to_cpu(rec->e_cpos);
> + trunc_len = 0;
> + coff = 0;
> + blkno = 0;
> + } else if (le32_to_cpu(rec->e_cpos) >= new_highest_cpos) {
> + /*
> + * Truncate entire record.
> + */
> + trunc_cpos = le32_to_cpu(rec->e_cpos);
> + trunc_len = ocfs2_rec_clusters(el, rec);
> + coff = 0;
> + blkno = le64_to_cpu(rec->e_blkno);
> } else if (range > new_highest_cpos) {
> - clusters_to_del = (ocfs2_rec_clusters(el, &el->l_recs[i]) +
> - le32_to_cpu(el->l_recs[i].e_cpos)) -
> - new_highest_cpos;
> - blkno = le64_to_cpu(el->l_recs[i].e_blkno) +
> - ocfs2_clusters_to_blocks(inode->i_sb,
> - ocfs2_rec_clusters(el, &el->l_recs[i]) -
> - clusters_to_del);
> + /*
> + * Partial truncate. it also should be
> + * the last truncate we're doing.
> + */
> + trunc_cpos = new_highest_cpos;
> + trunc_len = range - new_highest_cpos;
> + coff = new_highest_cpos - le32_to_cpu(rec->e_cpos);
> + blkno = le64_to_cpu(rec->e_blkno) +
> + ocfs2_clusters_to_blocks(inode->i_sb, coff);
>
another reason you want to change clusters_to_del to trunc_len? The
calcuation is the same.
> } else {
> + /*
> + * Truncate completed, leave happily.
> + */
> status = 0;
> goto bail;
> }
>
> - mlog(0, "clusters_to_del = %u in this pass, tail blk=%llu\n",
> - clusters_to_del, (unsigned long long)path_leaf_bh(path)->b_blocknr);
> + phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
>
> - if (el->l_recs[i].e_flags & OCFS2_EXT_REFCOUNTED && clusters_to_del) {
> + if (el->l_recs[i].e_flags & OCFS2_EXT_REFCOUNTED && trunc_len) {
> BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
> OCFS2_HAS_REFCOUNT_FL));
>
> @@ -7533,59 +7130,25 @@ start:
>
> status = ocfs2_prepare_refcount_change_for_del(inode, fe_bh,
> blkno,
> - clusters_to_del,
> + trunc_len,
> &credits,
> - &meta_ac);
>
As I said in the previous e-mail, we may add this function to the
ocfs2_remove_btree_range.
And what's more, we don't need to fixing punching hole any more since
this function can handle refcount tree by itself.
> - if (status < 0) {
> - mlog_errno(status);
> - goto bail;
> - }
> - }
> -
> - mutex_lock(&tl_inode->i_mutex);
> - tl_sem = 1;
> - /* ocfs2_truncate_log_needs_flush guarantees us at least one
> - * record is free for use. If there isn't any, we flush to get
> - * an empty truncate log. */
> - if (ocfs2_truncate_log_needs_flush(osb)) {
> - status = __ocfs2_flush_truncate_log(osb);
> + &ref_blocks);
> if (status < 0) {
> mlog_errno(status);
> goto bail;
> }
> }
>
> - credits += ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del,
> - (struct ocfs2_dinode *)fe_bh->b_data,
> - el);
> - handle = ocfs2_start_trans(osb, credits);
> - if (IS_ERR(handle)) {
> - status = PTR_ERR(handle);
> - handle = NULL;
> - mlog_errno(status);
> - goto bail;
> - }
> -
> - status = ocfs2_do_truncate(osb, clusters_to_del, inode, fe_bh, handle,
> - tc, path, meta_ac);
> + status = ocfs2_remove_btree_range(inode, &et, trunc_cpos, phys_cpos,
> + trunc_len, &dealloc, credits,
> + ref_blocks, flags);
> if (status < 0) {
> mlog_errno(status);
> goto bail;
> }
> -
> - mutex_unlock(&tl_inode->i_mutex);
> - tl_sem = 0;
> -
> - ocfs2_commit_trans(osb, handle);
> - handle = NULL;
> -
> +
> ocfs2_reinit_path(path, 1);
>
> - if (meta_ac) {
> - ocfs2_free_alloc_context(meta_ac);
> - meta_ac = NULL;
> - }
> -
> if (ref_tree) {
> ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
> ref_tree = NULL;
> @@ -7598,28 +7161,15 @@ start:
> goto start;
>
> bail:
> -
> ocfs2_schedule_truncate_log_flush(osb, 1);
>
> - if (tl_sem)
> - mutex_unlock(&tl_inode->i_mutex);
> -
> - if (handle)
> - ocfs2_commit_trans(osb, handle);
> -
> - if (meta_ac)
> - ocfs2_free_alloc_context(meta_ac);
> -
> if (ref_tree)
> ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
>
> - ocfs2_run_deallocs(osb, &tc->tc_dealloc);
> + ocfs2_run_deallocs(osb, &dealloc);
>
> ocfs2_free_path(path);
>
> - /* This will drop the ext_alloc cluster lock for us */
> - ocfs2_free_truncate_context(tc);
> -
>
I would suggest you to separate the removal of tc and
ocfs2_prepare_truncate to another function since it has nothing to do
with this patch.
Regards,
Tao
More information about the Ocfs2-devel
mailing list