]> err.no Git - linux-2.6/blobdiff - fs/ext4/extents.c
When ext4_ext_insert_extent() fails to insert new blocks
[linux-2.6] / fs / ext4 / extents.c
index 2608dce18f3e7f50461e1fe84225a24555b1da26..b9ce24129070bff5cee547a333139d9a4645d2c7 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/time.h>
 #include <linux/ext4_jbd2.h>
 #include <linux/jbd.h>
-#include <linux/smp_lock.h>
 #include <linux/highuid.h>
 #include <linux/pagemap.h>
 #include <linux/quotaops.h>
@@ -48,7 +47,7 @@
  * ext_pblock:
  * combine low and high parts of physical block number into ext4_fsblk_t
  */
-static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
+static ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
 {
        ext4_fsblk_t block;
 
@@ -61,7 +60,7 @@ static inline ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
  * idx_pblock:
  * combine low and high parts of a leaf physical block number into ext4_fsblk_t
  */
-static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
+static ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
 {
        ext4_fsblk_t block;
 
@@ -75,7 +74,7 @@ static inline ext4_fsblk_t idx_pblock(struct ext4_extent_idx *ix)
  * stores a large physical block number into an extent struct,
  * breaking it into parts
  */
-static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb)
+static void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb)
 {
        ex->ee_start = cpu_to_le32((unsigned long) (pb & 0xffffffff));
        ex->ee_start_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
@@ -86,7 +85,7 @@ static inline void ext4_ext_store_pblock(struct ext4_extent *ex, ext4_fsblk_t pb
  * stores a large physical block number into an index struct,
  * breaking it into parts
  */
-static inline void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
+static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
 {
        ix->ei_leaf = cpu_to_le32((unsigned long) (pb & 0xffffffff));
        ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
@@ -186,7 +185,8 @@ static ext4_fsblk_t ext4_ext_find_goal(struct inode *inode,
                depth = path->p_depth;
 
                /* try to predict block placement */
-               if ((ex = path[depth].p_ext))
+               ex = path[depth].p_ext;
+               if (ex)
                        return ext_pblock(ex)+(block-le32_to_cpu(ex->ee_block));
 
                /* it looks like index is empty;
@@ -215,54 +215,54 @@ ext4_ext_new_block(handle_t *handle, struct inode *inode,
        return newblock;
 }
 
-static inline int ext4_ext_space_block(struct inode *inode)
+static int ext4_ext_space_block(struct inode *inode)
 {
        int size;
 
        size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
                        / sizeof(struct ext4_extent);
-#ifdef AGRESSIVE_TEST
+#ifdef AGGRESSIVE_TEST
        if (size > 6)
                size = 6;
 #endif
        return size;
 }
 
-static inline int ext4_ext_space_block_idx(struct inode *inode)
+static int ext4_ext_space_block_idx(struct inode *inode)
 {
        int size;
 
        size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
                        / sizeof(struct ext4_extent_idx);
-#ifdef AGRESSIVE_TEST
+#ifdef AGGRESSIVE_TEST
        if (size > 5)
                size = 5;
 #endif
        return size;
 }
 
-static inline int ext4_ext_space_root(struct inode *inode)
+static int ext4_ext_space_root(struct inode *inode)
 {
        int size;
 
        size = sizeof(EXT4_I(inode)->i_data);
        size -= sizeof(struct ext4_extent_header);
        size /= sizeof(struct ext4_extent);
-#ifdef AGRESSIVE_TEST
+#ifdef AGGRESSIVE_TEST
        if (size > 3)
                size = 3;
 #endif
        return size;
 }
 
-static inline int ext4_ext_space_root_idx(struct inode *inode)
+static int ext4_ext_space_root_idx(struct inode *inode)
 {
        int size;
 
        size = sizeof(EXT4_I(inode)->i_data);
        size -= sizeof(struct ext4_extent_header);
        size /= sizeof(struct ext4_extent_idx);
-#ifdef AGRESSIVE_TEST
+#ifdef AGGRESSIVE_TEST
        if (size > 4)
                size = 4;
 #endif
@@ -374,7 +374,7 @@ ext4_ext_binsearch_idx(struct inode *inode, struct ext4_ext_path *path, int bloc
                                       le32_to_cpu(ix[-1].ei_block));
                        }
                        BUG_ON(k && le32_to_cpu(ix->ei_block)
-                                          <= le32_to_cpu(ix[-1].ei_block));
+                                          <= le32_to_cpu(ix[-1].ei_block));
                        if (block < le32_to_cpu(ix->ei_block))
                                break;
                        chix = ix;
@@ -423,8 +423,8 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
 
        path->p_ext = l - 1;
        ext_debug("  -> %d:%llu:%d ",
-                       le32_to_cpu(path->p_ext->ee_block),
-                       ext_pblock(path->p_ext),
+                       le32_to_cpu(path->p_ext->ee_block),
+                       ext_pblock(path->p_ext),
                        le16_to_cpu(path->p_ext->ee_len));
 
 #ifdef CHECK_BINSEARCH
@@ -435,7 +435,7 @@ ext4_ext_binsearch(struct inode *inode, struct ext4_ext_path *path, int block)
                chex = ex = EXT_FIRST_EXTENT(eh);
                for (k = 0; k < le16_to_cpu(eh->eh_entries); k++, ex++) {
                        BUG_ON(k && le32_to_cpu(ex->ee_block)
-                                         <= le32_to_cpu(ex[-1].ee_block));
+                                         <= le32_to_cpu(ex[-1].ee_block));
                        if (block < le32_to_cpu(ex->ee_block))
                                break;
                        chex = ex;
@@ -476,13 +476,12 @@ ext4_ext_find_extent(struct inode *inode, int block, struct ext4_ext_path *path)
 
        /* account possible depth increase */
        if (!path) {
-               path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 2),
+               path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 2),
                                GFP_NOFS);
                if (!path)
                        return ERR_PTR(-ENOMEM);
                alloc = 1;
        }
-       memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
        path[0].p_hdr = eh;
 
        /* walk through the tree */
@@ -543,7 +542,8 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
        struct ext4_extent_idx *ix;
        int len, err;
 
-       if ((err = ext4_ext_get_access(handle, inode, curp)))
+       err = ext4_ext_get_access(handle, inode, curp);
+       if (err)
                return err;
 
        BUG_ON(logical == le32_to_cpu(curp->p_idx->ei_block));
@@ -577,7 +577,7 @@ static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
        curp->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(curp->p_hdr->eh_entries)+1);
 
        BUG_ON(le16_to_cpu(curp->p_hdr->eh_entries)
-                            > le16_to_cpu(curp->p_hdr->eh_max));
+                            > le16_to_cpu(curp->p_hdr->eh_max));
        BUG_ON(ix > EXT_LAST_INDEX(curp->p_hdr));
 
        err = ext4_ext_dirty(handle, inode, curp);
