return ret;
 }
 
+/*
+ * ocfs2_reserve_blocks_for_rec_trunc() would look basically the
+ * same as ocfs2_lock_alloctors(), except for it accepts a blocks
+ * number to reserve some extra blocks, and it only handles meta
+ * data allocations.
+ *
+ * Currently, only ocfs2_remove_btree_range() uses it for truncating
+ * and punching holes.
+ */
+static int ocfs2_reserve_blocks_for_rec_trunc(struct inode *inode,
+                                             struct ocfs2_extent_tree *et,
+                                             u32 extents_to_split,
+                                             struct ocfs2_alloc_context **ac,
+                                             int extra_blocks)
+{
+       int ret = 0, num_free_extents;
+       unsigned int max_recs_needed = 2 * extents_to_split;
+       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
+
+       *ac = NULL;
+
+       num_free_extents = ocfs2_num_free_extents(osb, et);
+       if (num_free_extents < 0) {
+               ret = num_free_extents;
+               mlog_errno(ret);
+               goto out;
+       }
+
+       if (!num_free_extents ||
+           (ocfs2_sparse_alloc(osb) && num_free_extents < max_recs_needed))
+               extra_blocks += ocfs2_extend_meta_needed(et->et_root_el);
+
+       if (extra_blocks) {
+               ret = ocfs2_reserve_new_metadata_blocks(osb, extra_blocks, ac);
+               if (ret < 0) {
+                       if (ret != -ENOSPC)
+                               mlog_errno(ret);
+                       goto out;
+               }
+       }
+
+out:
+       if (ret) {
+               if (*ac) {
+                       ocfs2_free_alloc_context(*ac);
+                       *ac = NULL;
+               }
+       }
+
+       return ret;
+}
+
 int ocfs2_remove_btree_range(struct inode *inode,
                             struct ocfs2_extent_tree *et,
-                            u32 cpos, u32 phys_cpos, u32 len,
-                            struct ocfs2_cached_dealloc_ctxt *dealloc)
+                            u32 cpos, u32 phys_cpos, u32 len, int flags,
+                            struct ocfs2_cached_dealloc_ctxt *dealloc,
+                            u64 refcount_loc)
 {
-       int ret;
+       int ret, credits = 0, extra_blocks = 0;
        u64 phys_blkno = ocfs2_clusters_to_blocks(inode->i_sb, phys_cpos);
        struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
        struct inode *tl_inode = osb->osb_tl_inode;
        handle_t *handle;
        struct ocfs2_alloc_context *meta_ac = NULL;
+       struct ocfs2_refcount_tree *ref_tree = NULL;
+
+       if ((flags & OCFS2_EXT_REFCOUNTED) && len) {
+               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
+                        OCFS2_HAS_REFCOUNT_FL));
+
+               ret = ocfs2_lock_refcount_tree(osb, refcount_loc, 1,
+                                              &ref_tree, NULL);
+               if (ret) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+
+               ret = ocfs2_prepare_refcount_change_for_del(inode,
+                                                           refcount_loc,
+                                                           phys_blkno,
+                                                           len,
+                                                           &credits,
+                                                           &extra_blocks);
+               if (ret < 0) {
+                       mlog_errno(ret);
+                       goto out;
+               }
+       }
 
-       ret = ocfs2_lock_allocators(inode, et, 0, 1, NULL, &meta_ac);
+       ret = ocfs2_reserve_blocks_for_rec_trunc(inode, et, 1, &meta_ac,
+                                                extra_blocks);
        if (ret) {
                mlog_errno(ret);
                return ret;
                }
        }
 
-       handle = ocfs2_start_trans(osb, ocfs2_remove_extent_credits(osb->sb));
+       handle = ocfs2_start_trans(osb,
+                       ocfs2_remove_extent_credits(osb->sb) + credits);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
                mlog_errno(ret);
 
        ocfs2_journal_dirty(handle, et->et_root_bh);
 
-       ret = ocfs2_truncate_log_append(osb, handle, phys_blkno, len);
-       if (ret)
-               mlog_errno(ret);
+       if (phys_blkno) {
+               if (flags & OCFS2_EXT_REFCOUNTED)
+                       ret = ocfs2_decrease_refcount(inode, handle,
+                                       ocfs2_blocks_to_clusters(osb->sb,
+                                                                phys_blkno),
+                                       len, meta_ac,
+                                       dealloc, 1);
+               else
+                       ret = ocfs2_truncate_log_append(osb, handle,
+                                                       phys_blkno, len);
+               if (ret)
+                       mlog_errno(ret);
+
+       }
 
 out_commit:
        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);
