vfs: introduce noop_llseek()
[safe/jmp/linux-2.6] / fs / ocfs2 / alloc.c
index a629656..215e12c 100644 (file)
@@ -49,6 +49,7 @@
 #include "super.h"
 #include "uptodate.h"
 #include "xattr.h"
+#include "refcounttree.h"
 
 #include "buffer_head_io.h"
 
@@ -567,36 +568,6 @@ static inline int ocfs2_et_sanity_check(struct ocfs2_extent_tree *et)
 static void ocfs2_free_truncate_context(struct ocfs2_truncate_context *tc);
 static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
                                         struct ocfs2_extent_block *eb);
-
-/*
- * Structures which describe a path through a btree, and functions to
- * manipulate them.
- *
- * The idea here is to be as generic as possible with the tree
- * manipulation code.
- */
-struct ocfs2_path_item {
-       struct buffer_head              *bh;
-       struct ocfs2_extent_list        *el;
-};
-
-#define OCFS2_MAX_PATH_DEPTH   5
-
-struct ocfs2_path {
-       int                             p_tree_depth;
-       ocfs2_journal_access_func       p_root_access;
-       struct ocfs2_path_item          p_node[OCFS2_MAX_PATH_DEPTH];
-};
-
-#define path_root_bh(_path) ((_path)->p_node[0].bh)
-#define path_root_el(_path) ((_path)->p_node[0].el)
-#define path_root_access(_path)((_path)->p_root_access)
-#define path_leaf_bh(_path) ((_path)->p_node[(_path)->p_tree_depth].bh)
-#define path_leaf_el(_path) ((_path)->p_node[(_path)->p_tree_depth].el)
-#define path_num_items(_path) ((_path)->p_tree_depth + 1)
-
-static int ocfs2_find_path(struct ocfs2_caching_info *ci,
-                          struct ocfs2_path *path, u32 cpos);
 static void ocfs2_adjust_rightmost_records(handle_t *handle,
                                           struct ocfs2_extent_tree *et,
                                           struct ocfs2_path *path,
@@ -606,7 +577,7 @@ static void ocfs2_adjust_rightmost_records(handle_t *handle,
  * to build another path. Generally, this involves freeing the buffer
  * heads.
  */
-static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root)
+void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root)
 {
        int i, start = 0, depth = 0;
        struct ocfs2_path_item *node;
@@ -635,7 +606,7 @@ static void ocfs2_reinit_path(struct ocfs2_path *path, int keep_root)
        path->p_tree_depth = depth;
 }
 