@@ -621,12 +621,12 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                border = path[depth].p_ext[1].ee_block;
                ext_debug("leaf will be split."
                                " next leaf starts at %d\n",
-                                 le32_to_cpu(border));
+                                 le32_to_cpu(border));
        } else {
                border = newext->ee_block;
                ext_debug("leaf will be added."
                                " next leaf starts at %d\n",
-                               le32_to_cpu(border));
+                               le32_to_cpu(border));
        }
 
        /*
@@ -641,10 +641,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
         * We need this to handle errors and free blocks
         * upon them.
         */
-       ablocks = kmalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS);
+       ablocks = kzalloc(sizeof(ext4_fsblk_t) * depth, GFP_NOFS);
        if (!ablocks)
                return -ENOMEM;
-       memset(ablocks, 0, sizeof(ext4_fsblk_t) * depth);
 
        /* allocate all needed blocks */
        ext_debug("allocate %d blocks for indexes/leaf\n", depth - at);
@@ -665,7 +664,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        }
        lock_buffer(bh);
 
-       if ((err = ext4_journal_get_create_access(handle, bh)))
+       err = ext4_journal_get_create_access(handle, bh);
+       if (err)
                goto cleanup;
 
        neh = ext_block_hdr(bh);
@@ -684,9 +684,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        while (path[depth].p_ext <=
                        EXT_MAX_EXTENT(path[depth].p_hdr)) {
                ext_debug("move %d:%llu:%d in new leaf %llu\n",
-                               le32_to_cpu(path[depth].p_ext->ee_block),
-                               ext_pblock(path[depth].p_ext),
-                               le16_to_cpu(path[depth].p_ext->ee_len),
+                               le32_to_cpu(path[depth].p_ext->ee_block),
+                               ext_pblock(path[depth].p_ext),
+                               le16_to_cpu(path[depth].p_ext->ee_len),
                                newblock);
                /*memmove(ex++, path[depth].p_ext++,
                                sizeof(struct ext4_extent));
@@ -702,18 +702,21 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
 
-       if ((err = ext4_journal_dirty_metadata(handle, bh)))
+       err = ext4_journal_dirty_metadata(handle, bh);
+       if (err)
                goto cleanup;
        brelse(bh);
        bh = NULL;
 
        /* correct old leaf */
        if (m) {
-               if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
                        goto cleanup;
                path[depth].p_hdr->eh_entries =
                     cpu_to_le16(le16_to_cpu(path[depth].p_hdr->eh_entries)-m);
-               if ((err = ext4_ext_dirty(handle, inode, path + depth)))
+               err = ext4_ext_dirty(handle, inode, path + depth);
+               if (err)
                        goto cleanup;
 
        }
@@ -736,7 +739,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                }
                lock_buffer(bh);
 
