ext4: EXT4_IOC_MOVE_EXT: Check for different original and donor inodes first
[safe/jmp/linux-2.6] / fs / ext4 / extents.c
index e403321..10a6309 100644 (file)
@@ -49,7 +49,7 @@
  * ext_pblock:
  * combine low and high parts of physical block number into ext4_fsblk_t
  */
-static ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
+ext4_fsblk_t ext_pblock(struct ext4_extent *ex)
 {
        ext4_fsblk_t block;
 
@@ -93,7 +93,9 @@ static void ext4_idx_store_pblock(struct ext4_extent_idx *ix, ext4_fsblk_t pb)
        ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) & 0xffff);
 }
 
-static int ext4_ext_journal_restart(handle_t *handle, int needed)
+static int ext4_ext_truncate_extend_restart(handle_t *handle,
+                                           struct inode *inode,
+                                           int needed)
 {
        int err;
 
@@ -104,7 +106,14 @@ static int ext4_ext_journal_restart(handle_t *handle, int needed)
        err = ext4_journal_extend(handle, needed);
        if (err <= 0)
                return err;
-       return ext4_journal_restart(handle, needed);
+       err = ext4_truncate_restart_trans(handle, inode, needed);
+       /*
+        * We have dropped i_data_sem so someone might have cached again
+        * an extent we are going to truncate.
+        */
+       ext4_ext_invalidate_cache(inode);
+
+       return err;
 }
 
 /*
@@ -220,57 +229,65 @@ ext4_ext_new_meta_block(handle_t *handle, struct inode *inode,
        return newblock;
 }
 
-static int ext4_ext_space_block(struct inode *inode)
+static inline int ext4_ext_space_block(struct inode *inode, int check)
 {
        int size;
 
        size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
                        / sizeof(struct ext4_extent);
+       if (!check) {
 #ifdef AGGRESSIVE_TEST
-       if (size > 6)
-               size = 6;
+               if (size > 6)
+                       size = 6;
 #endif
+       }
        return size;
 }
 
-static int ext4_ext_space_block_idx(struct inode *inode)
+static inline int ext4_ext_space_block_idx(struct inode *inode, int check)
 {
        int size;
 
        size = (inode->i_sb->s_blocksize - sizeof(struct ext4_extent_header))
                        / sizeof(struct ext4_extent_idx);
+       if (!check) {
 #ifdef AGGRESSIVE_TEST
-       if (size > 5)
-               size = 5;
+               if (size > 5)
+                       size = 5;
 #endif
+       }
        return size;
 }
 
-static int ext4_ext_space_root(struct inode *inode)
+static inline int ext4_ext_space_root(struct inode *inode, int check)
 {
        int size;
 
        size = sizeof(EXT4_I(inode)->i_data);
        size -= sizeof(struct ext4_extent_header);
        size /= sizeof(struct ext4_extent);
+       if (!check) {
 #ifdef AGGRESSIVE_TEST
-       if (size > 3)
-               size = 3;
+               if (size > 3)
+                       size = 3;
 #endif
+       }
        return size;
 }
 
-static int ext4_ext_space_root_idx(struct inode *inode)
+static inline int ext4_ext_space_root_idx(struct inode *inode, int check)
 {
        int size;
 
        size = sizeof(EXT4_I(inode)->i_data);
        size -= sizeof(struct ext4_extent_header);
        size /= sizeof(struct ext4_extent_idx);
+       if (!check) {
 #ifdef AGGRESSIVE_TEST
-       if (size > 4)
-               size = 4;
+               if (size > 4)
+                       size = 4;
 #endif
+       }
        return size;
 }
 
@@ -284,9 +301,9 @@ int ext4_ext_calc_metadata_amount(struct inode *inode, int blocks)
        int lcap, icap, rcap, leafs, idxs, num;
        int newextents = blocks;
 
-       rcap = ext4_ext_space_root_idx(inode);
-       lcap = ext4_ext_space_block(inode);
-       icap = ext4_ext_space_block_idx(inode);
+       rcap = ext4_ext_space_root_idx(inode, 0);
+       lcap = ext4_ext_space_block(inode, 0);
+       icap = ext4_ext_space_block_idx(inode, 0);
 
        /* number of new leaf blocks needed */
        num = leafs = (newextents + lcap - 1) / lcap;
@@ -311,14 +328,14 @@ ext4_ext_max_entries(struct inode *inode, int depth)
 
        if (depth == ext_depth(inode)) {
                if (depth == 0)
-                       max = ext4_ext_space_root(inode);
+                       max = ext4_ext_space_root(inode, 1);
                else
-                       max = ext4_ext_space_root_idx(inode);
+                       max = ext4_ext_space_root_idx(inode, 1);
        } else {
                if (depth == 0)
-                       max = ext4_ext_space_block(inode);
+                       max = ext4_ext_space_block(inode, 1);
                else
-                       max = ext4_ext_space_block_idx(inode);
+                       max = ext4_ext_space_block_idx(inode, 1);
        }
 
        return max;