+
        return ret;
 }
 
                                         le16_to_cpu(eb->h_suballoc_bit));
 }
 
-/* This function will figure out whether the currently last extent
- * block will be deleted, and if it will, what the new last extent
- * block will be so we can update his h_next_leaf_blk field, as well
- * as the dinodes i_last_eb_blk */
-static int ocfs2_find_new_last_ext_blk(struct inode *inode,
-                                      unsigned int clusters_to_del,
-                                      struct ocfs2_path *path,
-                                      struct buffer_head **new_last_eb)
-{
-       int next_free, ret = 0;
-       u32 cpos;
-       struct ocfs2_extent_rec *rec;
-       struct ocfs2_extent_block *eb;
-       struct ocfs2_extent_list *el;
-       struct buffer_head *bh = NULL;
-
-       *new_last_eb = NULL;
-
-       /* we have no tree, so of course, no last_eb. */
-       if (!path->p_tree_depth)
-               goto out;
-
-       /* trunc to zero special case - this makes tree_depth = 0
-        * regardless of what it is.  */
-       if (OCFS2_I(inode)->ip_clusters == clusters_to_del)
-               goto out;
-
-       el = path_leaf_el(path);
-       BUG_ON(!el->l_next_free_rec);
-
-       /*
-        * Make sure that this extent list will actually be empty
-        * after we clear away the data. We can shortcut out if
-        * there's more than one non-empty extent in the
-        * list. Otherwise, a check of the remaining extent is
-        * necessary.
-        */
-       next_free = le16_to_cpu(el->l_next_free_rec);
-       rec = NULL;
-       if (ocfs2_is_empty_extent(&el->l_recs[0])) {
-               if (next_free > 2)
-                       goto out;
-
-               /* We may have a valid extent in index 1, check it. */
-               if (next_free == 2)
-                       rec = &el->l_recs[1];
-
-               /*
-                * Fall through - no more nonempty extents, so we want
-                * to delete this leaf.
-                */
-       } else {
-               if (next_free > 1)
-                       goto out;
-
-               rec = &el->l_recs[0];
-       }
-
-       if (rec) {
-               /*
-                * Check it we'll only be trimming off the end of this
-                * cluster.
-                */
-               if (le16_to_cpu(rec->e_leaf_clusters) > clusters_to_del)
-                       goto out;
-       }
-
-       ret = ocfs2_find_cpos_for_left_leaf(inode->i_sb, path, &cpos);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       ret = ocfs2_find_leaf(INODE_CACHE(inode), path_root_el(path), cpos, &bh);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
-
-       eb = (struct ocfs2_extent_block *) bh->b_data;
-       el = &eb->h_list;
-
-       /* ocfs2_find_leaf() gets the eb from ocfs2_read_extent_block().
-        * Any corruption is a code bug. */
-       BUG_ON(!OCFS2_IS_VALID_EXTENT_BLOCK(eb));
-
-       *new_last_eb = bh;
-       get_bh(*new_last_eb);
-       mlog(0, "returning block %llu, (cpos: %u)\n",
-            (unsigned long long)le64_to_cpu(eb->h_blkno), cpos);
-out:
-       brelse(bh);
-
-       return ret;
-}
-
-/*
- * Trim some clusters off the rightmost edge of a tree. Only called
- * during truncate.
- *
- * The caller needs to:
- *   - start journaling of each path component.
- *   - compute and fully set up any new last ext block
- */
-static int ocfs2_trim_tree(struct inode *inode, struct ocfs2_path *path,
-                          handle_t *handle, struct ocfs2_truncate_context *tc,
-                          u32 clusters_to_del, u64 *delete_start, u8 *flags)
-{
-       int ret, i, index = path->p_tree_depth;
-       u32 new_edge = 0;
-       u64 deleted_eb = 0;
-       struct buffer_head *bh;
-       struct ocfs2_extent_list *el;
-       struct ocfs2_extent_rec *rec;
-
-       *delete_start = 0;
-       *flags = 0;
-
-       while (index >= 0) {
-               bh = path->p_node[index].bh;
-               el = path->p_node[index].el;
-
-               mlog(0, "traveling tree (index = %d, block = %llu)\n",
-                    index,  (unsigned long long)bh->b_blocknr);
-
-               BUG_ON(le16_to_cpu(el->l_next_free_rec) == 0);
-
-               if (index !=
-                   (path->p_tree_depth - le16_to_cpu(el->l_tree_depth))) {
-                       ocfs2_error(inode->i_sb,
-                                   "Inode %lu has invalid ext. block %llu",
-                                   inode->i_ino,
-                                   (unsigned long long)bh->b_blocknr);
-                       ret = -EROFS;
-                       goto out;
-               }
-
-find_tail_record:
-               i = le16_to_cpu(el->l_next_free_rec) - 1;
-               rec = &el->l_recs[i];
-
-               mlog(0, "Extent list before: record %d: (%u, %u, %llu), "
-                    "next = %u\n", i, le32_to_cpu(rec->e_cpos),
-                    ocfs2_rec_clusters(el, rec),
-                    (unsigned long long)le64_to_cpu(rec->e_blkno),
-                    le16_to_cpu(el->l_next_free_rec));
-
-               BUG_ON(ocfs2_rec_clusters(el, rec) < clusters_to_del);
-
-               if (le16_to_cpu(el->l_tree_depth) == 0) {
-                       /*
-                        * If the leaf block contains a single empty
-                        * extent and no records, we can just remove
-                        * the block.
-                        */
-                       if (i == 0 && ocfs2_is_empty_extent(rec)) {
-                               memset(rec, 0,
-                                      sizeof(struct ocfs2_extent_rec));
-                               el->l_next_free_rec = cpu_to_le16(0);
-
-                               goto delete;
-                       }
-
-                       /*
-                        * Remove any empty extents by shifting things
-                        * left. That should make life much easier on
-                        * the code below. This condition is rare
-                        * enough that we shouldn't see a performance
-                        * hit.
-                        */
-                       if (ocfs2_is_empty_extent(&el->l_recs[0])) {
-                               le16_add_cpu(&el->l_next_free_rec, -1);
-
-                               for(i = 0;
-                                   i < le16_to_cpu(el->l_next_free_rec); i++)
-                                       el->l_recs[i] = el->l_recs[i + 1];
-
-                               memset(&el->l_recs[i], 0,
-                                      sizeof(struct ocfs2_extent_rec));
-
-                               /*
-                                * We've modified our extent list. The
-                                * simplest way to handle this change
-                                * is to being the search from the
-                                * start again.
-                                */
-                               goto find_tail_record;
-                       }
-
-                       le16_add_cpu(&rec->e_leaf_clusters, -clusters_to_del);
-
-                       /*
-                        * We'll use "new_edge" on our way back up the
-                        * tree to know what our rightmost cpos is.
-                        */
-                       new_edge = le16_to_cpu(rec->e_leaf_clusters);
-                       new_edge += le32_to_cpu(rec->e_cpos);
-
-                       /*
-                        * The caller will use this to delete data blocks.
-                        */
-                       *delete_start = le64_to_cpu(rec->e_blkno)
-                               + ocfs2_clusters_to_blocks(inode->i_sb,
-                                       le16_to_cpu(rec->e_leaf_clusters));
-                       *flags = rec->e_flags;
-
-                       /*
-                        * If it's now empty, remove this record.
-                        */
-                       if (le16_to_cpu(rec->e_leaf_clusters) == 0) {
-                               memset(rec, 0,
-                                      sizeof(struct ocfs2_extent_rec));
-                               le16_add_cpu(&el->l_next_free_rec, -1);
-                       }
-               } else {
-                       if (le64_to_cpu(rec->e_blkno) == deleted_eb) {
-                               memset(rec, 0,
-                                      sizeof(struct ocfs2_extent_rec));
-                               le16_add_cpu(&el->l_next_free_rec, -1);
-
-                               goto delete;
-                       }
-
-                       /* Can this actually happen? */
-                       if (le16_to_cpu(el->l_next_free_rec) == 0)
-                               goto delete;
-
-                       /*
-                        * We never actually deleted any clusters
-                        * because our leaf was empty. There's no
-                        * reason to adjust the rightmost edge then.
-                        */
-                       if (new_edge == 0)
-                               goto delete;
-
-                       rec->e_int_clusters = cpu_to_le32(new_edge);
-                       le32_add_cpu(&rec->e_int_clusters,
-                                    -le32_to_cpu(rec->e_cpos));
-
-                        /*
-                         * A deleted child record should have been
-                         * caught above.
-                         */
-                        BUG_ON(le32_to_cpu(rec->e_int_clusters) == 0);
-               }
-
-delete:
-               ocfs2_journal_dirty(handle, bh);
-
-               mlog(0, "extent list container %llu, after: record %d: "
-                    "(%u, %u, %llu), next = %u.\n",
-                    (unsigned long long)bh->b_blocknr, i,
-                    le32_to_cpu(rec->e_cpos), ocfs2_rec_clusters(el, rec),
-                    (unsigned long long)le64_to_cpu(rec->e_blkno),
-                    le16_to_cpu(el->l_next_free_rec));
-
-               /*
-                * We must be careful to only attempt delete of an
-                * extent block (and not the root inode block).
-                */
-               if (index > 0 && le16_to_cpu(el->l_next_free_rec) == 0) {
-                       struct ocfs2_extent_block *eb =
-                               (struct ocfs2_extent_block *)bh->b_data;
-
-                       /*
-                        * Save this for use when processing the
-                        * parent block.
-                        */
-                       deleted_eb = le64_to_cpu(eb->h_blkno);
-
-                       mlog(0, "deleting this extent block.\n");
-
-                       ocfs2_remove_from_cache(INODE_CACHE(inode), bh);
-
-                       BUG_ON(ocfs2_rec_clusters(el, &el->l_recs[0]));
-                       BUG_ON(le32_to_cpu(el->l_recs[0].e_cpos));
-                       BUG_ON(le64_to_cpu(el->l_recs[0].e_blkno));
-
-                       ret = ocfs2_cache_extent_block_free(&tc->tc_dealloc, eb);
-                       /* An error here is not fatal. */
-                       if (ret < 0)
-                               mlog_errno(ret);
-               } else {
-                       deleted_eb = 0;
-               }
-
-               index--;
-       }
-
-       ret = 0;
-out:
-       return ret;
-}
-
-static int ocfs2_do_truncate(struct ocfs2_super *osb,
-                            unsigned int clusters_to_del,
-                            struct inode *inode,
-                            struct buffer_head *fe_bh,
-                            handle_t *handle,
-                            struct ocfs2_truncate_context *tc,
-                            struct ocfs2_path *path,
-                            struct ocfs2_alloc_context *meta_ac)
-{
-       int status;
-       struct ocfs2_dinode *fe;
-       struct ocfs2_extent_block *last_eb = NULL;
-       struct ocfs2_extent_list *el;
-       struct buffer_head *last_eb_bh = NULL;
-       u64 delete_blk = 0;
-       u8 rec_flags;
-
-       fe = (struct ocfs2_dinode *) fe_bh->b_data;
-
-       status = ocfs2_find_new_last_ext_blk(inode, clusters_to_del,
-                                            path, &last_eb_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       /*
-        * Each component will be touched, so we might as well journal
-        * here to avoid having to handle errors later.
-        */
-       status = ocfs2_journal_access_path(INODE_CACHE(inode), handle, path);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       if (last_eb_bh) {
-               status = ocfs2_journal_access_eb(handle, INODE_CACHE(inode), last_eb_bh,
-                                                OCFS2_JOURNAL_ACCESS_WRITE);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-
-               last_eb = (struct ocfs2_extent_block *) last_eb_bh->b_data;
-       }
-
-       el = &(fe->id2.i_list);
-
-       /*
-        * Lower levels depend on this never happening, but it's best
-        * to check it up here before changing the tree.
-        */
-       if (el->l_tree_depth && el->l_recs[0].e_int_clusters == 0) {
-               ocfs2_error(inode->i_sb,
-                           "Inode %lu has an empty extent record, depth %u\n",
-                           inode->i_ino, le16_to_cpu(el->l_tree_depth));
-               status = -EROFS;
-               goto bail;
-       }
-
-       dquot_free_space_nodirty(inode,
-                       ocfs2_clusters_to_bytes(osb->sb, clusters_to_del));
-       spin_lock(&OCFS2_I(inode)->ip_lock);
-       OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters) -
-                                     clusters_to_del;
-       spin_unlock(&OCFS2_I(inode)->ip_lock);
-       le32_add_cpu(&fe->i_clusters, -clusters_to_del);
-       inode->i_blocks = ocfs2_inode_sector_count(inode);
-
-       status = ocfs2_trim_tree(inode, path, handle, tc,
-                                clusters_to_del, &delete_blk, &rec_flags);
-       if (status) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       if (le32_to_cpu(fe->i_clusters) == 0) {
-               /* trunc to zero is a special case. */
-               el->l_tree_depth = 0;
-               fe->i_last_eb_blk = 0;
-       } else if (last_eb)
-               fe->i_last_eb_blk = last_eb->h_blkno;
-
-       ocfs2_journal_dirty(handle, fe_bh);
-
-       if (last_eb) {
-               /* If there will be a new last extent block, then by
-                * definition, there cannot be any leaves to the right of
-                * him. */
-               last_eb->h_next_leaf_blk = 0;
-               ocfs2_journal_dirty(handle, last_eb_bh);
-       }
-
-       if (delete_blk) {
-               if (rec_flags & OCFS2_EXT_REFCOUNTED)
-                       status = ocfs2_decrease_refcount(inode, handle,
-                                       ocfs2_blocks_to_clusters(osb->sb,
-                                                                delete_blk),
-                                       clusters_to_del, meta_ac,
-                                       &tc->tc_dealloc, 1);
-               else
-                       status = ocfs2_truncate_log_append(osb, handle,
-                                                          delete_blk,
-                                                          clusters_to_del);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-       }
-       status = 0;
-bail:
-       brelse(last_eb_bh);
-       mlog_exit(status);
-       return status;
-}
-
 static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh)
 {
        set_buffer_uptodate(bh);
  */
 int ocfs2_commit_truncate(struct ocfs2_super *osb,
                          struct inode *inode,
-                         struct buffer_head *fe_bh,
-                         struct ocfs2_truncate_context *tc)
+                         struct buffer_head *di_bh)
 {
-       int status, i, credits, tl_sem = 0;
-       u32 clusters_to_del, new_highest_cpos, range;
+       int status = 0, i, 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_refcount_tree *ref_tree = NULL;
+       struct ocfs2_dinode *di = (struct ocfs2_dinode *)di_bh->b_data;
+       struct ocfs2_extent_list *root_el = &(di->id2.i_list);
+       u64 refcount_loc = le64_to_cpu(di->i_refcount_loc);
+       struct ocfs2_extent_tree et;
+       struct ocfs2_cached_dealloc_ctxt dealloc;
 
        mlog_entry_void();
 
+       ocfs2_init_dinode_extent_tree(&et, INODE_CACHE(inode), di_bh);
+       ocfs2_init_dealloc_ctxt(&dealloc);
+
        new_highest_cpos = ocfs2_clusters_for_bytes(osb->sb,
                                                     i_size_read(inode));
 
-       path = ocfs2_new_path(fe_bh, &di->id2.i_list,
+       path = ocfs2_new_path(di_bh, &di->id2.i_list,
                              ocfs2_journal_access_di);
        if (!path) {
                status = -ENOMEM;
                goto bail;
        }
 
-       credits = 0;
-
        /*
         * Truncate always works against the rightmost tree branch.
         */
        }
 
        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)) {
+               /*
+                * Lower levels depend on this never happening, but it's best
+                * to check it up here before changing the tree.
+               */
+               if (root_el->l_tree_depth && rec->e_int_clusters == 0) {
+                       ocfs2_error(inode->i_sb, "Inode %lu has an empty "
+                                   "extent record, depth %u\n", inode->i_ino,
+                                   le16_to_cpu(root_el->l_tree_depth));
+                       status = -EROFS;
+                       goto bail;
+               }
+               trunc_cpos = le32_to_cpu(rec->e_cpos);
+               trunc_len = 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);
+               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);
        } 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);
-
-       if (el->l_recs[i].e_flags & OCFS2_EXT_REFCOUNTED && clusters_to_del) {
-               BUG_ON(!(OCFS2_I(inode)->ip_dyn_features &
-                        OCFS2_HAS_REFCOUNT_FL));
-
-               status = ocfs2_lock_refcount_tree(osb,
-                                               le64_to_cpu(di->i_refcount_loc),
-                                               1, &ref_tree, NULL);
-               if (status) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-
-               status = ocfs2_prepare_refcount_change_for_del(inode, fe_bh,
-                                                              blkno,
-                                                              clusters_to_del,
-                                                              &credits,
-                                                              &meta_ac);
-               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);
-               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;
-       }
+       phys_cpos = ocfs2_blocks_to_clusters(inode->i_sb, blkno);
 
-       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, flags, &dealloc,
+                                         refcount_loc);
        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;
-       }
-
        /*
         * The check above will catch the case where we've truncated
         * away all allocation.
 
        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);
-
        mlog_exit(status);
        return status;
 }