-               if ((err = ext4_journal_get_create_access(handle, bh)))
+               err = ext4_journal_get_create_access(handle, bh);
+               if (err)
                        goto cleanup;
 
                neh = ext_block_hdr(bh);
@@ -761,9 +765,9 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                                EXT_LAST_INDEX(path[i].p_hdr));
                while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {
                        ext_debug("%d: move %d:%d in new index %llu\n", i,
-                                       le32_to_cpu(path[i].p_idx->ei_block),
-                                       idx_pblock(path[i].p_idx),
-                                       newblock);
+                                       le32_to_cpu(path[i].p_idx->ei_block),
+                                       idx_pblock(path[i].p_idx),
+                                       newblock);
                        /*memmove(++fidx, path[i].p_idx++,
                                        sizeof(struct ext4_extent_idx));
                        neh->eh_entries++;
@@ -780,7 +784,8 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                set_buffer_uptodate(bh);
                unlock_buffer(bh);
 
-               if ((err = ext4_journal_dirty_metadata(handle, bh)))
+               err = ext4_journal_dirty_metadata(handle, bh);
+               if (err)
                        goto cleanup;
                brelse(bh);
                bh = NULL;
@@ -800,9 +805,6 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        }
 
        /* insert new index */
-       if (err)
-               goto cleanup;
-
        err = ext4_ext_insert_index(handle, inode, path + at,
                                    le32_to_cpu(border), newblock);
 
@@ -857,7 +859,8 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        }
        lock_buffer(bh);
 
-       if ((err = ext4_journal_get_create_access(handle, bh))) {
+       err = ext4_journal_get_create_access(handle, bh);
+       if (err) {
                unlock_buffer(bh);
                goto out;
        }
@@ -877,11 +880,13 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
 
-       if ((err = ext4_journal_dirty_metadata(handle, bh)))
+       err = ext4_journal_dirty_metadata(handle, bh);
+       if (err)
                goto out;
 
        /* create index in new top-level index: num,max,pointer */
-       if ((err = ext4_ext_get_access(handle, inode, curp)))
+       err = ext4_ext_get_access(handle, inode, curp);
+       if (err)
                goto out;
 
        curp->p_hdr->eh_magic = EXT4_EXT_MAGIC;
@@ -1073,27 +1078,31 @@ int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
         */
        k = depth - 1;
        border = path[depth].p_ext->ee_block;
-       if ((err = ext4_ext_get_access(handle, inode, path + k)))
+       err = ext4_ext_get_access(handle, inode, path + k);
+       if (err)
                return err;
        path[k].p_idx->ei_block = border;
-       if ((err = ext4_ext_dirty(handle, inode, path + k)))
+       err = ext4_ext_dirty(handle, inode, path + k);
+       if (err)
                return err;
 
        while (k--) {
                /* change all left-side indexes */
                if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))
                        break;