@@ -326,32 +343,18 @@ ext4_ext_max_entries(struct inode *inode, int depth)
 
 static int ext4_valid_extent(struct inode *inode, struct ext4_extent *ext)
 {
-       ext4_fsblk_t block = ext_pblock(ext), valid_block;
+       ext4_fsblk_t block = ext_pblock(ext);
        int len = ext4_ext_get_actual_len(ext);
-       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
 
-       valid_block = le32_to_cpu(es->s_first_data_block) +
-               EXT4_SB(inode->i_sb)->s_gdb_count;
-       if (unlikely(block <= valid_block ||
-                    ((block + len) > ext4_blocks_count(es))))
-               return 0;
-       else
-               return 1;
+       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, len);
 }
 
 static int ext4_valid_extent_idx(struct inode *inode,
                                struct ext4_extent_idx *ext_idx)
 {
-       ext4_fsblk_t block = idx_pblock(ext_idx), valid_block;
-       struct ext4_super_block *es = EXT4_SB(inode->i_sb)->s_es;
+       ext4_fsblk_t block = idx_pblock(ext_idx);
 
-       valid_block = le32_to_cpu(es->s_first_data_block) +
-               EXT4_SB(inode->i_sb)->s_gdb_count;
-       if (unlikely(block <= valid_block ||
-                    (block >= ext4_blocks_count(es))))
-               return 0;
-       else
-               return 1;
+       return ext4_data_block_valid(EXT4_SB(inode->i_sb), block, 1);
 }
 
 static int ext4_valid_extent_entries(struct inode *inode,
@@ -451,8 +454,9 @@ static void ext4_ext_show_path(struct inode *inode, struct ext4_ext_path *path)
                  ext_debug("  %d->%llu", le32_to_cpu(path->p_idx->ei_block),
                            idx_pblock(path->p_idx));
                } else if (path->p_ext) {
-                       ext_debug("  %d:%d:%llu ",
+                       ext_debug("  %d:[%d]%d:%llu ",
                                  le32_to_cpu(path->p_ext->ee_block),
+                                 ext4_ext_is_uninitialized(path->p_ext),
                                  ext4_ext_get_actual_len(path->p_ext),
                                  ext_pblock(path->p_ext));
                } else
@@ -474,8 +478,11 @@ static void ext4_ext_show_leaf(struct inode *inode, struct ext4_ext_path *path)
        eh = path[depth].p_hdr;
        ex = EXT_FIRST_EXTENT(eh);
 
+       ext_debug("Displaying leaf extents for inode %lu\n", inode->i_ino);
+
        for (i = 0; i < le16_to_cpu(eh->eh_entries); i++, ex++) {
-               ext_debug("%d:%d:%llu ", le32_to_cpu(ex->ee_block),
+               ext_debug("%d:[%d]%d:%llu ", le32_to_cpu(ex->ee_block),
+                         ext4_ext_is_uninitialized(ex),
                          ext4_ext_get_actual_len(ex), ext_pblock(ex));
        }
        ext_debug("\n");
@@ -594,9 +601,10 @@ ext4_ext_binsearch(struct inode *inode,
        }
 
        path->p_ext = l - 1;
-       ext_debug("  -> %d:%llu:%d ",
+       ext_debug("  -> %d:%llu:[%d]%d ",
                        le32_to_cpu(path->p_ext->ee_block),
                        ext_pblock(path->p_ext),
+                       ext4_ext_is_uninitialized(path->p_ext),
                        ext4_ext_get_actual_len(path->p_ext));
 
 #ifdef CHECK_BINSEARCH
@@ -626,7 +634,7 @@ int ext4_ext_tree_init(handle_t *handle, struct inode *inode)
        eh->eh_depth = 0;
        eh->eh_entries = 0;
        eh->eh_magic = EXT4_EXT_MAGIC;
-       eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode));
+       eh->eh_max = cpu_to_le16(ext4_ext_space_root(inode, 0));
        ext4_mark_inode_dirty(handle, inode);
        ext4_ext_invalidate_cache(inode);
        return 0;
@@ -715,7 +723,7 @@ err:
  * insert new index [@logical;@ptr] into the block at @curp;
  * check where to insert: before @curp or after @curp
  */
-static int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
+int ext4_ext_insert_index(handle_t *handle, struct inode *inode,
                                struct ext4_ext_path *curp,
                                int logical, ext4_fsblk_t ptr)
 {
@@ -851,7 +859,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
 
        neh = ext_block_hdr(bh);
        neh->eh_entries = 0;
-       neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
+       neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
        neh->eh_magic = EXT4_EXT_MAGIC;
        neh->eh_depth = 0;
        ex = EXT_FIRST_EXTENT(neh);
@@ -864,9 +872,10 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
        path[depth].p_ext++;
        while (path[depth].p_ext <=
                        EXT_MAX_EXTENT(path[depth].p_hdr)) {
-               ext_debug("move %d:%llu:%d in new leaf %llu\n",
+               ext_debug("move %d:%llu:[%d]%d in new leaf %llu\n",
                                le32_to_cpu(path[depth].p_ext->ee_block),
                                ext_pblock(path[depth].p_ext),
+                               ext4_ext_is_uninitialized(path[depth].p_ext),
                                ext4_ext_get_actual_len(path[depth].p_ext),
                                newblock);
                /*memmove(ex++, path[depth].p_ext++,
@@ -926,7 +935,7 @@ static int ext4_ext_split(handle_t *handle, struct inode *inode,
                neh = ext_block_hdr(bh);
                neh->eh_entries = cpu_to_le16(1);
                neh->eh_magic = EXT4_EXT_MAGIC;
-               neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
+               neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
                neh->eh_depth = cpu_to_le16(depth - i);
                fidx = EXT_FIRST_INDEX(neh);
                fidx->ei_block = border;
@@ -1051,9 +1060,9 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
        /* old root could have indexes or leaves
         * so calculate e_max right way */
        if (ext_depth(inode))
-         neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode));
+               neh->eh_max = cpu_to_le16(ext4_ext_space_block_idx(inode, 0));
        else
-         neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode));
+               neh->eh_max = cpu_to_le16(ext4_ext_space_block(inode, 0));
        neh->eh_magic = EXT4_EXT_MAGIC;
        set_buffer_uptodate(bh);
        unlock_buffer(bh);