-static void ocfs2_free_path(struct ocfs2_path *path)
+void ocfs2_free_path(struct ocfs2_path *path)
 {
        if (path) {
                ocfs2_reinit_path(path, 0);
@@ -733,13 +704,13 @@ static struct ocfs2_path *ocfs2_new_path(struct buffer_head *root_bh,
        return path;
 }
 
-static struct ocfs2_path *ocfs2_new_path_from_path(struct ocfs2_path *path)
+struct ocfs2_path *ocfs2_new_path_from_path(struct ocfs2_path *path)
 {
        return ocfs2_new_path(path_root_bh(path), path_root_el(path),
                              path_root_access(path));
 }
 
-static struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et)
+struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et)
 {
        return ocfs2_new_path(et->et_root_bh, et->et_root_el,
                              et->et_root_journal_access);
@@ -752,10 +723,10 @@ static struct ocfs2_path *ocfs2_new_path_from_et(struct ocfs2_extent_tree *et)
  * I don't like the way this function's name looks next to
  * ocfs2_journal_access_path(), but I don't have a better one.
  */
-static int ocfs2_path_bh_journal_access(handle_t *handle,
-                                       struct ocfs2_caching_info *ci,
-                                       struct ocfs2_path *path,
-                                       int idx)
+int ocfs2_path_bh_journal_access(handle_t *handle,
+                                struct ocfs2_caching_info *ci,
+                                struct ocfs2_path *path,
+                                int idx)
 {
        ocfs2_journal_access_func access = path_root_access(path);
 
@@ -772,9 +743,9 @@ static int ocfs2_path_bh_journal_access(handle_t *handle,
 /*
  * Convenience function to journal all components in a path.
  */
-static int ocfs2_journal_access_path(struct ocfs2_caching_info *ci,
-                                    handle_t *handle,
-                                    struct ocfs2_path *path)
+int ocfs2_journal_access_path(struct ocfs2_caching_info *ci,
+                             handle_t *handle,
+                             struct ocfs2_path *path)
 {
        int i, ret = 0;
 
@@ -1035,7 +1006,7 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle,
        int count, status, i;
        u16 suballoc_bit_start;
        u32 num_got;
-       u64 first_blkno;
+       u64 suballoc_loc, first_blkno;
        struct ocfs2_super *osb =
                OCFS2_SB(ocfs2_metadata_cache_get_super(et->et_ci));
        struct ocfs2_extent_block *eb;
@@ -1044,10 +1015,10 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle,
 
        count = 0;
        while (count < wanted) {
-               status = ocfs2_claim_metadata(osb,
-                                             handle,
+               status = ocfs2_claim_metadata(handle,
                                              meta_ac,
                                              wanted - count,
+                                             &suballoc_loc,
                                              &suballoc_bit_start,
                                              &num_got,
                                              &first_blkno);
@@ -1079,7 +1050,9 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle,
                        strcpy(eb->h_signature, OCFS2_EXTENT_BLOCK_SIGNATURE);
                        eb->h_blkno = cpu_to_le64(first_blkno);
                        eb->h_fs_generation = cpu_to_le32(osb->fs_generation);
-                       eb->h_suballoc_slot = cpu_to_le16(osb->slot_num);
+                       eb->h_suballoc_slot =
+                               cpu_to_le16(meta_ac->ac_alloc_slot);
+                       eb->h_suballoc_loc = cpu_to_le64(suballoc_loc);
                        eb->h_suballoc_bit = cpu_to_le16(suballoc_bit_start);
                        eb->h_list.l_count =
                                cpu_to_le16(ocfs2_extent_recs_per_eb(osb->sb));
@@ -1089,11 +1062,7 @@ static int ocfs2_create_new_meta_bhs(handle_t *handle,
 
                        /* We'll also be dirtied by the caller, so
                         * this isn't absolutely necessary. */
-                       status = ocfs2_journal_dirty(handle, bhs[i]);
-                       if (status < 0) {
-                               mlog_errno(status);
-                               goto bail;
-                       }
+                       ocfs2_journal_dirty(handle, bhs[i]);
                }
 
                count += num_got;
@@ -1157,8 +1126,7 @@ static int ocfs2_adjust_rightmost_branch(handle_t *handle,
                goto out;
        }
 
-       status = ocfs2_extend_trans(handle, path_num_items(path) +
-                                   handle->h_buffer_credits);
+       status = ocfs2_extend_trans(handle, path_num_items(path));
        if (status < 0) {
                mlog_errno(status);
                goto out;
@@ -1298,12 +1266,7 @@ static int ocfs2_add_branch(handle_t *handle,
                if (!eb_el->l_tree_depth)
                        new_last_eb_blk = le64_to_cpu(eb->h_blkno);
 
-               status = ocfs2_journal_dirty(handle, bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-
+               ocfs2_journal_dirty(handle, bh);
                next_blkno = le64_to_cpu(eb->h_blkno);
        }
 
@@ -1349,17 +1312,10 @@ static int ocfs2_add_branch(handle_t *handle,
        eb = (struct ocfs2_extent_block *) (*last_eb_bh)->b_data;
        eb->h_next_leaf_blk = cpu_to_le64(new_last_eb_blk);
 
-       status = ocfs2_journal_dirty(handle, *last_eb_bh);
-       if (status < 0)
-               mlog_errno(status);
-       status = ocfs2_journal_dirty(handle, et->et_root_bh);
-       if (status < 0)
-               mlog_errno(status);
-       if (eb_bh) {
-               status = ocfs2_journal_dirty(handle, eb_bh);
-               if (status < 0)
-                       mlog_errno(status);
-       }
+       ocfs2_journal_dirty(handle, *last_eb_bh);
+       ocfs2_journal_dirty(handle, et->et_root_bh);
+       if (eb_bh)
+               ocfs2_journal_dirty(handle, eb_bh);
 
        /*
         * Some callers want to track the rightmost leaf so pass it
@@ -1427,11 +1383,7 @@ static int ocfs2_shift_tree_depth(handle_t *handle,
        for (i = 0; i < le16_to_cpu(root_el->l_next_free_rec); i++)
                eb_el->l_recs[i] = root_el->l_recs[i];
 
-       status = ocfs2_journal_dirty(handle, new_eb_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+       ocfs2_journal_dirty(handle, new_eb_bh);
 
        status = ocfs2_et_root_journal_access(handle, et,
                                              OCFS2_JOURNAL_ACCESS_WRITE);
@@ -1456,11 +1408,7 @@ static int ocfs2_shift_tree_depth(handle_t *handle,
        if (root_el->l_tree_depth == cpu_to_le16(1))
                ocfs2_et_set_last_eb_blk(et, le64_to_cpu(eb->h_blkno));
 
-       status = ocfs2_journal_dirty(handle, et->et_root_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+       ocfs2_journal_dirty(handle, et->et_root_bh);
 
        *ret_new_eb_bh = new_eb_bh;
        new_eb_bh = NULL;
@@ -1794,9 +1742,9 @@ set_and_inc:
  *
  * The array index of the subtree root is passed back.
  */
-static int ocfs2_find_subtree_root(struct ocfs2_extent_tree *et,
-                                  struct ocfs2_path *left,
-                                  struct ocfs2_path *right)
+int ocfs2_find_subtree_root(struct ocfs2_extent_tree *et,
+                           struct ocfs2_path *left,
+                           struct ocfs2_path *right)
 {
        int i = 0;
 
@@ -1942,8 +1890,8 @@ static void find_path_ins(void *data, struct buffer_head *bh)
        ocfs2_path_insert_eb(fp->path, fp->index, bh);
        fp->index++;
 }
-static int ocfs2_find_path(struct ocfs2_caching_info *ci,
-                          struct ocfs2_path *path, u32 cpos)
+int ocfs2_find_path(struct ocfs2_caching_info *ci,
+                   struct ocfs2_path *path, u32 cpos)
 {
        struct find_path_data data;
 
@@ -2092,7 +2040,7 @@ static void ocfs2_complete_edge_insert(handle_t *handle,
                                       struct ocfs2_path *right_path,
                                       int subtree_index)
 {
-       int ret, i, idx;
+       int i, idx;
        struct ocfs2_extent_list *el, *left_el, *right_el;
        struct ocfs2_extent_rec *left_rec, *right_rec;
        struct buffer_head *root_bh = left_path->p_node[subtree_index].bh;
@@ -2130,13 +2078,8 @@ static void ocfs2_complete_edge_insert(handle_t *handle,
                ocfs2_adjust_adjacent_records(left_rec, left_el, right_rec,
                                              right_el);
 
-               ret = ocfs2_journal_dirty(handle, left_path->p_node[i].bh);
-               if (ret)
-                       mlog_errno(ret);
-
-               ret = ocfs2_journal_dirty(handle, right_path->p_node[i].bh);
-               if (ret)
-                       mlog_errno(ret);
+               ocfs2_journal_dirty(handle, left_path->p_node[i].bh);
+               ocfs2_journal_dirty(handle, right_path->p_node[i].bh);
 
                /*
                 * Setup our list pointers now so that the current
@@ -2160,9 +2103,7 @@ static void ocfs2_complete_edge_insert(handle_t *handle,
 
        root_bh = left_path->p_node[subtree_index].bh;
 
-       ret = ocfs2_journal_dirty(handle, root_bh);
-       if (ret)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, root_bh);
 }
 
 static int ocfs2_rotate_subtree_right(handle_t *handle,
@@ -2235,11 +2176,7 @@ static int ocfs2_rotate_subtree_right(handle_t *handle,
 
        ocfs2_create_empty_extent(right_el);
 
-       ret = ocfs2_journal_dirty(handle, right_leaf_bh);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
+       ocfs2_journal_dirty(handle, right_leaf_bh);
 
        /* Do the copy now. */
        i = le16_to_cpu(left_el->l_next_free_rec) - 1;
@@ -2258,11 +2195,7 @@ static int ocfs2_rotate_subtree_right(handle_t *handle,
        memset(&left_el->l_recs[0], 0, sizeof(struct ocfs2_extent_rec));
        le16_add_cpu(&left_el->l_next_free_rec, 1);
 
-       ret = ocfs2_journal_dirty(handle, left_leaf_bh);
-       if (ret) {
-               mlog_errno(ret);
-               goto out;
-       }
+       ocfs2_journal_dirty(handle, left_leaf_bh);
 
        ocfs2_complete_edge_insert(handle, left_path, right_path,
                                   subtree_index);
@@ -2277,8 +2210,8 @@ out:
  *
  * Will return zero if the path passed in is already the leftmost path.
  */
-static int ocfs2_find_cpos_for_left_leaf(struct super_block *sb,
-                                        struct ocfs2_path *path, u32 *cpos)
+int ocfs2_find_cpos_for_left_leaf(struct super_block *sb,
+                                 struct ocfs2_path *path, u32 *cpos)
 {
        int i, j, ret = 0;
        u64 blkno;
@@ -2355,12 +2288,14 @@ static int ocfs2_extend_rotate_transaction(handle_t *handle, int subtree_depth,
                                           int op_credits,
                                           struct ocfs2_path *path)
 {
+       int ret = 0;
        int credits = (path->p_tree_depth - subtree_depth) * 2 + 1 + op_credits;
 
        if (handle->h_buffer_credits < credits)
-               return ocfs2_extend_trans(handle, credits);
+               ret = ocfs2_extend_trans(handle,
+                                        credits - handle->h_buffer_credits);
 
-       return 0;
+       return ret;
 }
 
 /*
@@ -2419,7 +2354,7 @@ static int ocfs2_leftmost_rec_contains(struct ocfs2_extent_list *el, u32 cpos)
  *
  * The array is assumed to be large enough to hold an entire path (tree depth).
  *
- * Upon succesful return from this function:
+ * Upon successful return from this function:
  *
  * - The 'right_path' array will contain a path to the leaf block
  *   whose range contains e_cpos.
@@ -2604,8 +2539,7 @@ static int ocfs2_update_edge_lengths(handle_t *handle,
         * records for all the bh in the path.
         * So we have to allocate extra credits and access them.
         */
-       ret = ocfs2_extend_trans(handle,
-                                handle->h_buffer_credits + subtree_index);
+       ret = ocfs2_extend_trans(handle, subtree_index);
        if (ret) {
                mlog_errno(ret);
                goto out;
@@ -2843,12 +2777,8 @@ static int ocfs2_rotate_subtree_left(handle_t *handle,
                ocfs2_remove_empty_extent(right_leaf_el);
        }
 
-       ret = ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
-       if (ret)
-               mlog_errno(ret);
-       ret = ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
-       if (ret)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
+       ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
 
        if (del_right_subtree) {
                ocfs2_unlink_subtree(handle, et, left_path, right_path,
@@ -2871,9 +2801,7 @@ static int ocfs2_rotate_subtree_left(handle_t *handle,
                if (right_has_empty)
                        ocfs2_remove_empty_extent(left_leaf_el);
 
-               ret = ocfs2_journal_dirty(handle, et_root_bh);
-               if (ret)
-                       mlog_errno(ret);
+               ocfs2_journal_dirty(handle, et_root_bh);
 
                *deleted = 1;
        } else
@@ -2893,8 +2821,8 @@ out:
  * This looks similar, but is subtly different to
  * ocfs2_find_cpos_for_left_leaf().
  */
-static int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
-                                         struct ocfs2_path *path, u32 *cpos)
+int ocfs2_find_cpos_for_right_leaf(struct super_block *sb,
+                                  struct ocfs2_path *path, u32 *cpos)
 {
        int i, j, ret = 0;
        u64 blkno;
@@ -2982,10 +2910,7 @@ static int ocfs2_rotate_rightmost_leaf_left(handle_t *handle,
        }
 
        ocfs2_remove_empty_extent(el);
-
-       ret = ocfs2_journal_dirty(handle, bh);
-       if (ret)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, bh);
 
 out:
        return ret;
@@ -3526,15 +3451,9 @@ static int ocfs2_merge_rec_right(struct ocfs2_path *left_path,
 
        ocfs2_cleanup_merge(el, index);
 
-       ret = ocfs2_journal_dirty(handle, bh);
-       if (ret)
-               mlog_errno(ret);
-
+       ocfs2_journal_dirty(handle, bh);
        if (right_path) {
-               ret = ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
-               if (ret)
-                       mlog_errno(ret);
-
+               ocfs2_journal_dirty(handle, path_leaf_bh(right_path));
                ocfs2_complete_edge_insert(handle, left_path, right_path,
                                           subtree_index);
        }
@@ -3703,14 +3622,9 @@ static int ocfs2_merge_rec_left(struct ocfs2_path *right_path,
 
        ocfs2_cleanup_merge(el, index);
 
-       ret = ocfs2_journal_dirty(handle, bh);
-       if (ret)
-               mlog_errno(ret);
-
+       ocfs2_journal_dirty(handle, bh);
        if (left_path) {
-               ret = ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
-               if (ret)
-                       mlog_errno(ret);
+               ocfs2_journal_dirty(handle, path_leaf_bh(left_path));
 
                /*
                 * In the situation that the right_rec is empty and the extent
@@ -4036,10 +3950,7 @@ static void ocfs2_adjust_rightmost_records(handle_t *handle,
                le32_add_cpu(&rec->e_int_clusters,
                             -le32_to_cpu(rec->e_cpos));
 
-               ret = ocfs2_journal_dirty(handle, bh);
-               if (ret)
-                       mlog_errno(ret);
-
+               ocfs2_journal_dirty(handle, bh);
        }
 }
 
@@ -4223,17 +4134,13 @@ static int ocfs2_insert_path(handle_t *handle,
        struct buffer_head *leaf_bh = path_leaf_bh(right_path);
 
        if (left_path) {
-               int credits = handle->h_buffer_credits;
-
                /*
                 * There's a chance that left_path got passed back to
                 * us without being accounted for in the
                 * journal. Extend our transaction here to be sure we
                 * can change those blocks.
                 */
-               credits += left_path->p_tree_depth;
-
-               ret = ocfs2_extend_trans(handle, credits);
+               ret = ocfs2_extend_trans(handle, left_path->p_tree_depth);
                if (ret < 0) {
                        mlog_errno(ret);
                        goto out;
@@ -4271,17 +4178,13 @@ static int ocfs2_insert_path(handle_t *handle,
                 * dirty this for us.
                 */
                if (left_path)
-                       ret = ocfs2_journal_dirty(handle,
-                                                 path_leaf_bh(left_path));
-                       if (ret)
-                               mlog_errno(ret);
+                       ocfs2_journal_dirty(handle,
+                                           path_leaf_bh(left_path));
        } else
                ocfs2_insert_at_leaf(et, insert_rec, path_leaf_el(right_path),
                                     insert);
 
-       ret = ocfs2_journal_dirty(handle, leaf_bh);
-       if (ret)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, leaf_bh);
 
        if (left_path) {
                /*
@@ -4404,9 +4307,7 @@ out_update_clusters:
                ocfs2_et_update_clusters(et,
                                         le16_to_cpu(insert_rec->e_leaf_clusters));
 
-       ret = ocfs2_journal_dirty(handle, et->et_root_bh);
-       if (ret)
-               mlog_errno(ret);
+       ocfs2_journal_dirty(handle, et->et_root_bh);
 
 out:
        ocfs2_free_path(left_path);
@@ -4886,7 +4787,7 @@ int ocfs2_add_clusters_in_btree(handle_t *handle,
                goto leave;
        }
 
-       status = __ocfs2_claim_clusters(osb, handle, data_ac, 1,
+       status = __ocfs2_claim_clusters(handle, data_ac, 1,
                                        clusters_to_add, &bit_off, &num_bits);
        if (status < 0) {
                if (status != -ENOSPC)
@@ -4915,11 +4816,7 @@ int ocfs2_add_clusters_in_btree(handle_t *handle,
                goto leave;
        }
 
-       status = ocfs2_journal_dirty(handle, et->et_root_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto leave;
-       }
+       ocfs2_journal_dirty(handle, et->et_root_bh);
 
        clusters_to_add -= num_bits;
        *logical_offset += num_bits;
@@ -5104,13 +5001,13 @@ out:
  * have been brought into cache (and pinned via the journal), so the
  * extra overhead is not expressed in terms of disk reads.
  */
-static int __ocfs2_split_extent(handle_t *handle,
-                               struct ocfs2_extent_tree *et,
-                               struct ocfs2_path *path,
-                               int split_index,
-                               struct ocfs2_extent_rec *split_rec,
-                               struct ocfs2_alloc_context *meta_ac,
-                               struct ocfs2_cached_dealloc_ctxt *dealloc)
+int ocfs2_split_extent(handle_t *handle,
+                      struct ocfs2_extent_tree *et,
+                      struct ocfs2_path *path,
+                      int split_index,
+                      struct ocfs2_extent_rec *split_rec,
+                      struct ocfs2_alloc_context *meta_ac,
+                      struct ocfs2_cached_dealloc_ctxt *dealloc)
 {
        int ret = 0;
        struct ocfs2_extent_list *el = path_leaf_el(path);
@@ -5199,12 +5096,12 @@ out:
  *
  * The caller is responsible for passing down meta_ac if we'll need it.
  */
-static int ocfs2_change_extent_flag(handle_t *handle,
-                                   struct ocfs2_extent_tree *et,
-                                   u32 cpos, u32 len, u32 phys,
-                                   struct ocfs2_alloc_context *meta_ac,
-                                   struct ocfs2_cached_dealloc_ctxt *dealloc,
-                                   int new_flags, int clear_flags)
+int ocfs2_change_extent_flag(handle_t *handle,
+                            struct ocfs2_extent_tree *et,
+                            u32 cpos, u32 len, u32 phys,
+                            struct ocfs2_alloc_context *meta_ac,
+                            struct ocfs2_cached_dealloc_ctxt *dealloc,
+                            int new_flags, int clear_flags)
 {
        int ret, index;
        struct super_block *sb = ocfs2_metadata_cache_get_super(et->et_ci);
@@ -5267,9 +5164,9 @@ static int ocfs2_change_extent_flag(handle_t *handle,
        if (clear_flags)
                split_rec.e_flags &= ~clear_flags;
 
-       ret = __ocfs2_split_extent(handle, et, left_path,
-                                 index, &split_rec, meta_ac,
-                                 dealloc);
+       ret = ocfs2_split_extent(handle, et, left_path,
+                                index, &split_rec, meta_ac,
+                                dealloc);
        if (ret)
                mlog_errno(ret);
 
@@ -5329,7 +5226,7 @@ static int ocfs2_split_tree(handle_t *handle, struct ocfs2_extent_tree *et,
                            int index, u32 new_range,
                            struct ocfs2_alloc_context *meta_ac)
 {
-       int ret, depth, credits = handle->h_buffer_credits;
+       int ret, depth, credits;
        struct buffer_head *last_eb_bh = NULL;
        struct ocfs2_extent_block *eb;
        struct ocfs2_extent_list *rightmost_el, *el;
@@ -5360,8 +5257,8 @@ static int ocfs2_split_tree(handle_t *handle, struct ocfs2_extent_tree *et,
        } else
                rightmost_el = path_leaf_el(path);
 
-       credits += path->p_tree_depth +
-                  ocfs2_extend_meta_needed(et->et_root_el);
+       credits = path->p_tree_depth +
+                 ocfs2_extend_meta_needed(et->et_root_el);
        ret = ocfs2_extend_trans(handle, credits);
        if (ret) {
                mlog_errno(ret);
@@ -5691,19 +5588,97 @@ out:
        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_lock_allocators(inode, et, 0, 1, NULL, &meta_ac);
+               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_reserve_blocks_for_rec_trunc(inode, et, 1, &meta_ac,
+                                                extra_blocks);
        if (ret) {
                mlog_errno(ret);
                return ret;
@@ -5719,7 +5694,8 @@ int ocfs2_remove_btree_range(struct inode *inode,
                }
        }
 
-       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);
@@ -5733,7 +5709,7 @@ int ocfs2_remove_btree_range(struct inode *inode,
                goto out;
        }
 
-       vfs_dq_free_space_nodirty(inode,
+       dquot_free_space_nodirty(inode,
                                  ocfs2_clusters_to_bytes(inode->i_sb, len));
 
        ret = ocfs2_remove_extent(handle, et, cpos, len, meta_ac, dealloc);
@@ -5744,15 +5720,22 @@ int ocfs2_remove_btree_range(struct inode *inode,
 
        ocfs2_et_update_clusters(et, -len);
 
-       ret = ocfs2_journal_dirty(handle, et->et_root_bh);
-       if (ret) {
-               mlog_errno(ret);
-               goto out_commit;
-       }
+       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);
@@ -5762,6 +5745,9 @@ out:
        if (meta_ac)
                ocfs2_free_alloc_context(meta_ac);
 
+       if (ref_tree)
+               ocfs2_unlock_refcount_tree(osb, ref_tree, 1);
+
        return ret;
 }
 
@@ -5870,11 +5856,7 @@ int ocfs2_truncate_log_append(struct ocfs2_super *osb,
        }
        tl->tl_recs[index].t_clusters = cpu_to_le32(num_clusters);
 
-       status = ocfs2_journal_dirty(handle, tl_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
+       ocfs2_journal_dirty(handle, tl_bh);
 
 bail:
        mlog_exit(status);
@@ -5913,11 +5895,7 @@ static int ocfs2_replay_truncate_records(struct ocfs2_super *osb,
 
                tl->tl_used = cpu_to_le16(i);
 
-               status = ocfs2_journal_dirty(handle, tl_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
+               ocfs2_journal_dirty(handle, tl_bh);
 
                /* TODO: Perhaps we can calculate the bulk of the
                 * credits up front rather than extending like
@@ -6058,7 +6036,7 @@ static void ocfs2_truncate_log_worker(struct work_struct *work)
        if (status < 0)
                mlog_errno(status);
        else
-               ocfs2_init_inode_steal_slot(osb);
+               ocfs2_init_steal_slots(osb);
 
        mlog_exit(status);
 }
@@ -6318,6 +6296,7 @@ int ocfs2_truncate_log_init(struct ocfs2_super *osb)
  */
 struct ocfs2_cached_block_free {
        struct ocfs2_cached_block_free          *free_next;
+       u64                                     free_bg;
        u64                                     free_blk;
        unsigned int                            free_bit;
 };
@@ -6364,8 +6343,11 @@ static int ocfs2_free_cached_blocks(struct ocfs2_super *osb,
        }
 
        while (head) {
-               bg_blkno = ocfs2_which_suballoc_group(head->free_blk,
-                                                     head->free_bit);
+               if (head->free_bg)
+                       bg_blkno = head->free_bg;
+               else
+                       bg_blkno = ocfs2_which_suballoc_group(head->free_blk,
+                                                             head->free_bit);
                mlog(0, "Free bit: (bit %u, blkno %llu)\n",
                     head->free_bit, (unsigned long long)head->free_blk);
 
@@ -6413,7 +6395,7 @@ int ocfs2_cache_cluster_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
        int ret = 0;
        struct ocfs2_cached_block_free *item;
 
-       item = kmalloc(sizeof(*item), GFP_NOFS);
+       item = kzalloc(sizeof(*item), GFP_NOFS);
        if (item == NULL) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -6552,9 +6534,9 @@ ocfs2_find_per_slot_free_list(int type,
        return fl;
 }
 
-static int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
-                                    int type, int slot, u64 blkno,
-                                    unsigned int bit)
+int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
+                             int type, int slot, u64 suballoc,
+                             u64 blkno, unsigned int bit)
 {
        int ret;
        struct ocfs2_per_slot_free_list *fl;
@@ -6567,7 +6549,7 @@ static int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
                goto out;
        }
 
-       item = kmalloc(sizeof(*item), GFP_NOFS);
+       item = kzalloc(sizeof(*item), GFP_NOFS);
        if (item == NULL) {
                ret = -ENOMEM;
                mlog_errno(ret);
@@ -6577,6 +6559,7 @@ static int ocfs2_cache_block_dealloc(struct ocfs2_cached_dealloc_ctxt *ctxt,
        mlog(0, "Insert: (type %d, slot %u, bit %u, blk %llu)\n",
             type, slot, bit, (unsigned long long)blkno);
 
+       item->free_bg = suballoc;
        item->free_blk = blkno;
        item->free_bit = bit;
        item->free_next = fl->f_first;
@@ -6593,421 +6576,11 @@ static int ocfs2_cache_extent_block_free(struct ocfs2_cached_dealloc_ctxt *ctxt,
 {
        return ocfs2_cache_block_dealloc(ctxt, EXTENT_ALLOC_SYSTEM_INODE,
                                         le16_to_cpu(eb->h_suballoc_slot),
+                                        le64_to_cpu(eb->h_suballoc_loc),
                                         le64_to_cpu(eb->h_blkno),
                                         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)
-{
-       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;
-
-       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));
-
-                       /*
-                        * 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:
-               ret = ocfs2_journal_dirty(handle, bh);
-               if (ret) {
-                       mlog_errno(ret);
-                       goto out;
-               }
-
-               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)
-{
-       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;
-
-       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;
-       }
-
-       vfs_dq_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);
-       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;
-
-       status = ocfs2_journal_dirty(handle, fe_bh);
-       if (status < 0) {
-               mlog_errno(status);
-               goto bail;
-       }
-
-       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;
-               status = ocfs2_journal_dirty(handle, last_eb_bh);
-               if (status < 0) {
-                       mlog_errno(status);
-                       goto bail;
-               }
-       }
-
-       if (delete_blk) {
-               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);
@@ -7015,9 +6588,9 @@ static int ocfs2_zero_func(handle_t *handle, struct buffer_head *bh)
        return 0;
 }
 
-static void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
-                                    unsigned int from, unsigned int to,
-                                    struct page *page, int zero, u64 *phys)
+void ocfs2_map_and_dirty_page(struct inode *inode, handle_t *handle,
+                             unsigned int from, unsigned int to,
+                             struct page *page, int zero, u64 *phys)
 {
        int ret, partial = 0;
 
@@ -7085,20 +6658,16 @@ out:
                ocfs2_unlock_and_free_pages(pages, numpages);
 }
 
-static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
-                               struct page **pages, int *num)
+int ocfs2_grab_pages(struct inode *inode, loff_t start, loff_t end,
+                    struct page **pages, int *num)
 {
        int numpages, ret = 0;
-       struct super_block *sb = inode->i_sb;
        struct address_space *mapping = inode->i_mapping;
        unsigned long index;
        loff_t last_page_bytes;
 
        BUG_ON(start > end);
 
-       BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
-              (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
-
        numpages = 0;
        last_page_bytes = PAGE_ALIGN(end);
        index = start >> PAGE_CACHE_SHIFT;
@@ -7126,6 +6695,17 @@ out:
        return ret;
 }
 
+static int ocfs2_grab_eof_pages(struct inode *inode, loff_t start, loff_t end,
+                               struct page **pages, int *num)
+{
+       struct super_block *sb = inode->i_sb;
+
+       BUG_ON(start >> OCFS2_SB(sb)->s_clustersize_bits !=
+              (end - 1) >> OCFS2_SB(sb)->s_clustersize_bits);
+
+       return ocfs2_grab_pages(inode, start, end, pages, num);
+}
+
 /*
  * Zero the area past i_size but still within an allocated
  * cluster. This avoids exposing nonzero data on subsequent file
@@ -7192,8 +6772,8 @@ int ocfs2_zero_range_for_truncate(struct inode *inode, handle_t *handle,
         * wait on them - the truncate_inode_pages() call later will
         * do that for us.
         */
-       ret = do_sync_mapping_range(inode->i_mapping, range_start,
-                                   range_end - 1, SYNC_FILE_RANGE_WRITE);
+       ret = filemap_fdatawrite_range(inode->i_mapping, range_start,
+                                      range_end - 1);
        if (ret)
                mlog_errno(ret);
 
@@ -7302,14 +6882,15 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
                unsigned int page_end;
                u64 phys;
 
-               if (vfs_dq_alloc_space_nodirty(inode,
-                                      ocfs2_clusters_to_bytes(osb->sb, 1))) {
-                       ret = -EDQUOT;
+               ret = dquot_alloc_space_nodirty(inode,
+                                      ocfs2_clusters_to_bytes(osb->sb, 1));
+               if (ret)
                        goto out_commit;
-               }
                did_quota = 1;
 
-               ret = ocfs2_claim_clusters(osb, handle, data_ac, 1, &bit_off,
+               data_ac->ac_resv = &OCFS2_I(inode)->ip_la_data_resv;
+
+               ret = ocfs2_claim_clusters(handle, data_ac, 1, &bit_off,
                                           &num);
                if (ret) {
                        mlog_errno(ret);
@@ -7382,7 +6963,7 @@ int ocfs2_convert_inline_data_to_extents(struct inode *inode,
 
 out_commit:
        if (ret < 0 && did_quota)
-               vfs_dq_free_space_nodirty(inode,
+               dquot_free_space_nodirty(inode,
                                          ocfs2_clusters_to_bytes(osb->sb, 1));
 
        ocfs2_commit_trans(osb, handle);
@@ -7408,23 +6989,29 @@ 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 *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_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;
@@ -7477,61 +7064,60 @@ 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]);
+       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;
+               /*
+                * 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);
-
-       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);
+       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);
 
        /*
@@ -7544,19 +7130,10 @@ bail:
 
        ocfs2_schedule_truncate_log_flush(osb, 1);
 
-       if (tl_sem)
-               mutex_unlock(&tl_inode->i_mutex);
-
-       if (handle)
-               ocfs2_commit_trans(osb, handle);
-
-       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;
 }