-               if ((err = ext4_ext_get_access(handle, inode, path + k)))
+               err = ext4_ext_get_access(handle, inode, path + k);
+               if (err)
                        break;
                path[k].p_idx->ei_block = border;
-               if ((err = ext4_ext_dirty(handle, inode, path + k)))
+               err = ext4_ext_dirty(handle, inode, path + k);
+               if (err)
                        break;
        }
 
        return err;
 }
 
-static int inline
+static int
 ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
                                struct ext4_extent *ex2)
 {
@@ -1108,7 +1117,7 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
         */
        if (le16_to_cpu(ex1->ee_len) + le16_to_cpu(ex2->ee_len) > EXT_MAX_LEN)
                return 0;
-#ifdef AGRESSIVE_TEST
+#ifdef AGGRESSIVE_TEST
        if (le16_to_cpu(ex1->ee_len) >= 4)
                return 0;
 #endif
@@ -1118,6 +1127,55 @@ ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
        return 0;
 }
 
+/*
+ * check if a portion of the "newext" extent overlaps with an
+ * existing extent.
+ *
+ * If there is an overlap discovered, it updates the length of the newext
+ * such that there will be no overlap, and then returns 1.
+ * If there is no overlap found, it returns 0.
+ */
+unsigned int ext4_ext_check_overlap(struct inode *inode,
+                                   struct ext4_extent *newext,
+                                   struct ext4_ext_path *path)
+{
+       unsigned long b1, b2;
+       unsigned int depth, len1;
+       unsigned int ret = 0;
+
+       b1 = le32_to_cpu(newext->ee_block);
+       len1 = le16_to_cpu(newext->ee_len);
+       depth = ext_depth(inode);
+       if (!path[depth].p_ext)
+               goto out;
+       b2 = le32_to_cpu(path[depth].p_ext->ee_block);
+
+       /*
+        * get the next allocated block if the extent in the path
+        * is before the requested block(s) 
+        */
+       if (b2 < b1) {
+               b2 = ext4_ext_next_allocated_block(path);
+               if (b2 == EXT_MAX_BLOCK)
+                       goto out;
+       }
+
+       /* check for wrap through zero */
+       if (b1 + len1 < b1) {
+               len1 = EXT_MAX_BLOCK - b1;
+               newext->ee_len = cpu_to_le16(len1);
+               ret = 1;
+       }
+
+       /* check for overlap */
+       if (b1 + len1 > b2) {
+               newext->ee_len = cpu_to_le16(b2 - b1);
+               ret = 1;
+       }
+out:
+       return ret;
+}
+
 /*
  * ext4_ext_insert_extent:
  * tries to merge requsted extent into the existing extent or
@@ -1145,7 +1203,8 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                                le16_to_cpu(newext->ee_len),
                                le32_to_cpu(ex->ee_block),
                                le16_to_cpu(ex->ee_len), ext_pblock(ex));
-               if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
                        return err;
                ex->ee_len = cpu_to_le16(le16_to_cpu(ex->ee_len)
                                         + le16_to_cpu(newext->ee_len));
@@ -1195,18 +1254,19 @@ repeat:
 has_space:
        nearex = path[depth].p_ext;
 
-       if ((err = ext4_ext_get_access(handle, inode, path + depth)))
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
                goto cleanup;
 
        if (!nearex) {
                /* there is no extent in this leaf, create first one */
                ext_debug("first extent in the leaf: %d:%llu:%d\n",
-                               le32_to_cpu(newext->ee_block),
-                               ext_pblock(newext),
-                               le16_to_cpu(newext->ee_len));
+                               le32_to_cpu(newext->ee_block),
+                               ext_pblock(newext),
+                               le16_to_cpu(newext->ee_len));
                path[depth].p_ext = EXT_FIRST_EXTENT(eh);
        } else if (le32_to_cpu(newext->ee_block)
-                          > le32_to_cpu(nearex->ee_block)) {
+                          > le32_to_cpu(nearex->ee_block)) {
 /*             BUG_ON(newext->ee_block == nearex->ee_block); */
                if (nearex != EXT_LAST_EXTENT(eh)) {
                        len = EXT_MAX_EXTENT(eh) - nearex;
@@ -1214,9 +1274,9 @@ has_space:
                        len = len < 0 ? 0 : len;
                        ext_debug("insert %d:%llu:%d after: nearest 0x%p, "
                                        "move %d from 0x%p to 0x%p\n",
-                                       le32_to_cpu(newext->ee_block),
-                                       ext_pblock(newext),
-                                       le16_to_cpu(newext->ee_len),
+                                       le32_to_cpu(newext->ee_block),
+                                       ext_pblock(newext),
+                                       le16_to_cpu(newext->ee_len),
                                        nearex, len, nearex + 1, nearex + 2);
                        memmove(nearex + 2, nearex + 1, len);
                }
@@ -1347,9 +1407,9 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
                        cbex.ec_start = 0;
                        cbex.ec_type = EXT4_EXT_CACHE_GAP;
                } else {
-                       cbex.ec_block = le32_to_cpu(ex->ee_block);
-                       cbex.ec_len = le16_to_cpu(ex->ee_len);
-                       cbex.ec_start = ext_pblock(ex);
+                       cbex.ec_block = le32_to_cpu(ex->ee_block);
+                       cbex.ec_len = le16_to_cpu(ex->ee_len);
+                       cbex.ec_start = ext_pblock(ex);
                        cbex.ec_type = EXT4_EXT_CACHE_EXTENT;
                }
 