@@ -1068,7 +1077,7 @@ static int ext4_ext_grow_indepth(handle_t *handle, struct inode *inode,
                goto out;
 
        curp->p_hdr->eh_magic = EXT4_EXT_MAGIC;
-       curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode));
+       curp->p_hdr->eh_max = cpu_to_le16(ext4_ext_space_root_idx(inode, 0));
        curp->p_hdr->eh_entries = cpu_to_le16(1);
        curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);
 
@@ -1431,7 +1440,7 @@ static int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,
        return err;
 }
 
-static int
+int
 ext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,
                                struct ext4_extent *ex2)
 {
@@ -1577,7 +1586,7 @@ out:
  */
 int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
                                struct ext4_ext_path *path,
-                               struct ext4_extent *newext)
+                               struct ext4_extent *newext, int flag)
 {
        struct ext4_extent_header *eh;
        struct ext4_extent *ex, *fex;
@@ -1593,10 +1602,13 @@ int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,
        BUG_ON(path[depth].p_hdr == NULL);
 
        /* try to insert block into found extent and return */
-       if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {
-               ext_debug("append %d block to %d:%d (from %llu)\n",
+       if (ex && (flag != EXT4_GET_BLOCKS_DIO_CREATE_EXT)
+               && ext4_can_extents_be_merged(inode, ex, newext)) {
+               ext_debug("append [%d]%d block to %d:[%d]%d (from %llu)\n",
+                               ext4_ext_is_uninitialized(newext),
                                ext4_ext_get_actual_len(newext),
                                le32_to_cpu(ex->ee_block),
+                               ext4_ext_is_uninitialized(ex),
                                ext4_ext_get_actual_len(ex), ext_pblock(ex));
                err = ext4_ext_get_access(handle, inode, path + depth);
                if (err)
@@ -1665,9 +1677,10 @@ has_space:
 
        if (!nearex) {
                /* there is no extent in this leaf, create first one */
-               ext_debug("first extent in the leaf: %d:%llu:%d\n",
+               ext_debug("first extent in the leaf: %d:%llu:[%d]%d\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
+                               ext4_ext_is_uninitialized(newext),
                                ext4_ext_get_actual_len(newext));
                path[depth].p_ext = EXT_FIRST_EXTENT(eh);
        } else if (le32_to_cpu(newext->ee_block)
@@ -1677,10 +1690,11 @@ has_space:
                        len = EXT_MAX_EXTENT(eh) - nearex;
                        len = (len - 1) * sizeof(struct ext4_extent);
                        len = len < 0 ? 0 : len;
-                       ext_debug("insert %d:%llu:%d after: nearest 0x%p, "
+                       ext_debug("insert %d:%llu:[%d]%d after: nearest 0x%p, "
                                        "move %d from 0x%p to 0x%p\n",
                                        le32_to_cpu(newext->ee_block),
                                        ext_pblock(newext),
+                                       ext4_ext_is_uninitialized(newext),
                                        ext4_ext_get_actual_len(newext),
                                        nearex, len, nearex + 1, nearex + 2);
                        memmove(nearex + 2, nearex + 1, len);
@@ -1690,10 +1704,11 @@ has_space:
                BUG_ON(newext->ee_block == nearex->ee_block);
                len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent);
                len = len < 0 ? 0 : len;
-               ext_debug("insert %d:%llu:%d before: nearest 0x%p, "
+               ext_debug("insert %d:%llu:[%d]%d before: nearest 0x%p, "
                                "move %d from 0x%p to 0x%p\n",
                                le32_to_cpu(newext->ee_block),
                                ext_pblock(newext),
+                               ext4_ext_is_uninitialized(newext),
                                ext4_ext_get_actual_len(newext),
                                nearex, len, nearex + 1, nearex + 2);
                memmove(nearex + 1, nearex, len);
@@ -1708,7 +1723,8 @@ has_space:
 
 merge:
        /* try to merge extents to the right */
-       ext4_ext_try_to_merge(inode, path, nearex);
+       if (flag != EXT4_GET_BLOCKS_DIO_CREATE_EXT)
+               ext4_ext_try_to_merge(inode, path, nearex);
 
        /* try to merge extents to the left */
 
@@ -1841,11 +1857,13 @@ ext4_ext_put_in_cache(struct inode *inode, ext4_lblk_t block,
 {
        struct ext4_ext_cache *cex;
        BUG_ON(len == 0);
+       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        cex = &EXT4_I(inode)->i_cached_extent;
        cex->ec_type = type;
        cex->ec_block = block;
        cex->ec_len = len;
        cex->ec_start = start;
+       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
 }
 
 /*
@@ -1902,12 +1920,17 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
                        struct ext4_extent *ex)
 {
        struct ext4_ext_cache *cex;
+       int ret = EXT4_EXT_CACHE_NO;
 
+       /* 
+        * We borrow i_block_reservation_lock to protect i_cached_extent
+        */
+       spin_lock(&EXT4_I(inode)->i_block_reservation_lock);
        cex = &EXT4_I(inode)->i_cached_extent;
 
        /* has cache valid data? */
        if (cex->ec_type == EXT4_EXT_CACHE_NO)
-               return EXT4_EXT_CACHE_NO;
+               goto errout;
 
        BUG_ON(cex->ec_type != EXT4_EXT_CACHE_GAP &&
                        cex->ec_type != EXT4_EXT_CACHE_EXTENT);
@@ -1918,11 +1941,11 @@ ext4_ext_in_cache(struct inode *inode, ext4_lblk_t block,
                ext_debug("%u cached by %u:%u:%llu\n",
                                block,
                                cex->ec_block, cex->ec_len, cex->ec_start);
-               return cex->ec_type;
+               ret = cex->ec_type;
        }
-
-       /* not in cache */
-       return EXT4_EXT_CACHE_NO;
+errout:
+       spin_unlock(&EXT4_I(inode)->i_block_reservation_lock);
+       return ret;
 }
 
 /*
@@ -1984,6 +2007,7 @@ int ext4_ext_calc_credits_for_single_extent(struct inode *inode, int nrblocks,
                         */
                        /* 1 bitmap, 1 block group descriptor */
                        ret = 2 + EXT4_META_TRANS_BLOCKS(inode->i_sb);
+                       return ret;
                }
        }
 
@@ -2090,13 +2114,18 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
        ex = EXT_LAST_EXTENT(eh);
 
        ex_ee_block = le32_to_cpu(ex->ee_block);
-       if (ext4_ext_is_uninitialized(ex))
-               uninitialized = 1;
        ex_ee_len = ext4_ext_get_actual_len(ex);
 
        while (ex >= EXT_FIRST_EXTENT(eh) &&
                        ex_ee_block + ex_ee_len > start) {
-               ext_debug("remove ext %lu:%u\n", ex_ee_block, ex_ee_len);
+
+               if (ext4_ext_is_uninitialized(ex))
+                       uninitialized = 1;
+               else
+                       uninitialized = 0;
+
+               ext_debug("remove ext %u:[%d]%d\n", ex_ee_block,
+                        uninitialized, ex_ee_len);
                path[depth].p_ext = ex;
 
                a = ex_ee_block > start ? ex_ee_block : start;
@@ -2140,7 +2169,7 @@ ext4_ext_rm_leaf(handle_t *handle, struct inode *inode,
                }
                credits += 2 * EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb);
 
-               err = ext4_ext_journal_restart(handle, credits);
+               err = ext4_ext_truncate_extend_restart(handle, inode, credits);
                if (err)
                        goto out;
 
@@ -2329,7 +2358,7 @@ static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
                if (err == 0) {
                        ext_inode_hdr(inode)->eh_depth = 0;
                        ext_inode_hdr(inode)->eh_max =
-                               cpu_to_le16(ext4_ext_space_root(inode));
+                               cpu_to_le16(ext4_ext_space_root(inode, 0));
                        err = ext4_ext_dirty(handle, inode, path);
                }
        }
@@ -2463,7 +2492,6 @@ static int ext4_ext_zeroout(struct inode *inode, struct ext4_extent *ex)
 }
 
 #define EXT4_EXT_ZERO_LEN 7
-
 /*
  * This function is called by ext4_ext_get_blocks() if someone tries to write
  * to an uninitialized extent. It may result in splitting the uninitialized
@@ -2556,7 +2584,8 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                        ex3->ee_block = cpu_to_le32(iblock);
                        ext4_ext_store_pblock(ex3, newblock);
                        ex3->ee_len = cpu_to_le16(allocated);
-                       err = ext4_ext_insert_extent(handle, inode, path, ex3);
+                       err = ext4_ext_insert_extent(handle, inode, path,
+                                                       ex3, 0);
                        if (err == -ENOSPC) {
                                err =  ext4_ext_zeroout(inode, &orig_ex);
                                if (err)
@@ -2612,7 +2641,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
                ext4_ext_store_pblock(ex3, newblock + max_blocks);
                ex3->ee_len = cpu_to_le16(allocated - max_blocks);
                ext4_ext_mark_uninitialized(ex3);
-               err = ext4_ext_insert_extent(handle, inode, path, ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, 0);
                if (err == -ENOSPC) {
                        err =  ext4_ext_zeroout(inode, &orig_ex);
                        if (err)
@@ -2730,7 +2759,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
        err = ext4_ext_dirty(handle, inode, path + depth);
        goto out;
 insert:
-       err = ext4_ext_insert_extent(handle, inode, path, &newex);
+       err = ext4_ext_insert_extent(handle, inode, path, &newex, 0);
        if (err == -ENOSPC) {
                err =  ext4_ext_zeroout(inode, &orig_ex);
                if (err)
@@ -2745,6 +2774,7 @@ insert:
        } else if (err)
                goto fix_extent_len;
 out:
+       ext4_ext_show_leaf(inode, path);
        return err ? err : allocated;
 
 fix_extent_len:
@@ -2757,6 +2787,324 @@ fix_extent_len:
 }
 
 /*
+ * This function is called by ext4_ext_get_blocks() from
+ * ext4_get_blocks_dio_write() when DIO to write
+ * to an uninitialized extent.
+ *
+ * Writing to an uninitized extent may result in splitting the uninitialized
+ * extent into multiple /intialized unintialized extents (up to three)
+ * There are three possibilities:
+ *   a> There is no split required: Entire extent should be uninitialized
+ *   b> Splits in two extents: Write is happening at either end of the extent
+ *   c> Splits in three extents: Somone is writing in middle of the extent
+ *
+ * One of more index blocks maybe needed if the extent tree grow after
+ * the unintialized extent split. To prevent ENOSPC occur at the IO
+ * complete, we need to split the uninitialized extent before DIO submit
+ * the IO. The uninitilized extent called at this time will be split
+ * into three uninitialized extent(at most). After IO complete, the part
+ * being filled will be convert to initialized by the end_io callback function
+ * via ext4_convert_unwritten_extents().
+ */
+static int ext4_split_unwritten_extents(handle_t *handle,
+                                       struct inode *inode,
+                                       struct ext4_ext_path *path,
+                                       ext4_lblk_t iblock,
+                                       unsigned int max_blocks,
+                                       int flags)
+{
+       struct ext4_extent *ex, newex, orig_ex;
+       struct ext4_extent *ex1 = NULL;
+       struct ext4_extent *ex2 = NULL;
+       struct ext4_extent *ex3 = NULL;
+       struct ext4_extent_header *eh;
+       ext4_lblk_t ee_block;
+       unsigned int allocated, ee_len, depth;
+       ext4_fsblk_t newblock;
+       int err = 0;
+       int ret = 0;
+
+       ext_debug("ext4_split_unwritten_extents: inode %lu,"
+                 "iblock %llu, max_blocks %u\n", inode->i_ino,
+                 (unsigned long long)iblock, max_blocks);
+       depth = ext_depth(inode);
+       eh = path[depth].p_hdr;
+       ex = path[depth].p_ext;
+       ee_block = le32_to_cpu(ex->ee_block);
+       ee_len = ext4_ext_get_actual_len(ex);
+       allocated = ee_len - (iblock - ee_block);
+       newblock = iblock - ee_block + ext_pblock(ex);
+       ex2 = ex;
+       orig_ex.ee_block = ex->ee_block;
+       orig_ex.ee_len   = cpu_to_le16(ee_len);
+       ext4_ext_store_pblock(&orig_ex, ext_pblock(ex));
+
+       /*
+        * if the entire unintialized extent length less than
+        * the size of extent to write, there is no need to split
+        * uninitialized extent
+        */
+       if (allocated <= max_blocks)
+               return ret;
+
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
+               goto out;
+       /* ex1: ee_block to iblock - 1 : uninitialized */
+       if (iblock > ee_block) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /*
+        * for sanity, update the length of the ex2 extent before
+        * we insert ex3, if ex1 is NULL. This is to avoid temporary
+        * overlap of blocks.
+        */
+       if (!ex1 && allocated > max_blocks)
+               ex2->ee_len = cpu_to_le16(max_blocks);
+       /* ex3: to ee_block + ee_len : uninitialised */
+       if (allocated > max_blocks) {
+               unsigned int newdepth;
+               ex3 = &newex;
+               ex3->ee_block = cpu_to_le32(iblock + max_blocks);
+               ext4_ext_store_pblock(ex3, newblock + max_blocks);
+               ex3->ee_len = cpu_to_le16(allocated - max_blocks);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
+               if (err == -ENOSPC) {
+                       err =  ext4_ext_zeroout(inode, &orig_ex);
+                       if (err)
+                               goto fix_extent_len;
+                       /* update the extent length and mark as initialized */
+                       ex->ee_block = orig_ex.ee_block;
+                       ex->ee_len   = orig_ex.ee_len;
+                       ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zeroed the full extent */
+                       /* blocks available from iblock */
+                       return allocated;
+
+               } else if (err)
+                       goto fix_extent_len;
+               /*
+                * The depth, and hence eh & ex might change
+                * as part of the insert above.
+                */
+               newdepth = ext_depth(inode);
+               /*
+                * update the extent length after successful insert of the
+                * split extent
+                */
+               orig_ex.ee_len = cpu_to_le16(ee_len -
+                                               ext4_ext_get_actual_len(ex3));
+               depth = newdepth;
+               ext4_ext_drop_refs(path);
+               path = ext4_ext_find_extent(inode, iblock, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+               }
+               eh = path[depth].p_hdr;
+               ex = path[depth].p_ext;
+               if (ex2 != &newex)
+                       ex2 = ex;
+
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
+                       goto out;
+
+               allocated = max_blocks;
+       }
+       /*
+        * If there was a change of depth as part of the
+        * insertion of ex3 above, we need to update the length
+        * of the ex1 extent again here
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+               ex1->ee_len = cpu_to_le16(iblock - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ex2 = &newex;
+       }
+       /*
+        * ex2: iblock to iblock + maxblocks-1 : to be direct IO written,
+        * uninitialised still.
+        */
+       ex2->ee_block = cpu_to_le32(iblock);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       ext4_ext_mark_uninitialized(ex2);
+       if (ex2 != ex)
+               goto insert;
+       /* Mark modified extent as dirty */
+       err = ext4_ext_dirty(handle, inode, path + depth);
+       ext_debug("out here\n");
+       goto out;
+insert:
+       err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
+       if (err == -ENOSPC) {
+               err =  ext4_ext_zeroout(inode, &orig_ex);
+               if (err)
+                       goto fix_extent_len;
+               /* update the extent length and mark as initialized */
+               ex->ee_block = orig_ex.ee_block;
+               ex->ee_len   = orig_ex.ee_len;
+               ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+               ext4_ext_dirty(handle, inode, path + depth);
+               /* zero out the first half */
+               return allocated;
+       } else if (err)
+               goto fix_extent_len;
+out:
+       ext4_ext_show_leaf(inode, path);
+       return err ? err : allocated;
+
+fix_extent_len:
+       ex->ee_block = orig_ex.ee_block;
+       ex->ee_len   = orig_ex.ee_len;
+       ext4_ext_store_pblock(ex, ext_pblock(&orig_ex));
+       ext4_ext_mark_uninitialized(ex);
+       ext4_ext_dirty(handle, inode, path + depth);
+       return err;
+}
+static int ext4_convert_unwritten_extents_dio(handle_t *handle,
+                                             struct inode *inode,
+                                             struct ext4_ext_path *path)
+{
+       struct ext4_extent *ex;
+       struct ext4_extent_header *eh;
+       int depth;
+       int err = 0;
+       int ret = 0;
+
+       depth = ext_depth(inode);
+       eh = path[depth].p_hdr;
+       ex = path[depth].p_ext;
+
+       err = ext4_ext_get_access(handle, inode, path + depth);
+       if (err)
+               goto out;
+       /* first mark the extent as initialized */
+       ext4_ext_mark_initialized(ex);
+
+       /*
+        * We have to see if it can be merged with the extent
+        * on the left.
+        */
+       if (ex > EXT_FIRST_EXTENT(eh)) {
+               /*
+                * To merge left, pass "ex - 1" to try_to_merge(),
+                * since it merges towards right _only_.
+                */
+               ret = ext4_ext_try_to_merge(inode, path, ex - 1);
+               if (ret) {
+                       err = ext4_ext_correct_indexes(handle, inode, path);
+                       if (err)
+                               goto out;
+                       depth = ext_depth(inode);
+                       ex--;
+               }
+       }
+       /*
+        * Try to Merge towards right.
+        */
+       ret = ext4_ext_try_to_merge(inode, path, ex);
+       if (ret) {
+               err = ext4_ext_correct_indexes(handle, inode, path);
+               if (err)
+                       goto out;
+               depth = ext_depth(inode);
+       }
+       /* Mark modified extent as dirty */
+       err = ext4_ext_dirty(handle, inode, path + depth);
+out:
+       ext4_ext_show_leaf(inode, path);
+       return err;
+}
+
+static int
+ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
+                       ext4_lblk_t iblock, unsigned int max_blocks,
+                       struct ext4_ext_path *path, int flags,
+                       unsigned int allocated, struct buffer_head *bh_result,
+                       ext4_fsblk_t newblock)
+{
+       int ret = 0;
+       int err = 0;
+       ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
+
+       ext_debug("ext4_ext_handle_uninitialized_extents: inode %lu, logical"
+                 "block %llu, max_blocks %u, flags %d, allocated %u",
+                 inode->i_ino, (unsigned long long)iblock, max_blocks,
+                 flags, allocated);
+       ext4_ext_show_leaf(inode, path);
+
+       /* DIO get_block() before submit the IO, split the extent */
+       if (flags == EXT4_GET_BLOCKS_DIO_CREATE_EXT) {
+               ret = ext4_split_unwritten_extents(handle,
+                                               inode, path, iblock,
+                                               max_blocks, flags);
+               /* flag the io_end struct that we need convert when IO done */
+               if (io)
+                       io->flag = DIO_AIO_UNWRITTEN;
+               goto out;
+       }
+       /* DIO end_io complete, convert the filled extent to written */
+       if (flags == EXT4_GET_BLOCKS_DIO_CONVERT_EXT) {
+               ret = ext4_convert_unwritten_extents_dio(handle, inode,
+                                                       path);
+               goto out2;
+       }
+       /* buffered IO case */
+       /*
+        * repeat fallocate creation request
+        * we already have an unwritten extent
+        */
+       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT)
+               goto map_out;
+
+       /* buffered READ or buffered write_begin() lookup */
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+               /*
+                * We have blocks reserved already.  We
+                * return allocated blocks so that delalloc
+                * won't do block reservation for us.  But
+                * the buffer head will be unmapped so that
+                * a read from the block returns 0s.
+                */
+               set_buffer_unwritten(bh_result);
+               goto out1;
+       }
+
+       /* buffered write, writepage time, convert*/
+       ret = ext4_ext_convert_to_initialized(handle, inode,
+                                               path, iblock,
+                                               max_blocks);
+out:
+       if (ret <= 0) {
+               err = ret;
+               goto out2;
+       } else
+               allocated = ret;
+       set_buffer_new(bh_result);
+map_out:
+       set_buffer_mapped(bh_result);
+out1:
+       if (allocated > max_blocks)
+               allocated = max_blocks;
+       ext4_ext_show_leaf(inode, path);
+       bh_result->b_bdev = inode->i_sb->s_bdev;
+       bh_result->b_blocknr = newblock;
+out2:
+       if (path) {
+               ext4_ext_drop_refs(path);
+               kfree(path);
+       }
+       return err ? err : allocated;
+}
+/*
  * Block allocation/map/preallocation routine for extents based files
  *
  *
@@ -2777,7 +3125,7 @@ fix_extent_len:
 int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        ext4_lblk_t iblock,
                        unsigned int max_blocks, struct buffer_head *bh_result,
-                       int create, int extend_disksize)
+                       int flags)
 {
        struct ext4_ext_path *path = NULL;
        struct ext4_extent_header *eh;
@@ -2786,17 +3134,17 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        int err = 0, depth, ret, cache_type;
        unsigned int allocated = 0;
        struct ext4_allocation_request ar;
-       loff_t disksize;
+       ext4_io_end_t *io = EXT4_I(inode)->cur_aio_dio;
 
        __clear_bit(BH_New, &bh_result->b_state);
-       ext_debug("blocks %u/%u requested for inode %u\n",
+       ext_debug("blocks %u/%u requested for inode %lu\n",
                        iblock, max_blocks, inode->i_ino);
 
        /* check in cache */
        cache_type = ext4_ext_in_cache(inode, iblock, &newex);
        if (cache_type) {
                if (cache_type == EXT4_EXT_CACHE_GAP) {
-                       if (!create) {
+                       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                                /*
                                 * block isn't allocated yet and
                                 * user doesn't want to allocate it
@@ -2852,7 +3200,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                        newblock = iblock - ee_block + ee_start;
                        /* number of remaining blocks in the extent */
                        allocated = ee_len - (iblock - ee_block);
-                       ext_debug("%u fit into %lu:%d -> %llu\n", iblock,
+                       ext_debug("%u fit into %u:%d -> %llu\n", iblock,
                                        ee_block, ee_len, newblock);
 
                        /* Do not put uninitialized extent in the cache */
@@ -2862,31 +3210,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
                                                        EXT4_EXT_CACHE_EXTENT);
                                goto out;
                        }
-                       if (create == EXT4_CREATE_UNINITIALIZED_EXT)
-                               goto out;
-                       if (!create) {
-                               /*
-                                * We have blocks reserved already.  We
-                                * return allocated blocks so that delalloc
-                                * won't do block reservation for us.  But
-                                * the buffer head will be unmapped so that
-                                * a read from the block returns 0s.
-                                */
-                               if (allocated > max_blocks)
-                                       allocated = max_blocks;
-                               set_buffer_unwritten(bh_result);
-                               goto out2;
-                       }
-
-                       ret = ext4_ext_convert_to_initialized(handle, inode,
-                                                               path, iblock,
-                                                               max_blocks);
-                       if (ret <= 0) {
-                               err = ret;
-                               goto out2;
-                       } else
-                               allocated = ret;
-                       goto outnew;
+                       ret = ext4_ext_handle_uninitialized_extents(handle,
+                                       inode, iblock, max_blocks, path,
+                                       flags, allocated, bh_result, newblock);
+                       return ret;
                }
        }
 
@@ -2894,7 +3221,7 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * requested block isn't allocated yet;
         * we couldn't try to create block if create flag is zero
         */
-       if (!create) {
+       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
                /*
                 * put just found gap into cache to speed up
                 * subsequent requests
@@ -2923,10 +3250,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
         * EXT_UNINIT_MAX_LEN.
         */
        if (max_blocks > EXT_INIT_MAX_LEN &&
-           create != EXT4_CREATE_UNINITIALIZED_EXT)
+           !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
                max_blocks = EXT_INIT_MAX_LEN;
        else if (max_blocks > EXT_UNINIT_MAX_LEN &&
-                create == EXT4_CREATE_UNINITIALIZED_EXT)
+                (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
                max_blocks = EXT_UNINIT_MAX_LEN;
 
        /* Check if we can really insert (iblock)::(iblock+max_blocks) extent */
@@ -2951,15 +3278,27 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        newblock = ext4_mb_new_blocks(handle, &ar, &err);
        if (!newblock)
                goto out2;
-       ext_debug("allocate new block: goal %llu, found %llu/%lu\n",
+       ext_debug("allocate new block: goal %llu, found %llu/%u\n",
                  ar.goal, newblock, allocated);
 
        /* try to insert new extent into found leaf and return */
        ext4_ext_store_pblock(&newex, newblock);
        newex.ee_len = cpu_to_le16(ar.len);
-       if (create == EXT4_CREATE_UNINITIALIZED_EXT)  /* Mark uninitialized */
+       /* Mark uninitialized */
+       if (flags & EXT4_GET_BLOCKS_UNINIT_EXT){
                ext4_ext_mark_uninitialized(&newex);
-       err = ext4_ext_insert_extent(handle, inode, path, &newex);
+               /*
+                * io_end structure was created for every async
+                * direct IO write to the middle of the file.
+                * To avoid unecessary convertion for every aio dio rewrite
+                * to the mid of file, here we flag the IO that is really
+                * need the convertion.
+                *
+                */
+               if (io && flags == EXT4_GET_BLOCKS_DIO_CREATE_EXT)
+                       io->flag = DIO_AIO_UNWRITTEN;
+       }
+       err = ext4_ext_insert_extent(handle, inode, path, &newex, flags);
        if (err) {
                /* free data blocks we just allocated */
                /* not a good idea to call discard here directly,
@@ -2973,19 +3312,10 @@ int ext4_ext_get_blocks(handle_t *handle, struct inode *inode,
        /* previous routine could use block we allocated */
        newblock = ext_pblock(&newex);
        allocated = ext4_ext_get_actual_len(&newex);
-outnew:
-       if (extend_disksize) {
-               disksize = ((loff_t) iblock + ar.len) << inode->i_blkbits;
-               if (disksize > i_size_read(inode))
-                       disksize = i_size_read(inode);
-               if (disksize > EXT4_I(inode)->i_disksize)
-                       EXT4_I(inode)->i_disksize = disksize;
-       }
-
        set_buffer_new(bh_result);
 
        /* Cache only when it is _not_ an uninitialized extent */
-       if (create != EXT4_CREATE_UNINITIALIZED_EXT)
+       if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0)
                ext4_ext_put_in_cache(inode, iblock, allocated, newblock,
                                                EXT4_EXT_CACHE_EXTENT);
 out:
@@ -3141,9 +3471,10 @@ retry:
                        ret = PTR_ERR(handle);
                        break;
                }
-               ret = ext4_get_blocks_wrap(handle, inode, block,
-                                         max_blocks, &map_bh,
-                                         EXT4_CREATE_UNINITIALIZED_EXT, 0, 0);
+               map_bh.b_state = 0;
+               ret = ext4_get_blocks(handle, inode, block,
+                                     max_blocks, &map_bh,
+                                     EXT4_GET_BLOCKS_CREATE_UNINIT_EXT);
                if (ret <= 0) {
 #ifdef EXT4FS_DEBUG
                        WARN_ON(ret <= 0);
@@ -3179,6 +3510,63 @@ retry:
 }
 
 /*
+ * This function convert a range of blocks to written extents
+ * The caller of this function will pass the start offset and the size.
+ * all unwritten extents within this range will be converted to
+ * written extents.
+ *
+ * This function is called from the direct IO end io call back
+ * function, to convert the fallocated extents after IO is completed.
+ */
+int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
+                                   loff_t len)
+{
+       handle_t *handle;
+       ext4_lblk_t block;
+       unsigned int max_blocks;
+       int ret = 0;
+       int ret2 = 0;
+       struct buffer_head map_bh;
+       unsigned int credits, blkbits = inode->i_blkbits;
+
+       block = offset >> blkbits;
+       /*
+        * We can't just convert len to max_blocks because
+        * If blocksize = 4096 offset = 3072 and len = 2048
+        */
+       max_blocks = (EXT4_BLOCK_ALIGN(len + offset, blkbits) >> blkbits)
+                                                       - block;
+       /*
+        * credits to insert 1 extent into extent tree
+        */
+       credits = ext4_chunk_trans_blocks(inode, max_blocks);
+       while (ret >= 0 && ret < max_blocks) {
+               block = block + ret;
+               max_blocks = max_blocks - ret;
+               handle = ext4_journal_start(inode, credits);
+               if (IS_ERR(handle)) {
+                       ret = PTR_ERR(handle);
+                       break;
+               }
+               map_bh.b_state = 0;
+               ret = ext4_get_blocks(handle, inode, block,
+                                     max_blocks, &map_bh,
+                                     EXT4_GET_BLOCKS_DIO_CONVERT_EXT);
+               if (ret <= 0) {
+                       WARN_ON(ret <= 0);
+                       printk(KERN_ERR "%s: ext4_ext_get_blocks "
+                                   "returned error inode#%lu, block=%u, "
+                                   "max_blocks=%u", __func__,
+                                   inode->i_ino, block, max_blocks);
+               }
+               ext4_mark_inode_dirty(handle, inode);
+               ret2 = ext4_journal_stop(handle);
+               if (ret <= 0 || ret2 )
+                       break;
+       }
+       return ret > 0 ? ret2 : ret;
+}
+/*
  * Callback function called for each extent to gather FIEMAP information.
  */
 static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
@@ -3186,7 +3574,7 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
                       void *data)
 {
        struct fiemap_extent_info *fieinfo = data;
-       unsigned long blksize_bits = inode->i_sb->s_blocksize_bits;
+       unsigned char blksize_bits = inode->i_sb->s_blocksize_bits;
        __u64   logical;
        __u64   physical;
        __u64   length;
@@ -3233,9 +3621,16 @@ static int ext4_ext_fiemap_cb(struct inode *inode, struct ext4_ext_path *path,
         *
         * XXX this might miss a single-block extent at EXT_MAX_BLOCK
         */
-       if (logical + length - 1 == EXT_MAX_BLOCK ||
-           ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK)
+       if (ext4_ext_next_allocated_block(path) == EXT_MAX_BLOCK ||
+           newex->ec_block + newex->ec_len - 1 == EXT_MAX_BLOCK) {
+               loff_t size = i_size_read(inode);
+               loff_t bs = EXT4_BLOCK_SIZE(inode->i_sb);
+
                flags |= FIEMAP_EXTENT_LAST;
+               if ((flags & FIEMAP_EXTENT_DELALLOC) &&
+                   logical+length > size)
+                       length = (size - logical + bs - 1) & ~(bs-1);
+       }
 
        error = fiemap_fill_next_extent(fieinfo, logical, physical,
                                        length, flags);
@@ -3309,10 +3704,10 @@ int ext4_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                 * Walk the extent tree gathering extent information.
                 * ext4_ext_fiemap_cb will push extents back to user.
                 */
-               down_write(&EXT4_I(inode)->i_data_sem);
+               down_read(&EXT4_I(inode)->i_data_sem);
                error = ext4_ext_walk_space(inode, start_blk, len_blks,
                                          ext4_ext_fiemap_cb, fieinfo);
-               up_write(&EXT4_I(inode)->i_data_sem);
+               up_read(&EXT4_I(inode)->i_data_sem);
        }
 
        return error;