@@ -1383,7 +1443,7 @@ int ext4_ext_walk_space(struct inode *inode, unsigned long block,
        return err;
 }
 
-static inline void
+static void
 ext4_ext_put_in_cache(struct inode *inode, __u32 block,
                        __u32 len, __u32 start, int type)
 {
@@ -1401,7 +1461,7 @@ ext4_ext_put_in_cache(struct inode *inode, __u32 block,
  * calculate boundaries of the gap that the requested block fits into
  * and cache this gap
  */
-static inline void
+static void
 ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
                                unsigned long block)
 {
@@ -1420,16 +1480,16 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
                len = le32_to_cpu(ex->ee_block) - block;
                ext_debug("cache gap(before): %lu [%lu:%lu]",
                                (unsigned long) block,
-                               (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len));
+                               (unsigned long) le32_to_cpu(ex->ee_block),
+                               (unsigned long) le16_to_cpu(ex->ee_len));
        } else if (block >= le32_to_cpu(ex->ee_block)
-                           + le16_to_cpu(ex->ee_len)) {
-               lblock = le32_to_cpu(ex->ee_block)
-                        + le16_to_cpu(ex->ee_len);
+                           + le16_to_cpu(ex->ee_len)) {
+               lblock = le32_to_cpu(ex->ee_block)
+                        + le16_to_cpu(ex->ee_len);
                len = ext4_ext_next_allocated_block(path);
                ext_debug("cache gap(after): [%lu:%lu] %lu",
-                               (unsigned long) le32_to_cpu(ex->ee_block),
-                               (unsigned long) le16_to_cpu(ex->ee_len),
+                               (unsigned long) le32_to_cpu(ex->ee_block),
+                               (unsigned long) le16_to_cpu(ex->ee_len),
                                (unsigned long) block);
                BUG_ON(len == lblock);
                len = len - lblock;
@@ -1442,7 +1502,7 @@ ext4_ext_put_gap_in_cache(struct inode *inode, struct ext4_ext_path *path,
        ext4_ext_put_in_cache(inode, lblock, len, 0, EXT4_EXT_CACHE_GAP);
 }
 
-static inline int
+static int
 ext4_ext_in_cache(struct inode *inode, unsigned long block,
                        struct ext4_extent *ex)
 {
@@ -1457,9 +1517,9 @@ ext4_ext_in_cache(struct inode *inode, unsigned long block,
        BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
                        cex->ec_type != EXT4_EXT_CACHE_EXTENT);
        if (block >= cex->ec_block && block < cex->ec_block + cex->ec_len) {
-               ex->ee_block = cpu_to_le32(cex->ec_block);
+               ex->ee_block = cpu_to_le32(cex->ec_block);
                ext4_ext_store_pblock(ex, cex->ec_start);
-               ex->ee_len = cpu_to_le16(cex->ec_len);
+               ex->ee_len = cpu_to_le16(cex->ec_len);
                ext_debug("%lu cached by %lu:%lu:%llu\n",
                                (unsigned long) block,
                                (unsigned long) cex->ec_block,
@@ -1489,10 +1549,12 @@ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
        path--;
        leaf = idx_pblock(path->p_idx);
        BUG_ON(path->p_hdr->eh_entries == 0);
-       if ((err = ext4_ext_get_access(handle, inode, path)))
+       err = ext4_ext_get_access(handle, inode, path);
+       if (err)
                return err;
        path->p_hdr->eh_entries = cpu_to_le16(le16_to_cpu(path->p_hdr->eh_entries)-1);
-       if ((err = ext4_ext_dirty(handle, inode, path)))
+       err = ext4_ext_dirty(handle, inode, path);
+       if (err)
                return err;
        ext_debug("index is empty, remove it, free block %llu\n", leaf);
        bh = sb_find_get_block(inode->i_sb, leaf);
@@ -1509,7 +1571,7 @@ int ext4_ext_rm_idx(handle_t *handle, struct inode *inode,
  * the caller should calculate credits under truncate_mutex and
  * pass the actual path.
  */
-int inline ext4_ext_calc_credits_for_insert(struct inode *inode,
+int ext4_ext_calc_credits_for_insert(struct inode *inode,
                                                struct ext4_ext_path *path)
 {
        int depth, needed;
@@ -1534,16 +1596,17 @@ int inline ext4_ext_calc_credits_for_insert(struct inode *inode,
 
        /*
         * tree can be full, so it would need to grow in depth:
-        * allocation + old root + new root
+        * we need one credit to modify old root, credits for
+        * new root will be added in split accounting
         */
-       needed += 2 + 1 + 1;
+       needed += 1;
 
        /*
         * Index split can happen, we would need:
         *    allocate intermediate indexes (bitmap + group)
         *  + change two blocks at each level, but root (already included)
         */
-       needed = (depth * 2) + (depth * 2);
+       needed += (depth * 2) + (depth * 2);
 
        /* any allocation modifies superblock */
        needed += 1;
@@ -1718,7 +1781,7 @@ out:
  * ext4_ext_more_to_rm:
  * returns 1 if current index has to be freed (even partial)
  */
-static int inline
+static int
 ext4_ext_more_to_rm(struct ext4_ext_path *path)
 {
        BUG_ON(path->p_idx == NULL);
@@ -1756,12 +1819,11 @@ int ext4_ext_remove_space(struct inode *inode, unsigned long start)
         * We start scanning from right side, freeing all the blocks
         * after i_size and walking into the tree depth-wise.
         */
-       path = kmalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
+       path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1), GFP_KERNEL);
        if (path == NULL) {
                ext4_journal_stop(handle);
                return -ENOMEM;
        }
-       memset(path, 0, sizeof(struct ext4_ext_path) * (depth + 1));
        path[0].p_hdr = ext_inode_hdr(inode);
        if (ext4_ext_check_header(__FUNCTION__, inode, path[0].p_hdr)) {
                err = -EIO;
@@ -1877,8 +1939,8 @@ void ext4_ext_init(struct super_block *sb)
 
        if (test_opt(sb, EXTENTS)) {
                printk("EXT4-fs: file extents enabled");
-#ifdef AGRESSIVE_TEST
-               printk(", agressive tests");
+#ifdef AGGRESSIVE_TEST
+               printk(", aggressive tests");
 #endif
 #ifdef CHECK_BINSEARCH
                printk(", check binsearch");
@@ -1932,7 +1994,8 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        mutex_lock(&EXT4_I(inode)->truncate_mutex);
 
        /* check in cache */
-       if ((goal = ext4_ext_in_cache(inode, iblock, &newex))) {
+       goal = ext4_ext_in_cache(inode, iblock, &newex);
+       if (goal) {
                if (goal == EXT4_EXT_CACHE_GAP) {
                        if (!create) {
                                /* block isn't allocated yet and
@@ -1942,9 +2005,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        /* we should allocate requested block */
                } else if (goal == EXT4_EXT_CACHE_EXTENT) {
                        /* block is already allocated */
-                       newblock = iblock
-                                  - le32_to_cpu(newex.ee_block)
-                                  + ext_pblock(&newex);
+                       newblock = iblock
+                                  - le32_to_cpu(newex.ee_block)
+                                  + ext_pblock(&newex);
                        /* number of remaining blocks in the extent */
                        allocated = le16_to_cpu(newex.ee_len) -
                                        (iblock - le32_to_cpu(newex.ee_block));
@@ -1971,8 +2034,9 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         */
        BUG_ON(path[depth].p_ext == NULL && depth != 0);
 
-       if ((ex = path[depth].p_ext)) {
-               unsigned long ee_block = le32_to_cpu(ex->ee_block);
+       ex = path[depth].p_ext;
+       if (ex) {
+               unsigned long ee_block = le32_to_cpu(ex->ee_block);
                ext4_fsblk_t ee_start = ext_pblock(ex);
                unsigned short ee_len  = le16_to_cpu(ex->ee_len);
 
@@ -1985,7 +2049,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                if (ee_len > EXT_MAX_LEN)
                        goto out2;
                /* if found extent covers block, simply return it */
-               if (iblock >= ee_block && iblock < ee_block + ee_len) {
+               if (iblock >= ee_block && iblock < ee_block + ee_len) {
                        newblock = iblock - ee_block + ee_start;
                        /* number of remaining blocks in the extent */
                        allocated = ee_len - (iblock - ee_block);
@@ -2016,7 +2080,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
 
        /* allocate new block */
        goal = ext4_ext_find_goal(inode, path, iblock);
-       allocated = max_blocks;
+
+       /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
+       newex.ee_block = cpu_to_le32(iblock);
+       newex.ee_len = cpu_to_le16(max_blocks);
+       err = ext4_ext_check_overlap(inode, &newex, path);
+       if (err)
+               allocated = le16_to_cpu(newex.ee_len);
+       else
+               allocated = max_blocks;
        newblock = ext4_new_blocks(handle, inode, goal, &allocated, &err);
        if (!newblock)
                goto out2;
@@ -2024,12 +2096,15 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        goal, newblock, allocated);
 
        /* try to insert new extent into found leaf and return */
-       newex.ee_block = cpu_to_le32(iblock);
        ext4_ext_store_pblock(&newex, newblock);
        newex.ee_len = cpu_to_le16(allocated);
        err = ext4_ext_insert_extent(handle, inode, path, &newex);
-       if (err)
+       if (err) {
+               /* free data blocks we just allocated */
+               ext4_free_blocks(handle, inode, ext_pblock(&newex),
+                                       le16_to_cpu(newex.ee_len));
                goto out2;
+       }
 
        if (extend_disksize && inode->i_size > EXT4_I(inode)->i_disksize)
                EXT4_I(inode)->i_disksize = inode->i_size;
@@ -2142,11 +2217,3 @@ int ext4_ext_writepage_trans_blocks(struct inode *inode, int num)
 
        return needed;
 }
-
-EXPORT_SYMBOL(ext4_mark_inode_dirty);
-EXPORT_SYMBOL(ext4_ext_invalidate_cache);
-EXPORT_SYMBOL(ext4_ext_insert_extent);
-EXPORT_SYMBOL(ext4_ext_walk_space);
-EXPORT_SYMBOL(ext4_ext_find_goal);
-EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
-