Whamcloud - gitweb
LU-8410 ldiskfs: new FIEMAP API 03/21603/7
authorAlexey Lyashkov <alexey.lyashkov@seagate.com>
Fri, 29 Jul 2016 16:12:57 +0000 (19:12 +0300)
committerOleg Drokin <oleg.drokin@intel.com>
Sat, 10 Sep 2016 03:23:30 +0000 (03:23 +0000)
With RH 6.5 old API was deprecated and was removed.
Backport a new API from ext4 upstream in opposite to copy-paste
older buggy code as FIEMAP now uses in current code.

Kernel upstream commit is 91dd8c114499e9818f2d5919ef0b9eee61810220
ext4: prevent race while walking extent tree for fiemap.

Signed-off-by: Alexey Lyashkov <alexey.lyashkov@seagate.com>
Change-Id: I7790c9e1a9cbfbd2cc429292aa764250e0525e21
Reviewed-on: http://review.whamcloud.com/21603
Tested-by: Jenkins
Tested-by: Maloo <hpdd-maloo@intel.com>
Reviewed-by: Andreas Dilger <andreas.dilger@intel.com>
Reviewed-by: Faccini Bruno <bruno.faccini@intel.com>
Reviewed-by: Oleg Drokin <oleg.drokin@intel.com>
ldiskfs/kernel_patches/patches/rhel6.5/ext4-add-new-abstraction-ext4_map_blocks.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel6.5/ext4-ext-walk-space.patch [deleted file]
ldiskfs/kernel_patches/patches/rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch [new file with mode: 0644]
ldiskfs/kernel_patches/patches/rhel6.6/ext4_s_max_ext_tree_depth.patch
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.4.series
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.5.series
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.6.series
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.7.series
ldiskfs/kernel_patches/series/ldiskfs-2.6-rhel6.8.series

diff --git a/ldiskfs/kernel_patches/patches/rhel6.5/ext4-add-new-abstraction-ext4_map_blocks.patch b/ldiskfs/kernel_patches/patches/rhel6.5/ext4-add-new-abstraction-ext4_map_blocks.patch
new file mode 100644 (file)
index 0000000..11ebba3
--- /dev/null
@@ -0,0 +1,1011 @@
+From: Theodore Ts'o <tytso@mit.edu>
+
+From e35fd6609b2fee54484d520deccb8f18bf7d38f3 Mon Sep 17 00:00:00 2001
+
+
+Subject: [PATCH] ext4: Add new abstraction ext4_map_blocks() underneath
+ ext4_get_blocks()
+
+Jack up ext4_get_blocks() and add a new function, ext4_map_blocks()
+which uses a much smaller structure, struct ext4_map_blocks which is
+20 bytes, as opposed to a struct buffer_head, which nearly 5 times
+bigger on an x86_64 machine.  By switching things to use
+ext4_map_blocks(), we can save stack space by using ext4_map_blocks()
+since we can avoid allocating a struct buffer_head on the stack.
+
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Index: linux-stage/fs/ext4/ext4.h
+===================================================================
+--- linux-stage.orig/fs/ext4/ext4.h    2016-07-15 09:52:28.000000000 +0300
++++ linux-stage/fs/ext4/ext4.h 2016-07-15 09:52:29.000000000 +0300
+@@ -142,10 +142,8 @@ struct ext4_allocation_request {
+ #define EXT4_MAP_MAPPED               (1 << BH_Mapped)
+ #define EXT4_MAP_UNWRITTEN    (1 << BH_Unwritten)
+ #define EXT4_MAP_BOUNDARY     (1 << BH_Boundary)
+-#define EXT4_MAP_UNINIT               (1 << BH_Uninit)
+ #define EXT4_MAP_FLAGS                (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
+-                               EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
+-                               EXT4_MAP_UNINIT)
++                               EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
+ struct ext4_map_blocks {
+       ext4_fsblk_t m_pblk;
+@@ -2184,9 +2182,9 @@ extern int ext4_ext_tree_init(handle_t *
+ extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
+ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
+                                      int chunk);
+-extern 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 flags);
++#define HAVE_EXT4_MAP_BLOCKS
++extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
++                             struct ext4_map_blocks *map, int flags);
+ extern void ext4_ext_truncate(struct inode *);
+ extern int ext4_ext_punch_hole(struct inode *inode, loff_t offset,
+                               loff_t length);
+@@ -2196,6 +2194,8 @@ extern long ext4_fallocate(struct inode 
+                         loff_t len);
+ extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
+                         ssize_t len);
++extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
++                         struct ext4_map_blocks *map, int flags);
+ extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
+                          sector_t block, unsigned int max_blocks,
+                          struct buffer_head *bh, int flags);
+Index: linux-stage/fs/ext4/extents.c
+===================================================================
+--- linux-stage.orig/fs/ext4/extents.c 2016-07-15 09:52:28.000000000 +0300
++++ linux-stage/fs/ext4/extents.c      2016-07-15 09:53:10.000000000 +0300
+@@ -2960,7 +2960,7 @@ fix_extent_len:
+ #define EXT4_EXT_ZERO_LEN 7
+ /*
+- * This function is called by ext4_ext_get_blocks() if someone tries to write
++ * This function is called by ext4_ext_map_blocks() if someone tries to write
+  * to an uninitialized extent. It may result in splitting the uninitialized
+  * extent into multiple extents (upto three - one initialized and two
+  * uninitialized).
+@@ -2970,11 +2970,10 @@ fix_extent_len:
+  *   c> Splits in three extents: Somone is writing in middle of the extent
+  */
+ static int ext4_ext_convert_to_initialized(handle_t *handle,
+-                                              struct inode *inode,
+-                                              struct ext4_ext_path *path,
+-                                              ext4_lblk_t iblock,
+-                                              unsigned int max_blocks,
+-                                              int flags)
++                                         struct inode *inode,
++                                         struct ext4_map_blocks *map,
++                                         struct ext4_ext_path *path,
++                                         int flags)
+ {
+       struct ext4_extent *ex, newex, orig_ex;
+       struct ext4_extent *ex1 = NULL;
+@@ -2990,20 +2989,20 @@ static int ext4_ext_convert_to_initializ
+       ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+-              (unsigned long long)iblock, max_blocks);
++              (unsigned long long)map->m_lblk, map->m_len);
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+-      if (eof_block < iblock + max_blocks)
+-              eof_block = iblock + max_blocks;
++      if (eof_block < map->m_lblk + map->m_len)
++              eof_block = map->m_lblk + map->m_len;
+       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 + ext4_ext_pblock(ex);
++      allocated = ee_len - (map->m_lblk - ee_block);
++      newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
+       ex2 = ex;
+       orig_ex.ee_block = ex->ee_block;
+@@ -3033,10 +3032,10 @@ static int ext4_ext_convert_to_initializ
+               return allocated;
+       }
+-      /* ex1: ee_block to iblock - 1 : uninitialized */
+-      if (iblock > ee_block) {
++      /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
++      if (map->m_lblk > ee_block) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+@@ -3046,15 +3045,15 @@ static int ext4_ext_convert_to_initializ
+        * 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);
++      if (!ex1 && allocated > map->m_len)
++              ex2->ee_len = cpu_to_le16(map->m_len);
+       /* ex3: to ee_block + ee_len : uninitialised */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               unsigned int newdepth;
+               /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
+               if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) {
+                       /*
+-                       * iblock == ee_block is handled by the zerouout
++                       * map->m_lblk == ee_block is handled by the zerouout
+                        * at the beginning.
+                        * Mark first half uninitialized.
+                        * Mark second half initialized and zero out the
+@@ -3067,7 +3066,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       ex3 = &newex;
+-                      ex3->ee_block = cpu_to_le32(iblock);
++                      ex3->ee_block = cpu_to_le32(map->m_lblk);
+                       ext4_ext_store_pblock(ex3, newblock);
+                       ex3->ee_len = cpu_to_le16(allocated);
+                       err = ext4_ext_insert_extent(handle, inode, path,
+@@ -3081,7 +3080,7 @@ static int ext4_ext_convert_to_initializ
+                               ext4_ext_store_pblock(ex,
+                                       ext4_ext_pblock(&orig_ex));
+                               ext4_ext_dirty(handle, inode, path + depth);
+-                              /* blocks available from iblock */
++                              /* blocks available from map->m_lblk */
+                               return allocated;
+                       } else if (err)
+@@ -3103,8 +3102,8 @@ static int ext4_ext_convert_to_initializ
+                                */
+                               depth = ext_depth(inode);
+                               ext4_ext_drop_refs(path);
+-                              path = ext4_ext_find_extent(inode,
+-                                                              iblock, path);
++                              path = ext4_ext_find_extent(inode, map->m_lblk,
++                                                          path);
+                               if (IS_ERR(path)) {
+                                       err = PTR_ERR(path);
+                                       return err;
+@@ -3124,9 +3123,9 @@ static int ext4_ext_convert_to_initializ
+                       return allocated;
+               }
+               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);
++              ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
++              ext4_ext_store_pblock(ex3, newblock + map->m_len);
++              ex3->ee_len = cpu_to_le16(allocated - map->m_len);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
+               if (err == -ENOSPC && may_zeroout) {
+@@ -3139,7 +3138,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zeroed the full extent */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               } else if (err)
+@@ -3159,7 +3158,7 @@ static int ext4_ext_convert_to_initializ
+               depth = newdepth;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3173,14 +3172,14 @@ static int ext4_ext_convert_to_initializ
+               if (err)
+                       goto out;
+-              allocated = max_blocks;
++              allocated = map->m_len;
+               /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
+                * to insert a extent in the middle zerout directly
+                * otherwise give the extent a chance to merge to left
+                */
+               if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
+-                      iblock != ee_block && may_zeroout) {
++                      map->m_lblk != ee_block && may_zeroout) {
+                       err =  ext4_ext_zeroout(inode, &orig_ex);
+                       if (err)
+                               goto fix_extent_len;
+@@ -3190,7 +3189,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zero out the first half */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               }
+       }
+@@ -3201,13 +3200,13 @@ static int ext4_ext_convert_to_initializ
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+       }
+-      /* ex2: iblock to iblock + maxblocks-1 : initialised */
+-      ex2->ee_block = cpu_to_le32(iblock);
++      /* ex2: map->m_lblk to map->m_lblk + maxblocks-1 : initialised */
++      ex2->ee_block = cpu_to_le32(map->m_lblk);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       if (ex2 != ex)
+@@ -3277,7 +3276,7 @@ fix_extent_len:
+ }
+ /*
+- * This function is called by ext4_ext_get_blocks() from
++ * This function is called by ext4_ext_map_blocks() from
+  * ext4_get_blocks_dio_write() when DIO to write
+  * to an uninitialized extent.
+  *
+@@ -3300,9 +3299,8 @@ fix_extent_len:
+  */
+ static int ext4_split_unwritten_extents(handle_t *handle,
+                                       struct inode *inode,
++                                      struct ext4_map_blocks *map,
+                                       struct ext4_ext_path *path,
+-                                      ext4_lblk_t iblock,
+-                                      unsigned int max_blocks,
+                                       int flags)
+ {
+       struct ext4_extent *ex, newex, orig_ex;
+@@ -3318,20 +3316,20 @@ static int ext4_split_unwritten_extents(
+       ext_debug("ext4_split_unwritten_extents: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+-              (unsigned long long)iblock, max_blocks);
++              (unsigned long long)map->m_lblk, map->m_len);
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+-      if (eof_block < iblock + max_blocks)
+-              eof_block = iblock + max_blocks;
++      if (eof_block < map->m_lblk + map->m_len)
++              eof_block = map->m_lblk + map->m_len;
+       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 + ext4_ext_pblock(ex);
++      allocated = ee_len - (map->m_lblk - ee_block);
++      newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
+       ex2 = ex;
+       orig_ex.ee_block = ex->ee_block;
+@@ -3349,16 +3347,16 @@ static int ext4_split_unwritten_extents(
+        * block where the write begins, and the write completely
+        * covers the extent, then we don't need to split it.
+        */
+-      if ((iblock == ee_block) && (allocated <= max_blocks))
++      if ((map->m_lblk == ee_block) && (allocated <= map->m_len))
+               return allocated;
+       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: ee_block to map->m_lblk - 1 : uninitialized */
++      if (map->m_lblk > ee_block) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+@@ -3368,15 +3366,15 @@ static int ext4_split_unwritten_extents(
+        * 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);
++      if (!ex1 && allocated > map->m_len)
++              ex2->ee_len = cpu_to_le16(map->m_len);
+       /* ex3: to ee_block + ee_len : uninitialised */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               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);
++              ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
++              ext4_ext_store_pblock(ex3, newblock + map->m_len);
++              ex3->ee_len = cpu_to_le16(allocated - map->m_len);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
+               if (err == -ENOSPC && may_zeroout) {
+@@ -3400,8 +3398,8 @@ static int ext4_split_unwritten_extents(
+                               err =  ext4_ext_zeroout(inode, ex3);
+                               if (err)
+                                       goto fix_extent_len;
+-                              max_blocks = allocated;
+-                              ex2->ee_len = cpu_to_le16(max_blocks);
++                              map->m_len = allocated;
++                              ex2->ee_len = cpu_to_le16(map->m_len);
+                               goto skip;
+                       }
+                       err =  ext4_ext_zeroout(inode, &orig_ex);
+@@ -3413,7 +3411,7 @@ static int ext4_split_unwritten_extents(
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zeroed the full extent */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               } else if (err)
+@@ -3433,7 +3431,7 @@ static int ext4_split_unwritten_extents(
+               depth = newdepth;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3446,8 +3444,7 @@ static int ext4_split_unwritten_extents(
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
+                       goto out;
+-
+-              allocated = max_blocks;
++              allocated = map->m_len;
+       }
+ skip:
+       /*
+@@ -3457,16 +3454,16 @@ skip:
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+       }
+       /*
+-       * ex2: iblock to iblock + maxblocks-1 : to be direct IO written,
+-       * uninitialised still.
++       * ex2: map->m_lblk to map->m_lblk + map->m_len-1 : to be written
++       * using direct I/O, uninitialised still.
+        */
+-      ex2->ee_block = cpu_to_le32(iblock);
++      ex2->ee_block = cpu_to_le32(map->m_lblk);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       ext4_ext_mark_uninitialized(ex2);
+@@ -3506,8 +3503,7 @@ fix_extent_len:
+ static int ext4_convert_unwritten_extents_dio(handle_t *handle,
+                                             struct inode *inode,
+-                                            ext4_lblk_t iblock,
+-                                            unsigned int max_blocks,
++                                            struct ext4_map_blocks *map,
+                                             struct ext4_ext_path *path)
+ {
+       struct ext4_extent *ex;
+@@ -3529,14 +3525,13 @@ static int ext4_convert_unwritten_extent
+       /* If extent is larger than requested then split is required */
+-      if (ee_block != iblock || ee_len > max_blocks) {
+-              err = ext4_split_unwritten_extents(handle, inode, path,
+-                                      iblock, max_blocks,
++      if (ee_block != map->m_lblk || ee_len > map->m_len) {
++              err = ext4_split_unwritten_extents(handle, inode, map, path,
+                                       EXT4_EXT_DATA_VALID);
+               if (err < 0)
+                       goto out;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3627,10 +3622,9 @@ out:
+ static int
+ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
+-                      ext4_lblk_t iblock, unsigned int max_blocks,
++                      struct ext4_map_blocks *map,
+                       struct ext4_ext_path *path, int flags,
+-                      unsigned int allocated, struct buffer_head *bh_result,
+-                      ext4_fsblk_t newblock)
++                      unsigned int allocated, ext4_fsblk_t newblock)
+ {
+       int ret = 0;
+       int err = 0;
+@@ -3638,7 +3632,7 @@ ext4_ext_handle_uninitialized_extents(ha
+       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,
++                inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
+                 flags, allocated);
+       ext4_ext_show_leaf(inode, path);
+@@ -3651,9 +3645,8 @@ ext4_ext_handle_uninitialized_extents(ha
+       /* DIO get_block() before submit the IO, split the extent */
+       if ((flags & ~EXT4_GET_BLOCKS_METADATA_NOFAIL) ==
+           EXT4_GET_BLOCKS_DIO_CREATE_EXT) {
+-              ret = ext4_split_unwritten_extents(handle,
+-                                              inode, path, iblock,
+-                                              max_blocks, flags);
++              ret = ext4_split_unwritten_extents(handle, inode, map,
++                                                 path, flags);
+               /*
+                * Flag the inode(non aio case) or end_io struct (aio case)
+                * that this IO needs to convertion to written when IO is
+@@ -3670,12 +3663,11 @@ ext4_ext_handle_uninitialized_extents(ha
+       if ((flags & ~EXT4_GET_BLOCKS_METADATA_NOFAIL) ==
+           EXT4_GET_BLOCKS_DIO_CONVERT_EXT) {
+               ret = ext4_convert_unwritten_extents_dio(handle, inode,
+-                                                       iblock, max_blocks,
+-                                                       path);
++                                                       map, path);
+               if (ret >= 0) {
+                       ext4_update_inode_fsync_trans(handle, inode, 1);
+-                      err = check_eofblocks_fl(handle, inode, iblock, path,
+-                                               max_blocks);
++                      err = check_eofblocks_fl(handle, inode, map->m_lblk, path,
++                                               map->m_len);
+               } else
+                       err = ret;
+               goto out2;
+@@ -3697,18 +3689,15 @@ ext4_ext_handle_uninitialized_extents(ha
+                * the buffer head will be unmapped so that
+                * a read from the block returns 0s.
+                */
+-              set_buffer_unwritten(bh_result);
++              map->m_flags |= EXT4_MAP_UNWRITTEN;
+               goto out1;
+       }
+       /* buffered write, writepage time, convert*/
+-      ret = ext4_ext_convert_to_initialized(handle, inode,
+-                                              path, iblock,
+-                                              max_blocks,
+-                                              flags);
++      ret = ext4_ext_convert_to_initialized(handle, inode, map, path, flags);
+       if (ret >= 0) {
+               ext4_update_inode_fsync_trans(handle, inode, 1);
+-              err = check_eofblocks_fl(handle, inode, iblock, path, max_blocks);
++              err = check_eofblocks_fl(handle, inode, map->m_lblk, path, map->m_len);
+               if (err < 0)
+                       goto out2;
+       }
+@@ -3718,7 +3707,7 @@ out:
+               goto out2;
+       } else
+               allocated = ret;
+-      set_buffer_new(bh_result);
++      map->m_flags |= EXT4_MAP_NEW;
+       /*
+        * if we allocated more blocks than requested
+        * we need to make sure we unmap the extra block
+@@ -3726,11 +3715,11 @@ out:
+        * unmapped later when we find the buffer_head marked
+        * new.
+        */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               unmap_underlying_metadata_blocks(inode->i_sb->s_bdev,
+-                                      newblock + max_blocks,
+-                                      allocated - max_blocks);
+-              allocated = max_blocks;
++                                      newblock + map->m_len,
++                                      allocated - map->m_len);
++              allocated = map->m_len;
+       }
+       /*
+@@ -3744,13 +3733,13 @@ out:
+               ext4_da_update_reserve_space(inode, allocated, 0);
+ map_out:
+-      set_buffer_mapped(bh_result);
++      map->m_flags |= EXT4_MAP_MAPPED;
+ out1:
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
++      if (allocated > map->m_len)
++              allocated = map->m_len;
+       ext4_ext_show_leaf(inode, path);
+-      bh_result->b_bdev = inode->i_sb->s_bdev;
+-      bh_result->b_blocknr = newblock;
++      map->m_pblk = newblock;
++      map->m_len = allocated;
+ out2:
+       if (path) {
+               ext4_ext_drop_refs(path);
+@@ -3777,10 +3766,8 @@ out2:
+  *
+  * return < 0, error case.
+  */
+-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 flags)
++int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
++                      struct ext4_map_blocks *map, int flags)
+ {
+       struct ext4_ext_path *path = NULL;
+       struct ext4_extent_header *eh;
+@@ -3791,12 +3778,11 @@ int ext4_ext_get_blocks(handle_t *handle
+       struct ext4_allocation_request ar;
+       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 %lu\n",
+-                      iblock, max_blocks, inode->i_ino);
++                map->m_lblk, map->m_len, inode->i_ino);
+       /* check in cache */
+-      if (ext4_ext_in_cache(inode, iblock, &newex)) {
++      if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
+               if (!newex.ee_start_lo && !newex.ee_start_hi) {
+                       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+                               /*
+@@ -3808,18 +3794,18 @@ int ext4_ext_get_blocks(handle_t *handle
+                       /* we should allocate requested block */
+               } else {
+                       /* block is already allocated */
+-                      newblock = iblock
++                      newblock = map->m_lblk
+                                  - le32_to_cpu(newex.ee_block)
+                                  + ext4_ext_pblock(&newex);
+                       /* number of remaining blocks in the extent */
+                       allocated = ext4_ext_get_actual_len(&newex) -
+-                                      (iblock - le32_to_cpu(newex.ee_block));
++                                      (map->m_lblk - le32_to_cpu(newex.ee_block));
+                       goto out;
+               }
+       }
+       /* find extent for this block */
+-      path = ext4_ext_find_extent(inode, iblock, NULL);
++      path = ext4_ext_find_extent(inode, map->m_lblk, NULL);
+       if (IS_ERR(path)) {
+               err = PTR_ERR(path);
+               path = NULL;
+@@ -3836,7 +3822,7 @@ int ext4_ext_get_blocks(handle_t *handle
+       if (unlikely(path[depth].p_ext == NULL && depth != 0)) {
+               EXT4_ERROR_INODE(inode, "bad extent address "
+                                "iblock: %d, depth: %d pblock %lld",
+-                               iblock, depth, path[depth].p_block);
++                               map->m_lblk, depth, path[depth].p_block);
+               err = -EIO;
+               goto out2;
+       }
+@@ -3854,11 +3840,11 @@ int ext4_ext_get_blocks(handle_t *handle
+                */
+               ee_len = ext4_ext_get_actual_len(ex);
+               /* if found extent covers block, simply return it */
+-              if (in_range(iblock, ee_block, ee_len)) {
+-                      newblock = iblock - ee_block + ee_start;
++              if (in_range(map->m_lblk, ee_block, ee_len)) {
++                      newblock = map->m_lblk - ee_block + ee_start;
+                       /* number of remaining blocks in the extent */
+-                      allocated = ee_len - (iblock - ee_block);
+-                      ext_debug("%u fit into %u:%d -> %llu\n", iblock,
++                      allocated = ee_len - (map->m_lblk - ee_block);
++                      ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
+                                       ee_block, ee_len, newblock);
+                       /*
+@@ -3870,9 +3856,9 @@ int ext4_ext_get_blocks(handle_t *handle
+                                       ee_len, ee_start);
+                               goto out;
+                       }
+-                      ret = ext4_ext_handle_uninitialized_extents(
+-                              handle, inode, iblock, max_blocks, path,
+-                              flags, allocated, bh_result, newblock);
++                      ret = ext4_ext_handle_uninitialized_extents(handle,
++                                      inode, map, path, flags, allocated,
++                                      newblock);
+                       return ret;
+               }
+       }
+@@ -3886,7 +3872,7 @@ int ext4_ext_get_blocks(handle_t *handle
+                * put just found gap into cache to speed up
+                * subsequent requests
+                */
+-              ext4_ext_put_gap_in_cache(inode, path, iblock);
++              ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
+               goto out2;
+       }
+       /*
+@@ -3894,11 +3880,11 @@ int ext4_ext_get_blocks(handle_t *handle
+        */
+       /* find neighbour allocated blocks */
+-      ar.lleft = iblock;
++      ar.lleft = map->m_lblk;
+       err = ext4_ext_search_left(inode, path, &ar.lleft, &ar.pleft);
+       if (err)
+               goto out2;
+-      ar.lright = iblock;
++      ar.lright = map->m_lblk;
+       err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright);
+       if (err)
+               goto out2;
+@@ -3909,26 +3895,26 @@ int ext4_ext_get_blocks(handle_t *handle
+        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+        * EXT_UNINIT_MAX_LEN.
+        */
+-      if (max_blocks > EXT_INIT_MAX_LEN &&
++      if (map->m_len > EXT_INIT_MAX_LEN &&
+           !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
+-              max_blocks = EXT_INIT_MAX_LEN;
+-      else if (max_blocks > EXT_UNINIT_MAX_LEN &&
++              map->m_len = EXT_INIT_MAX_LEN;
++      else if (map->m_len > EXT_UNINIT_MAX_LEN &&
+                (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
+-              max_blocks = EXT_UNINIT_MAX_LEN;
++              map->m_len = EXT_UNINIT_MAX_LEN;
+-      /* 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);
++      /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
++      newex.ee_block = cpu_to_le32(map->m_lblk);
++      newex.ee_len = cpu_to_le16(map->m_len);
+       err = ext4_ext_check_overlap(inode, &newex, path);
+       if (err)
+               allocated = ext4_ext_get_actual_len(&newex);
+       else
+-              allocated = max_blocks;
++              allocated = map->m_len;
+       /* allocate new block */
+       ar.inode = inode;
+-      ar.goal = ext4_ext_find_goal(inode, path, iblock);
+-      ar.logical = iblock;
++      ar.goal = ext4_ext_find_goal(inode, path, map->m_lblk);
++      ar.logical = map->m_lblk;
+       ar.len = allocated;
+       if (S_ISREG(inode->i_mode))
+               ar.flags = EXT4_MB_HINT_DATA;
+@@ -3967,7 +3953,7 @@ int ext4_ext_get_blocks(handle_t *handle
+               }
+       }
+-      err = check_eofblocks_fl(handle, inode, iblock, path, ar.len);
++      err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len);
+       if (err)
+               goto out2;
+@@ -3987,9 +3973,9 @@ int ext4_ext_get_blocks(handle_t *handle
+       /* previous routine could use block we allocated */
+       newblock = ext4_ext_pblock(&newex);
+       allocated = ext4_ext_get_actual_len(&newex);
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
+-      set_buffer_new(bh_result);
++      if (allocated > map->m_len)
++              allocated = map->m_len;
++      map->m_flags |= EXT4_MAP_NEW;
+       /*
+        * Update reserved blocks/metadata blocks after successful
+@@ -4003,17 +3989,17 @@ int ext4_ext_get_blocks(handle_t *handle
+        * when it is _not_ an uninitialized extent.
+        */
+       if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) {
+-              ext4_ext_put_in_cache(inode, iblock, allocated, newblock);
++              ext4_ext_put_in_cache(inode, map->m_lblk, allocated, newblock);
+               ext4_update_inode_fsync_trans(handle, inode, 1);
+       } else
+               ext4_update_inode_fsync_trans(handle, inode, 0);
+ out:
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
++      if (allocated > map->m_len)
++              allocated = map->m_len;
+       ext4_ext_show_leaf(inode, path);
+-      set_buffer_mapped(bh_result);
+-      bh_result->b_bdev = inode->i_sb->s_bdev;
+-      bh_result->b_blocknr = newblock;
++      map->m_flags |= EXT4_MAP_MAPPED;
++      map->m_pblk = newblock;
++      map->m_len = allocated;
+ out2:
+       if (path) {
+               ext4_ext_drop_refs(path);
+@@ -4196,7 +4182,7 @@ retry:
+               if (ret <= 0) {
+ #ifdef EXT4FS_DEBUG
+                       WARN_ON(ret <= 0);
+-                      printk(KERN_ERR "%s: ext4_ext_get_blocks "
++                      printk(KERN_ERR "%s: ext4_ext_map_blocks "
+                                   "returned error inode#%lu, block=%u, "
+                                   "max_blocks=%u", __func__,
+                                   inode->i_ino, block, max_blocks);
+@@ -4709,6 +4695,5 @@ EXPORT_SYMBOL(ext4_ext_insert_extent);
+ EXPORT_SYMBOL(ext4_mb_new_blocks);
+ EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
+ EXPORT_SYMBOL(ext4_mark_inode_dirty);
+-EXPORT_SYMBOL(ext4_ext_walk_space);
+ EXPORT_SYMBOL(ext4_ext_find_extent);
+ EXPORT_SYMBOL(ext4_ext_drop_refs);
+Index: linux-stage/fs/ext4/inode.c
+===================================================================
+--- linux-stage.orig/fs/ext4/inode.c   2016-07-15 09:52:28.000000000 +0300
++++ linux-stage/fs/ext4/inode.c        2016-07-15 09:52:29.000000000 +0300
+@@ -200,7 +200,7 @@ int ext4_truncate_restart_trans(handle_t
+       int ret;
+       /*
+-       * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this
++       * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
+        * moment, get_block can be called only for blocks inside i_size since
+        * page cache has been already dropped and writes are blocked by
+        * i_mutex. So we can safely drop the i_data_sem here.
+@@ -970,9 +970,9 @@ err_out:
+ }
+ /*
+- * The ext4_ind_get_blocks() function handles non-extents inodes
++ * The ext4_ind_map_blocks() function handles non-extents inodes
+  * (i.e., using the traditional indirect/double-indirect i_blocks
+- * scheme) for ext4_get_blocks().
++ * scheme) for ext4_map_blocks().
+  *
+  * Allocation strategy is simple: if we have to allocate something, we will
+  * have to go the whole way to leaf. So let's do it before attaching anything
+@@ -991,15 +991,14 @@ err_out:
+  * return = 0, if plain lookup failed.
+  * return < 0, error case.
+  *
+- * The ext4_ind_get_blocks() function should be called with
++ * The ext4_ind_map_blocks() function should be called with
+  * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
+  * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
+  * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
+  * blocks.
+  */
+-static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
+-                             ext4_lblk_t iblock, unsigned int maxblocks,
+-                             struct buffer_head *bh_result,
++static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
++                             struct ext4_map_blocks *map,
+                              int flags)
+ {
+       int err = -EIO;
+@@ -1015,7 +1014,7 @@ static int ext4_ind_get_blocks(handle_t 
+       J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
+       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
+-      depth = ext4_block_to_path(inode, iblock, offsets,
++      depth = ext4_block_to_path(inode, map->m_lblk, offsets,
+                                  &blocks_to_boundary);
+       if (depth == 0)
+@@ -1026,10 +1025,9 @@ static int ext4_ind_get_blocks(handle_t 
+       /* Simplest case - block found, no allocation needed */
+       if (!partial) {
+               first_block = le32_to_cpu(chain[depth - 1].key);
+-              clear_buffer_new(bh_result);
+               count++;
+               /*map more blocks*/
+-              while (count < maxblocks && count <= blocks_to_boundary) {
++              while (count < map->m_len && count <= blocks_to_boundary) {
+                       ext4_fsblk_t blk;
+                       blk = le32_to_cpu(*(chain[depth-1].p + count));
+@@ -1049,7 +1047,7 @@ static int ext4_ind_get_blocks(handle_t 
+       /*
+        * Okay, we need to do block allocation.
+       */
+-      goal = ext4_find_goal(inode, iblock, partial);
++      goal = ext4_find_goal(inode, map->m_lblk, partial);
+       /* the number of blocks need to allocate for [d,t]indirect blocks */
+       indirect_blks = (chain + depth) - partial - 1;
+@@ -1059,11 +1057,11 @@ static int ext4_ind_get_blocks(handle_t 
+        * direct blocks to allocate for this branch.
+        */
+       count = ext4_blks_to_allocate(partial, indirect_blks,
+-                                      maxblocks, blocks_to_boundary);
++                                    map->m_len, blocks_to_boundary);
+       /*
+        * Block out ext4_truncate while we alter the tree
+        */
+-      err = ext4_alloc_branch(handle, inode, iblock, indirect_blks,
++      err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
+                               &count, goal,
+                               offsets + (partial - chain), partial);
+@@ -1075,18 +1073,20 @@ static int ext4_ind_get_blocks(handle_t 
+        * may need to return -EAGAIN upwards in the worst case.  --sct
+        */
+       if (!err)
+-              err = ext4_splice_branch(handle, inode, iblock,
++              err = ext4_splice_branch(handle, inode, map->m_lblk,
+                                        partial, indirect_blks, count);
+       if (err)
+               goto cleanup;
+-      set_buffer_new(bh_result);
++      map->m_flags |= EXT4_MAP_NEW;
+       ext4_update_inode_fsync_trans(handle, inode, 1);
+ got_it:
+-      map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
++      map->m_flags |= EXT4_MAP_MAPPED;
++      map->m_pblk = le32_to_cpu(chain[depth-1].key);
++      map->m_len = count;
+       if (count > blocks_to_boundary)
+-              set_buffer_boundary(bh_result);
++              map->m_flags |= EXT4_MAP_BOUNDARY;
+       err = count;
+       /* Clean up and exit */
+       partial = chain + depth - 1;    /* the whole chain */
+@@ -1096,7 +1096,6 @@ cleanup:
+               brelse(partial->bh);
+               partial--;
+       }
+-      BUFFER_TRACE(bh_result, "returned");
+ out:
+       return err;
+ }
+@@ -1291,15 +1290,15 @@ static pgoff_t ext4_num_dirty_pages(stru
+ }
+ /*
+- * The ext4_get_blocks() function tries to look up the requested blocks,
++ * The ext4_map_blocks() function tries to look up the requested blocks,
+  * and returns if the blocks are already mapped.
+  *
+  * Otherwise it takes the write lock of the i_data_sem and allocate blocks
+  * and store the allocated blocks in the result buffer head and mark it
+  * mapped.
+  *
+- * If file type is extents based, it will call ext4_ext_get_blocks(),
+- * Otherwise, call with ext4_ind_get_blocks() to handle indirect mapping
++ * If file type is extents based, it will call ext4_ext_map_blocks(),
++ * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
+  * based files
+  *
+  * On success, it returns the number of blocks being mapped or allocate.
+@@ -1312,35 +1311,31 @@ static pgoff_t ext4_num_dirty_pages(stru
+  *
+  * It returns the error in case of allocation failure.
+  */
+-int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
+-                  unsigned int max_blocks, struct buffer_head *bh,
+-                  int flags)
++int ext4_map_blocks(handle_t *handle, struct inode *inode,
++                  struct ext4_map_blocks *map, int flags)
+ {
+       int retval;
+-      clear_buffer_mapped(bh);
+-      clear_buffer_unwritten(bh);
++      map->m_flags = 0;
++      ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
++                "logical block %lu\n", inode->i_ino, flags, map->m_len,
++                (unsigned long) map->m_lblk);
+-      ext_debug("ext4_get_blocks(): inode %lu, flag %d, max_blocks %u,"
+-                "logical block %lu\n", inode->i_ino, flags, max_blocks,
+-                (unsigned long)block);
+       /*
+        * Try to see if we can get the block without requesting a new
+        * file system block.
+        */
+       down_read((&EXT4_I(inode)->i_data_sem));
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+-              retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
+-                              bh, 0);
++              retval = ext4_ext_map_blocks(handle, inode, map, 0);
+       } else {
+-              retval = ext4_ind_get_blocks(handle, inode, block, max_blocks,
+-                                           bh, 0);
++              retval = ext4_ind_map_blocks(handle, inode, map, 0);
+       }
+       up_read((&EXT4_I(inode)->i_data_sem));
+-      if (retval > 0 && buffer_mapped(bh)) {
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode, "file system corruption",
+-                                             block, bh->b_blocknr, retval);
++                                      map->m_lblk, map->m_pblk, retval);
+               if (ret != 0)
+                       return ret;
+       }
+@@ -1356,7 +1351,7 @@ int ext4_get_blocks(handle_t *handle, st
+        * ext4_ext_get_block() returns th create = 0
+        * with buffer head unmapped.
+        */
+-      if (retval > 0 && buffer_mapped(bh))
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)
+               return retval;
+       /*
+@@ -1369,7 +1364,7 @@ int ext4_get_blocks(handle_t *handle, st
+        * of BH_Unwritten and BH_Mapped flags being simultaneously
+        * set on the buffer_head.
+        */
+-      clear_buffer_unwritten(bh);
++      map->m_flags &= ~EXT4_MAP_UNWRITTEN;
+       /*
+        * New blocks allocate and/or writing to uninitialized extent
+@@ -1392,13 +1387,11 @@ int ext4_get_blocks(handle_t *handle, st
+        * could have changed the inode type in between
+        */
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+-              retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
+-                                            bh, flags);
++              retval = ext4_ext_map_blocks(handle, inode, map, flags);
+       } else {
+-              retval = ext4_ind_get_blocks(handle, inode, block,
+-                                           max_blocks, bh, flags);
++              retval = ext4_ind_map_blocks(handle, inode, map, flags);
+-              if (retval > 0 && buffer_new(bh)) {
++              if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {
+                       /*
+                        * We allocated new blocks which will result in
+                        * i_data's format changing.  Force the migrate
+@@ -1421,15 +1414,38 @@ int ext4_get_blocks(handle_t *handle, st
+               EXT4_I(inode)->i_delalloc_reserved_flag = 0;
+       up_write((&EXT4_I(inode)->i_data_sem));
+-      if (retval > 0 && buffer_mapped(bh)) {
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode, "file system "
+                                              "corruption after allocation",
+-                                             block, bh->b_blocknr, retval);
++                                             map->m_lblk, map->m_pblk,
++                                             retval);
+               if (ret != 0)
+                       return ret;
+       }
+       return retval;
+ }
++EXPORT_SYMBOL(ext4_map_blocks);
++
++int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
++                  unsigned int max_blocks, struct buffer_head *bh,
++                  int flags)
++{
++      struct ext4_map_blocks map;
++      int ret;
++
++      map.m_lblk = block;
++      map.m_len = max_blocks;
++
++      ret = ext4_map_blocks(handle, inode, &map, flags);
++      if (ret < 0)
++              return ret;
++
++      bh->b_blocknr = map.m_pblk;
++      bh->b_size = inode->i_sb->s_blocksize * map.m_len;
++      bh->b_bdev = inode->i_sb->s_bdev;
++      bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
++      return ret;
++}
+ /* Maximum number of blocks we map for direct IO at once. */
+ #define DIO_MAX_BLOCKS 4096
diff --git a/ldiskfs/kernel_patches/patches/rhel6.5/ext4-ext-walk-space.patch b/ldiskfs/kernel_patches/patches/rhel6.5/ext4-ext-walk-space.patch
deleted file mode 100644 (file)
index 714de7b..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-Restore ext4_ext_walk_space().
-Copy from rhel6.4 [2.6.32-358.23.2.el6] kernel.
-
-Index: linux-2.6.32-431.3.1.el6.x86_64/fs/ext4/extents.c
-===================================================================
---- linux-2.6.32-431.3.1.el6.x86_64.orig/fs/ext4/extents.c
-+++ linux-2.6.32-431.3.1.el6.x86_64/fs/ext4/extents.c
-@@ -4487,6 +4487,121 @@ static int ext4_xattr_fiemap(struct inod
-       return (error < 0 ? error : 0);
- }
-+int ext4_ext_walk_space(struct inode *inode, ext4_lblk_t block,
-+                      ext4_lblk_t num, ext_prepare_callback func,
-+                      void *cbdata)
-+{
-+      struct ext4_ext_path *path = NULL;
-+      struct ext4_ext_cache cbex;
-+      struct ext4_extent *ex;
-+      ext4_lblk_t next, start = 0, end = 0;
-+      ext4_lblk_t last = block + num;
-+      int depth, exists, err = 0;
-+
-+      BUG_ON(func == NULL);
-+      BUG_ON(inode == NULL);
-+
-+      while (block < last && block != EXT_MAX_BLOCKS) {
-+              num = last - block;
-+              /* find extent for this block */
-+              down_read(&EXT4_I(inode)->i_data_sem);
-+              path = ext4_ext_find_extent(inode, block, path);
-+              up_read(&EXT4_I(inode)->i_data_sem);
-+              if (IS_ERR(path)) {
-+                      err = PTR_ERR(path);
-+                      path = NULL;
-+                      break;
-+              }
-+
-+              depth = ext_depth(inode);
-+              if (unlikely(path[depth].p_hdr == NULL)) {
-+                      EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
-+                      err = -EIO;
-+                      break;
-+              }
-+              ex = path[depth].p_ext;
-+              next = ext4_ext_next_allocated_block(path);
-+
-+              exists = 0;
-+              if (!ex) {
-+                      /* there is no extent yet, so try to allocate
-+                       * all requested space */
-+                      start = block;
-+                      end = block + num;
-+              } else if (le32_to_cpu(ex->ee_block) > block) {
-+                      /* need to allocate space before found extent */
-+                      start = block;
-+                      end = le32_to_cpu(ex->ee_block);
-+                      if (block + num < end)
-+                              end = block + num;
-+              } else if (block >= le32_to_cpu(ex->ee_block)
-+                                      + ext4_ext_get_actual_len(ex)) {
-+                      /* need to allocate space after found extent */
-+                      start = block;
-+                      end = block + num;
-+                      if (end >= next)
-+                              end = next;
-+              } else if (block >= le32_to_cpu(ex->ee_block)) {
-+                      /*
-+                       * some part of requested space is covered
-+                       * by found extent
-+                       */
-+                      start = block;
-+                      end = le32_to_cpu(ex->ee_block)
-+                              + ext4_ext_get_actual_len(ex);
-+                      if (block + num < end)
-+                              end = block + num;
-+                      exists = 1;
-+              } else {
-+                      BUG();
-+              }
-+              BUG_ON(end <= start);
-+
-+              if (!exists) {
-+                      cbex.ec_block = start;
-+                      cbex.ec_len = end - start;
-+                      cbex.ec_start = 0;
-+              } else {
-+                      cbex.ec_block = le32_to_cpu(ex->ee_block);
-+                      cbex.ec_len = ext4_ext_get_actual_len(ex);
-+                      cbex.ec_start = ext4_ext_pblock(ex);
-+              }
-+
-+              if (unlikely(cbex.ec_len == 0)) {
-+                      EXT4_ERROR_INODE(inode, "cbex.ec_len == 0");
-+                      err = -EIO;
-+                      break;
-+              }
-+              err = func(inode, path, &cbex, ex, cbdata);
-+              ext4_ext_drop_refs(path);
-+
-+              if (err < 0)
-+                      break;
-+
-+              if (err == EXT_REPEAT)
-+                      continue;
-+              else if (err == EXT_BREAK) {
-+                      err = 0;
-+                      break;
-+              }
-+
-+              if (ext_depth(inode) != depth) {
-+                      /* depth was changed. we have to realloc path */
-+                      kfree(path);
-+                      path = NULL;
-+              }
-+
-+              block = cbex.ec_block + cbex.ec_len;
-+      }
-+
-+      if (path) {
-+              ext4_ext_drop_refs(path);
-+              kfree(path);
-+      }
-+
-+      return err;
-+}
-+
- /*
-  * ext4_ext_punch_hole
-  *
-Index: linux-2.6.32-431.3.1.el6.x86_64/fs/ext4/ext4_extents.h
-===================================================================
---- linux-2.6.32-431.3.1.el6.x86_64.orig/fs/ext4/ext4_extents.h
-+++ linux-2.6.32-431.3.1.el6.x86_64/fs/ext4/ext4_extents.h
-@@ -120,6 +120,19 @@ struct ext4_ext_path {
-       struct ext4_extent_header       *p_hdr;
-       struct buffer_head              *p_bh;
- };
-+/*
-+ * to be called by ext4_ext_walk_space()
-+ * negative retcode - error
-+ * positive retcode - signal for ext4_ext_walk_space(), see below
-+ * callback must return valid extent (passed or newly created)
-+ */
-+typedef int (*ext_prepare_callback)(struct inode *, struct ext4_ext_path *,
-+                                      struct ext4_ext_cache *,
-+                                      struct ext4_extent *, void *);
-+
-+#define EXT_CONTINUE   0
-+#define EXT_BREAK      1
-+#define EXT_REPEAT     2
- /*
-  * structure for external API
-@@ -272,6 +285,9 @@ static inline void ext4_idx_store_pblock
-       ix->ei_leaf_hi = cpu_to_le16((unsigned long) ((pb >> 31) >> 1) &
-                                    0xffff);
- }
-+extern int ext4_ext_walk_space(struct inode *, ext4_lblk_t,
-+                      ext4_lblk_t, ext_prepare_callback,
-+                      void *);
- extern int ext4_ext_calc_metadata_amount(struct inode *inode,
-                                        sector_t lblocks);
diff --git a/ldiskfs/kernel_patches/patches/rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch b/ldiskfs/kernel_patches/patches/rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch
new file mode 100644 (file)
index 0000000..0fe87ff
--- /dev/null
@@ -0,0 +1,1019 @@
+From: Theodore Ts'o <tytso@mit.edu>
+
+From e35fd6609b2fee54484d520deccb8f18bf7d38f3 Mon Sep 17 00:00:00 2001
+
+
+Subject: [PATCH] ext4: Add new abstraction ext4_map_blocks() underneath
+ ext4_get_blocks()
+
+Jack up ext4_get_blocks() and add a new function, ext4_map_blocks()
+which uses a much smaller structure, struct ext4_map_blocks which is
+20 bytes, as opposed to a struct buffer_head, which nearly 5 times
+bigger on an x86_64 machine.  By switching things to use
+ext4_map_blocks(), we can save stack space by using ext4_map_blocks()
+since we can avoid allocating a struct buffer_head on the stack.
+
+Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
+Index: linux-stage/fs/ext4/ext4.h
+===================================================================
+--- linux-stage.orig/fs/ext4/ext4.h    2016-07-15 12:13:05.000000000 +0300
++++ linux-stage/fs/ext4/ext4.h 2016-07-15 12:13:05.000000000 +0300
+@@ -142,10 +142,8 @@ struct ext4_allocation_request {
+ #define EXT4_MAP_MAPPED               (1 << BH_Mapped)
+ #define EXT4_MAP_UNWRITTEN    (1 << BH_Unwritten)
+ #define EXT4_MAP_BOUNDARY     (1 << BH_Boundary)
+-#define EXT4_MAP_UNINIT               (1 << BH_Uninit)
+ #define EXT4_MAP_FLAGS                (EXT4_MAP_NEW | EXT4_MAP_MAPPED |\
+-                               EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY |\
+-                               EXT4_MAP_UNINIT)
++                               EXT4_MAP_UNWRITTEN | EXT4_MAP_BOUNDARY)
+ struct ext4_map_blocks {
+       ext4_fsblk_t m_pblk;
+@@ -2194,9 +2192,9 @@ extern int ext4_ext_tree_init(handle_t *
+ extern int ext4_ext_writepage_trans_blocks(struct inode *, int);
+ extern int ext4_ext_index_trans_blocks(struct inode *inode, int nrblocks,
+                                      int chunk);
+-extern 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 flags);
++#define HAVE_EXT4_MAP_BLOCKS
++extern int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
++                             struct ext4_map_blocks *map, int flags);
+ extern void ext4_ext_truncate(struct inode *);
+ extern int ext4_ext_punch_hole(struct inode *inode, loff_t offset,
+                               loff_t length);
+@@ -2206,6 +2204,8 @@ extern long ext4_fallocate(struct inode 
+                         loff_t len);
+ extern int ext4_convert_unwritten_extents(struct inode *inode, loff_t offset,
+                         ssize_t len);
++extern int ext4_map_blocks(handle_t *handle, struct inode *inode,
++                         struct ext4_map_blocks *map, int flags);
+ extern int ext4_get_blocks(handle_t *handle, struct inode *inode,
+                          sector_t block, unsigned int max_blocks,
+                          struct buffer_head *bh, int flags);
+Index: linux-stage/fs/ext4/extents.c
+===================================================================
+--- linux-stage.orig/fs/ext4/extents.c 2016-07-15 12:13:04.000000000 +0300
++++ linux-stage/fs/ext4/extents.c      2016-07-15 12:13:05.000000000 +0300
+@@ -2960,7 +2960,7 @@ fix_extent_len:
+ #define EXT4_EXT_ZERO_LEN 7
+ /*
+- * This function is called by ext4_ext_get_blocks() if someone tries to write
++ * This function is called by ext4_ext_map_blocks() if someone tries to write
+  * to an uninitialized extent. It may result in splitting the uninitialized
+  * extent into multiple extents (upto three - one initialized and two
+  * uninitialized).
+@@ -2970,11 +2970,10 @@ fix_extent_len:
+  *   c> Splits in three extents: Somone is writing in middle of the extent
+  */
+ static int ext4_ext_convert_to_initialized(handle_t *handle,
+-                                              struct inode *inode,
+-                                              struct ext4_ext_path *path,
+-                                              ext4_lblk_t iblock,
+-                                              unsigned int max_blocks,
+-                                              int flags)
++                                         struct inode *inode,
++                                         struct ext4_map_blocks *map,
++                                         struct ext4_ext_path *path,
++                                         int flags)
+ {
+       struct ext4_extent *ex, newex, orig_ex;
+       struct ext4_extent *ex1 = NULL;
+@@ -2990,20 +2989,20 @@ static int ext4_ext_convert_to_initializ
+       ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+-              (unsigned long long)iblock, max_blocks);
++              (unsigned long long)map->m_lblk, map->m_len);
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+-      if (eof_block < iblock + max_blocks)
+-              eof_block = iblock + max_blocks;
++      if (eof_block < map->m_lblk + map->m_len)
++              eof_block = map->m_lblk + map->m_len;
+       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 + ext4_ext_pblock(ex);
++      allocated = ee_len - (map->m_lblk - ee_block);
++      newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
+       ex2 = ex;
+       orig_ex.ee_block = ex->ee_block;
+@@ -3033,10 +3032,10 @@ static int ext4_ext_convert_to_initializ
+               return allocated;
+       }
+-      /* ex1: ee_block to iblock - 1 : uninitialized */
+-      if (iblock > ee_block) {
++      /* ex1: ee_block to map->m_lblk - 1 : uninitialized */
++      if (map->m_lblk > ee_block) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+@@ -3046,15 +3045,15 @@ static int ext4_ext_convert_to_initializ
+        * 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);
++      if (!ex1 && allocated > map->m_len)
++              ex2->ee_len = cpu_to_le16(map->m_len);
+       /* ex3: to ee_block + ee_len : uninitialised */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               unsigned int newdepth;
+               /* If extent has less than EXT4_EXT_ZERO_LEN zerout directly */
+               if (allocated <= EXT4_EXT_ZERO_LEN && may_zeroout) {
+                       /*
+-                       * iblock == ee_block is handled by the zerouout
++                       * map->m_lblk == ee_block is handled by the zerouout
+                        * at the beginning.
+                        * Mark first half uninitialized.
+                        * Mark second half initialized and zero out the
+@@ -3067,7 +3066,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       ex3 = &newex;
+-                      ex3->ee_block = cpu_to_le32(iblock);
++                      ex3->ee_block = cpu_to_le32(map->m_lblk);
+                       ext4_ext_store_pblock(ex3, newblock);
+                       ex3->ee_len = cpu_to_le16(allocated);
+                       err = ext4_ext_insert_extent(handle, inode, path,
+@@ -3081,7 +3080,7 @@ static int ext4_ext_convert_to_initializ
+                               ext4_ext_store_pblock(ex,
+                                       ext4_ext_pblock(&orig_ex));
+                               ext4_ext_dirty(handle, inode, path + depth);
+-                              /* blocks available from iblock */
++                              /* blocks available from map->m_lblk */
+                               return allocated;
+                       } else if (err)
+@@ -3103,8 +3102,8 @@ static int ext4_ext_convert_to_initializ
+                                */
+                               depth = ext_depth(inode);
+                               ext4_ext_drop_refs(path);
+-                              path = ext4_ext_find_extent(inode,
+-                                                              iblock, path);
++                              path = ext4_ext_find_extent(inode, map->m_lblk,
++                                                          path);
+                               if (IS_ERR(path)) {
+                                       err = PTR_ERR(path);
+                                       return err;
+@@ -3124,9 +3123,9 @@ static int ext4_ext_convert_to_initializ
+                       return allocated;
+               }
+               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);
++              ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
++              ext4_ext_store_pblock(ex3, newblock + map->m_len);
++              ex3->ee_len = cpu_to_le16(allocated - map->m_len);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
+               if (err == -ENOSPC && may_zeroout) {
+@@ -3139,7 +3138,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zeroed the full extent */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               } else if (err)
+@@ -3159,7 +3158,7 @@ static int ext4_ext_convert_to_initializ
+               depth = newdepth;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3173,14 +3172,14 @@ static int ext4_ext_convert_to_initializ
+               if (err)
+                       goto out;
+-              allocated = max_blocks;
++              allocated = map->m_len;
+               /* If extent has less than EXT4_EXT_ZERO_LEN and we are trying
+                * to insert a extent in the middle zerout directly
+                * otherwise give the extent a chance to merge to left
+                */
+               if (le16_to_cpu(orig_ex.ee_len) <= EXT4_EXT_ZERO_LEN &&
+-                      iblock != ee_block && may_zeroout) {
++                      map->m_lblk != ee_block && may_zeroout) {
+                       err =  ext4_ext_zeroout(inode, &orig_ex);
+                       if (err)
+                               goto fix_extent_len;
+@@ -3190,7 +3189,7 @@ static int ext4_ext_convert_to_initializ
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zero out the first half */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               }
+       }
+@@ -3201,13 +3200,13 @@ static int ext4_ext_convert_to_initializ
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+       }
+-      /* ex2: iblock to iblock + maxblocks-1 : initialised */
+-      ex2->ee_block = cpu_to_le32(iblock);
++      /* ex2: map->m_lblk to map->m_lblk + maxblocks-1 : initialised */
++      ex2->ee_block = cpu_to_le32(map->m_lblk);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       if (ex2 != ex)
+@@ -3277,7 +3276,7 @@ fix_extent_len:
+ }
+ /*
+- * This function is called by ext4_ext_get_blocks() from
++ * This function is called by ext4_ext_map_blocks() from
+  * ext4_get_blocks_dio_write() when DIO to write
+  * to an uninitialized extent.
+  *
+@@ -3300,9 +3299,8 @@ fix_extent_len:
+  */
+ static int ext4_split_unwritten_extents(handle_t *handle,
+                                       struct inode *inode,
++                                      struct ext4_map_blocks *map,
+                                       struct ext4_ext_path *path,
+-                                      ext4_lblk_t iblock,
+-                                      unsigned int max_blocks,
+                                       int flags)
+ {
+       struct ext4_extent *ex, newex, orig_ex;
+@@ -3318,20 +3316,20 @@ static int ext4_split_unwritten_extents(
+       ext_debug("ext4_split_unwritten_extents: inode %lu, logical"
+               "block %llu, max_blocks %u\n", inode->i_ino,
+-              (unsigned long long)iblock, max_blocks);
++              (unsigned long long)map->m_lblk, map->m_len);
+       eof_block = (inode->i_size + inode->i_sb->s_blocksize - 1) >>
+               inode->i_sb->s_blocksize_bits;
+-      if (eof_block < iblock + max_blocks)
+-              eof_block = iblock + max_blocks;
++      if (eof_block < map->m_lblk + map->m_len)
++              eof_block = map->m_lblk + map->m_len;
+       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 + ext4_ext_pblock(ex);
++      allocated = ee_len - (map->m_lblk - ee_block);
++      newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex);
+       ex2 = ex;
+       orig_ex.ee_block = ex->ee_block;
+@@ -3349,16 +3347,16 @@ static int ext4_split_unwritten_extents(
+        * block where the write begins, and the write completely
+        * covers the extent, then we don't need to split it.
+        */
+-      if ((iblock == ee_block) && (allocated <= max_blocks))
++      if ((map->m_lblk == ee_block) && (allocated <= map->m_len))
+               return allocated;
+       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: ee_block to map->m_lblk - 1 : uninitialized */
++      if (map->m_lblk > ee_block) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+@@ -3368,15 +3366,15 @@ static int ext4_split_unwritten_extents(
+        * 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);
++      if (!ex1 && allocated > map->m_len)
++              ex2->ee_len = cpu_to_le16(map->m_len);
+       /* ex3: to ee_block + ee_len : uninitialised */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               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);
++              ex3->ee_block = cpu_to_le32(map->m_lblk + map->m_len);
++              ext4_ext_store_pblock(ex3, newblock + map->m_len);
++              ex3->ee_len = cpu_to_le16(allocated - map->m_len);
+               ext4_ext_mark_uninitialized(ex3);
+               err = ext4_ext_insert_extent(handle, inode, path, ex3, flags);
+               if (err == -ENOSPC && may_zeroout) {
+@@ -3400,8 +3398,8 @@ static int ext4_split_unwritten_extents(
+                               err =  ext4_ext_zeroout(inode, ex3);
+                               if (err)
+                                       goto fix_extent_len;
+-                              max_blocks = allocated;
+-                              ex2->ee_len = cpu_to_le16(max_blocks);
++                              map->m_len = allocated;
++                              ex2->ee_len = cpu_to_le16(map->m_len);
+                               goto skip;
+                       }
+                       err =  ext4_ext_zeroout(inode, &orig_ex);
+@@ -3413,7 +3411,7 @@ static int ext4_split_unwritten_extents(
+                       ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex));
+                       ext4_ext_dirty(handle, inode, path + depth);
+                       /* zeroed the full extent */
+-                      /* blocks available from iblock */
++                      /* blocks available from map->m_lblk */
+                       return allocated;
+               } else if (err)
+@@ -3433,7 +3431,7 @@ static int ext4_split_unwritten_extents(
+               depth = newdepth;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3446,8 +3444,7 @@ static int ext4_split_unwritten_extents(
+               err = ext4_ext_get_access(handle, inode, path + depth);
+               if (err)
+                       goto out;
+-
+-              allocated = max_blocks;
++              allocated = map->m_len;
+       }
+ skip:
+       /*
+@@ -3457,16 +3454,16 @@ skip:
+        */
+       if (ex1 && ex1 != ex) {
+               ex1 = ex;
+-              ex1->ee_len = cpu_to_le16(iblock - ee_block);
++              ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block);
+               ext4_ext_mark_uninitialized(ex1);
+               ext4_ext_dirty(handle, inode, path + depth);
+               ex2 = &newex;
+       }
+       /*
+-       * ex2: iblock to iblock + maxblocks-1 : to be direct IO written,
+-       * uninitialised still.
++       * ex2: map->m_lblk to map->m_lblk + map->m_len-1 : to be written
++       * using direct I/O, uninitialised still.
+        */
+-      ex2->ee_block = cpu_to_le32(iblock);
++      ex2->ee_block = cpu_to_le32(map->m_lblk);
+       ext4_ext_store_pblock(ex2, newblock);
+       ex2->ee_len = cpu_to_le16(allocated);
+       ext4_ext_mark_uninitialized(ex2);
+@@ -3506,8 +3503,7 @@ fix_extent_len:
+ static int ext4_convert_unwritten_extents_dio(handle_t *handle,
+                                             struct inode *inode,
+-                                            ext4_lblk_t iblock,
+-                                            unsigned int max_blocks,
++                                            struct ext4_map_blocks *map,
+                                             struct ext4_ext_path *path)
+ {
+       struct ext4_extent *ex;
+@@ -3529,14 +3525,13 @@ static int ext4_convert_unwritten_extent
+       /* If extent is larger than requested then split is required */
+-      if (ee_block != iblock || ee_len > max_blocks) {
+-              err = ext4_split_unwritten_extents(handle, inode, path,
+-                                      iblock, max_blocks,
++      if (ee_block != map->m_lblk || ee_len > map->m_len) {
++              err = ext4_split_unwritten_extents(handle, inode, map, path,
+                                       EXT4_EXT_DATA_VALID);
+               if (err < 0)
+                       goto out;
+               ext4_ext_drop_refs(path);
+-              path = ext4_ext_find_extent(inode, iblock, path);
++              path = ext4_ext_find_extent(inode, map->m_lblk, path);
+               if (IS_ERR(path)) {
+                       err = PTR_ERR(path);
+                       goto out;
+@@ -3627,10 +3622,9 @@ out:
+ static int
+ ext4_ext_handle_uninitialized_extents(handle_t *handle, struct inode *inode,
+-                      ext4_lblk_t iblock, unsigned int max_blocks,
++                      struct ext4_map_blocks *map,
+                       struct ext4_ext_path *path, int flags,
+-                      unsigned int allocated, struct buffer_head *bh_result,
+-                      ext4_fsblk_t newblock)
++                      unsigned int allocated, ext4_fsblk_t newblock)
+ {
+       int ret = 0;
+       int err = 0;
+@@ -3638,7 +3632,7 @@ ext4_ext_handle_uninitialized_extents(ha
+       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,
++                inode->i_ino, (unsigned long long)map->m_lblk, map->m_len,
+                 flags, allocated);
+       ext4_ext_show_leaf(inode, path);
+@@ -3651,9 +3645,8 @@ ext4_ext_handle_uninitialized_extents(ha
+       /* DIO get_block() before submit the IO, split the extent */
+       if ((flags & ~EXT4_GET_BLOCKS_METADATA_NOFAIL) ==
+           EXT4_GET_BLOCKS_DIO_CREATE_EXT) {
+-              ret = ext4_split_unwritten_extents(handle,
+-                                              inode, path, iblock,
+-                                              max_blocks, flags);
++              ret = ext4_split_unwritten_extents(handle, inode, map,
++                                                 path, flags);
+               if (ret <= 0)
+                       goto out;
+               /*
+@@ -3674,12 +3667,11 @@ ext4_ext_handle_uninitialized_extents(ha
+       if ((flags & ~EXT4_GET_BLOCKS_METADATA_NOFAIL) ==
+           EXT4_GET_BLOCKS_DIO_CONVERT_EXT) {
+               ret = ext4_convert_unwritten_extents_dio(handle, inode,
+-                                                       iblock, max_blocks,
+-                                                       path);
++                                                       map, path);
+               if (ret >= 0) {
+                       ext4_update_inode_fsync_trans(handle, inode, 1);
+-                      err = check_eofblocks_fl(handle, inode, iblock, path,
+-                                               max_blocks);
++                      err = check_eofblocks_fl(handle, inode, map->m_lblk, path,
++                                               map->m_len);
+               } else
+                       err = ret;
+               goto out2;
+@@ -3701,18 +3693,15 @@ ext4_ext_handle_uninitialized_extents(ha
+                * the buffer head will be unmapped so that
+                * a read from the block returns 0s.
+                */
+-              set_buffer_unwritten(bh_result);
++              map->m_flags |= EXT4_MAP_UNWRITTEN;
+               goto out1;
+       }
+       /* buffered write, writepage time, convert*/
+-      ret = ext4_ext_convert_to_initialized(handle, inode,
+-                                              path, iblock,
+-                                              max_blocks,
+-                                              flags);
++      ret = ext4_ext_convert_to_initialized(handle, inode, map, path, flags);
+       if (ret >= 0) {
+               ext4_update_inode_fsync_trans(handle, inode, 1);
+-              err = check_eofblocks_fl(handle, inode, iblock, path, max_blocks);
++              err = check_eofblocks_fl(handle, inode, map->m_lblk, path, map->m_len);
+               if (err < 0)
+                       goto out2;
+       }
+@@ -3722,7 +3711,7 @@ out:
+               goto out2;
+       } else
+               allocated = ret;
+-      set_buffer_new(bh_result);
++      map->m_flags |= EXT4_MAP_NEW;
+       /*
+        * if we allocated more blocks than requested
+        * we need to make sure we unmap the extra block
+@@ -3730,11 +3719,11 @@ out:
+        * unmapped later when we find the buffer_head marked
+        * new.
+        */
+-      if (allocated > max_blocks) {
++      if (allocated > map->m_len) {
+               unmap_underlying_metadata_blocks(inode->i_sb->s_bdev,
+-                                      newblock + max_blocks,
+-                                      allocated - max_blocks);
+-              allocated = max_blocks;
++                                      newblock + map->m_len,
++                                      allocated - map->m_len);
++              allocated = map->m_len;
+       }
+       /*
+@@ -3748,13 +3737,13 @@ out:
+               ext4_da_update_reserve_space(inode, allocated, 0);
+ map_out:
+-      set_buffer_mapped(bh_result);
++      map->m_flags |= EXT4_MAP_MAPPED;
+ out1:
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
++      if (allocated > map->m_len)
++              allocated = map->m_len;
+       ext4_ext_show_leaf(inode, path);
+-      bh_result->b_bdev = inode->i_sb->s_bdev;
+-      bh_result->b_blocknr = newblock;
++      map->m_pblk = newblock;
++      map->m_len = allocated;
+ out2:
+       if (path) {
+               ext4_ext_drop_refs(path);
+@@ -3781,10 +3770,8 @@ out2:
+  *
+  * return < 0, error case.
+  */
+-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 flags)
++int ext4_ext_map_blocks(handle_t *handle, struct inode *inode,
++                      struct ext4_map_blocks *map, int flags)
+ {
+       struct ext4_ext_path *path = NULL;
+       struct ext4_extent_header *eh;
+@@ -3796,12 +3783,11 @@ int ext4_ext_get_blocks(handle_t *handle
+       ext4_io_end_t *io = ext4_inode_aio(inode);
+       int set_unwritten = 0;
+-      __clear_bit(BH_New, &bh_result->b_state);
+       ext_debug("blocks %u/%u requested for inode %lu\n",
+-                      iblock, max_blocks, inode->i_ino);
++                map->m_lblk, map->m_len, inode->i_ino);
+       /* check in cache */
+-      if (ext4_ext_in_cache(inode, iblock, &newex)) {
++      if (ext4_ext_in_cache(inode, map->m_lblk, &newex)) {
+               if (!newex.ee_start_lo && !newex.ee_start_hi) {
+                       if ((flags & EXT4_GET_BLOCKS_CREATE) == 0) {
+                               /*
+@@ -3813,18 +3799,18 @@ int ext4_ext_get_blocks(handle_t *handle
+                       /* we should allocate requested block */
+               } else {
+                       /* block is already allocated */
+-                      newblock = iblock
++                      newblock = map->m_lblk
+                                  - le32_to_cpu(newex.ee_block)
+                                  + ext4_ext_pblock(&newex);
+                       /* number of remaining blocks in the extent */
+                       allocated = ext4_ext_get_actual_len(&newex) -
+-                                      (iblock - le32_to_cpu(newex.ee_block));
++                                      (map->m_lblk - le32_to_cpu(newex.ee_block));
+                       goto out;
+               }
+       }
+       /* find extent for this block */
+-      path = ext4_ext_find_extent(inode, iblock, NULL);
++      path = ext4_ext_find_extent(inode, map->m_lblk, NULL);
+       if (IS_ERR(path)) {
+               err = PTR_ERR(path);
+               path = NULL;
+@@ -3841,7 +3827,7 @@ int ext4_ext_get_blocks(handle_t *handle
+       if (unlikely(path[depth].p_ext == NULL && depth != 0)) {
+               EXT4_ERROR_INODE(inode, "bad extent address "
+                                "iblock: %d, depth: %d pblock %lld",
+-                               iblock, depth, path[depth].p_block);
++                               map->m_lblk, depth, path[depth].p_block);
+               err = -EIO;
+               goto out2;
+       }
+@@ -3859,11 +3845,11 @@ int ext4_ext_get_blocks(handle_t *handle
+                */
+               ee_len = ext4_ext_get_actual_len(ex);
+               /* if found extent covers block, simply return it */
+-              if (in_range(iblock, ee_block, ee_len)) {
+-                      newblock = iblock - ee_block + ee_start;
++              if (in_range(map->m_lblk, ee_block, ee_len)) {
++                      newblock = map->m_lblk - ee_block + ee_start;
+                       /* number of remaining blocks in the extent */
+-                      allocated = ee_len - (iblock - ee_block);
+-                      ext_debug("%u fit into %u:%d -> %llu\n", iblock,
++                      allocated = ee_len - (map->m_lblk - ee_block);
++                      ext_debug("%u fit into %u:%d -> %llu\n", map->m_lblk,
+                                       ee_block, ee_len, newblock);
+                       /*
+@@ -3875,9 +3861,9 @@ int ext4_ext_get_blocks(handle_t *handle
+                                       ee_len, ee_start);
+                               goto out;
+                       }
+-                      ret = ext4_ext_handle_uninitialized_extents(
+-                              handle, inode, iblock, max_blocks, path,
+-                              flags, allocated, bh_result, newblock);
++                      ret = ext4_ext_handle_uninitialized_extents(handle,
++                                      inode, map, path, flags, allocated,
++                                      newblock);
+                       return ret;
+               }
+       }
+@@ -3891,7 +3877,7 @@ int ext4_ext_get_blocks(handle_t *handle
+                * put just found gap into cache to speed up
+                * subsequent requests
+                */
+-              ext4_ext_put_gap_in_cache(inode, path, iblock);
++              ext4_ext_put_gap_in_cache(inode, path, map->m_lblk);
+               goto out2;
+       }
+       /*
+@@ -3899,11 +3885,11 @@ int ext4_ext_get_blocks(handle_t *handle
+        */
+       /* find neighbour allocated blocks */
+-      ar.lleft = iblock;
++      ar.lleft = map->m_lblk;
+       err = ext4_ext_search_left(inode, path, &ar.lleft, &ar.pleft);
+       if (err)
+               goto out2;
+-      ar.lright = iblock;
++      ar.lright = map->m_lblk;
+       err = ext4_ext_search_right(inode, path, &ar.lright, &ar.pright);
+       if (err)
+               goto out2;
+@@ -3914,26 +3900,26 @@ int ext4_ext_get_blocks(handle_t *handle
+        * EXT_INIT_MAX_LEN and for an uninitialized extent this limit is
+        * EXT_UNINIT_MAX_LEN.
+        */
+-      if (max_blocks > EXT_INIT_MAX_LEN &&
++      if (map->m_len > EXT_INIT_MAX_LEN &&
+           !(flags & EXT4_GET_BLOCKS_UNINIT_EXT))
+-              max_blocks = EXT_INIT_MAX_LEN;
+-      else if (max_blocks > EXT_UNINIT_MAX_LEN &&
++              map->m_len = EXT_INIT_MAX_LEN;
++      else if (map->m_len > EXT_UNINIT_MAX_LEN &&
+                (flags & EXT4_GET_BLOCKS_UNINIT_EXT))
+-              max_blocks = EXT_UNINIT_MAX_LEN;
++              map->m_len = EXT_UNINIT_MAX_LEN;
+-      /* 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);
++      /* Check if we can really insert (m_lblk)::(m_lblk + m_len) extent */
++      newex.ee_block = cpu_to_le32(map->m_lblk);
++      newex.ee_len = cpu_to_le16(map->m_len);
+       err = ext4_ext_check_overlap(inode, &newex, path);
+       if (err)
+               allocated = ext4_ext_get_actual_len(&newex);
+       else
+-              allocated = max_blocks;
++              allocated = map->m_len;
+       /* allocate new block */
+       ar.inode = inode;
+-      ar.goal = ext4_ext_find_goal(inode, path, iblock);
+-      ar.logical = iblock;
++      ar.goal = ext4_ext_find_goal(inode, path, map->m_lblk);
++      ar.logical = map->m_lblk;
+       ar.len = allocated;
+       if (S_ISREG(inode->i_mode))
+               ar.flags = EXT4_MB_HINT_DATA;
+@@ -3966,7 +3952,7 @@ int ext4_ext_get_blocks(handle_t *handle
+                       set_unwritten = 1;
+       }
+-      err = check_eofblocks_fl(handle, inode, iblock, path, ar.len);
++      err = check_eofblocks_fl(handle, inode, map->m_lblk, path, ar.len);
+       if (err)
+               goto out2;
+@@ -3997,9 +3983,9 @@ int ext4_ext_get_blocks(handle_t *handle
+       /* previous routine could use block we allocated */
+       newblock = ext4_ext_pblock(&newex);
+       allocated = ext4_ext_get_actual_len(&newex);
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
+-      set_buffer_new(bh_result);
++      if (allocated > map->m_len)
++              allocated = map->m_len;
++      map->m_flags |= EXT4_MAP_NEW;
+       /*
+        * Update reserved blocks/metadata blocks after successful
+@@ -4013,17 +3999,17 @@ int ext4_ext_get_blocks(handle_t *handle
+        * when it is _not_ an uninitialized extent.
+        */
+       if ((flags & EXT4_GET_BLOCKS_UNINIT_EXT) == 0) {
+-              ext4_ext_put_in_cache(inode, iblock, allocated, newblock);
++              ext4_ext_put_in_cache(inode, map->m_lblk, allocated, newblock);
+               ext4_update_inode_fsync_trans(handle, inode, 1);
+       } else
+               ext4_update_inode_fsync_trans(handle, inode, 0);
+ out:
+-      if (allocated > max_blocks)
+-              allocated = max_blocks;
++      if (allocated > map->m_len)
++              allocated = map->m_len;
+       ext4_ext_show_leaf(inode, path);
+-      set_buffer_mapped(bh_result);
+-      bh_result->b_bdev = inode->i_sb->s_bdev;
+-      bh_result->b_blocknr = newblock;
++      map->m_flags |= EXT4_MAP_MAPPED;
++      map->m_pblk = newblock;
++      map->m_len = allocated;
+ out2:
+       if (path) {
+               ext4_ext_drop_refs(path);
+@@ -4206,7 +4192,7 @@ retry:
+               if (ret <= 0) {
+ #ifdef EXT4FS_DEBUG
+                       WARN_ON(ret <= 0);
+-                      printk(KERN_ERR "%s: ext4_ext_get_blocks "
++                      printk(KERN_ERR "%s: ext4_ext_map_blocks "
+                                   "returned error inode#%lu, block=%u, "
+                                   "max_blocks=%u", __func__,
+                                   inode->i_ino, block, max_blocks);
+@@ -4720,6 +4706,5 @@ EXPORT_SYMBOL(ext4_ext_insert_extent);
+ EXPORT_SYMBOL(ext4_mb_new_blocks);
+ EXPORT_SYMBOL(ext4_ext_calc_credits_for_insert);
+ EXPORT_SYMBOL(ext4_mark_inode_dirty);
+-EXPORT_SYMBOL(ext4_ext_walk_space);
+ EXPORT_SYMBOL(ext4_ext_find_extent);
+ EXPORT_SYMBOL(ext4_ext_drop_refs);
+Index: linux-stage/fs/ext4/inode.c
+===================================================================
+--- linux-stage.orig/fs/ext4/inode.c   2016-07-15 12:13:05.000000000 +0300
++++ linux-stage/fs/ext4/inode.c        2016-07-15 12:15:36.000000000 +0300
+@@ -200,7 +200,7 @@ int ext4_truncate_restart_trans(handle_t
+       int ret;
+       /*
+-       * Drop i_data_sem to avoid deadlock with ext4_get_blocks At this
++       * Drop i_data_sem to avoid deadlock with ext4_map_blocks.  At this
+        * moment, get_block can be called only for blocks inside i_size since
+        * page cache has been already dropped and writes are blocked by
+        * i_mutex. So we can safely drop the i_data_sem here.
+@@ -970,9 +970,9 @@ err_out:
+ }
+ /*
+- * The ext4_ind_get_blocks() function handles non-extents inodes
++ * The ext4_ind_map_blocks() function handles non-extents inodes
+  * (i.e., using the traditional indirect/double-indirect i_blocks
+- * scheme) for ext4_get_blocks().
++ * scheme) for ext4_map_blocks().
+  *
+  * Allocation strategy is simple: if we have to allocate something, we will
+  * have to go the whole way to leaf. So let's do it before attaching anything
+@@ -991,15 +991,14 @@ err_out:
+  * return = 0, if plain lookup failed.
+  * return < 0, error case.
+  *
+- * The ext4_ind_get_blocks() function should be called with
++ * The ext4_ind_map_blocks() function should be called with
+  * down_write(&EXT4_I(inode)->i_data_sem) if allocating filesystem
+  * blocks (i.e., flags has EXT4_GET_BLOCKS_CREATE set) or
+  * down_read(&EXT4_I(inode)->i_data_sem) if not allocating file system
+  * blocks.
+  */
+-static int ext4_ind_get_blocks(handle_t *handle, struct inode *inode,
+-                             ext4_lblk_t iblock, unsigned int maxblocks,
+-                             struct buffer_head *bh_result,
++static int ext4_ind_map_blocks(handle_t *handle, struct inode *inode,
++                             struct ext4_map_blocks *map,
+                              int flags)
+ {
+       int err = -EIO;
+@@ -1015,7 +1014,7 @@ static int ext4_ind_get_blocks(handle_t 
+       J_ASSERT(!(ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)));
+       J_ASSERT(handle != NULL || (flags & EXT4_GET_BLOCKS_CREATE) == 0);
+-      depth = ext4_block_to_path(inode, iblock, offsets,
++      depth = ext4_block_to_path(inode, map->m_lblk, offsets,
+                                  &blocks_to_boundary);
+       if (depth == 0)
+@@ -1026,10 +1025,9 @@ static int ext4_ind_get_blocks(handle_t 
+       /* Simplest case - block found, no allocation needed */
+       if (!partial) {
+               first_block = le32_to_cpu(chain[depth - 1].key);
+-              clear_buffer_new(bh_result);
+               count++;
+               /*map more blocks*/
+-              while (count < maxblocks && count <= blocks_to_boundary) {
++              while (count < map->m_len && count <= blocks_to_boundary) {
+                       ext4_fsblk_t blk;
+                       blk = le32_to_cpu(*(chain[depth-1].p + count));
+@@ -1049,7 +1047,7 @@ static int ext4_ind_get_blocks(handle_t 
+       /*
+        * Okay, we need to do block allocation.
+       */
+-      goal = ext4_find_goal(inode, iblock, partial);
++      goal = ext4_find_goal(inode, map->m_lblk, partial);
+       /* the number of blocks need to allocate for [d,t]indirect blocks */
+       indirect_blks = (chain + depth) - partial - 1;
+@@ -1059,11 +1057,11 @@ static int ext4_ind_get_blocks(handle_t 
+        * direct blocks to allocate for this branch.
+        */
+       count = ext4_blks_to_allocate(partial, indirect_blks,
+-                                      maxblocks, blocks_to_boundary);
++                                    map->m_len, blocks_to_boundary);
+       /*
+        * Block out ext4_truncate while we alter the tree
+        */
+-      err = ext4_alloc_branch(handle, inode, iblock, indirect_blks,
++      err = ext4_alloc_branch(handle, inode, map->m_lblk, indirect_blks,
+                               &count, goal,
+                               offsets + (partial - chain), partial);
+@@ -1075,18 +1073,20 @@ static int ext4_ind_get_blocks(handle_t 
+        * may need to return -EAGAIN upwards in the worst case.  --sct
+        */
+       if (!err)
+-              err = ext4_splice_branch(handle, inode, iblock,
++              err = ext4_splice_branch(handle, inode, map->m_lblk,
+                                        partial, indirect_blks, count);
+       if (err)
+               goto cleanup;
+-      set_buffer_new(bh_result);
++      map->m_flags |= EXT4_MAP_NEW;
+       ext4_update_inode_fsync_trans(handle, inode, 1);
+ got_it:
+-      map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));
++      map->m_flags |= EXT4_MAP_MAPPED;
++      map->m_pblk = le32_to_cpu(chain[depth-1].key);
++      map->m_len = count;
+       if (count > blocks_to_boundary)
+-              set_buffer_boundary(bh_result);
++              map->m_flags |= EXT4_MAP_BOUNDARY;
+       err = count;
+       /* Clean up and exit */
+       partial = chain + depth - 1;    /* the whole chain */
+@@ -1096,7 +1096,6 @@ cleanup:
+               brelse(partial->bh);
+               partial--;
+       }
+-      BUFFER_TRACE(bh_result, "returned");
+ out:
+       return err;
+ }
+@@ -1291,15 +1290,15 @@ static pgoff_t ext4_num_dirty_pages(stru
+ }
+ /*
+- * The ext4_get_blocks() function tries to look up the requested blocks,
++ * The ext4_map_blocks() function tries to look up the requested blocks,
+  * and returns if the blocks are already mapped.
+  *
+  * Otherwise it takes the write lock of the i_data_sem and allocate blocks
+  * and store the allocated blocks in the result buffer head and mark it
+  * mapped.
+  *
+- * If file type is extents based, it will call ext4_ext_get_blocks(),
+- * Otherwise, call with ext4_ind_get_blocks() to handle indirect mapping
++ * If file type is extents based, it will call ext4_ext_map_blocks(),
++ * Otherwise, call with ext4_ind_map_blocks() to handle indirect mapping
+  * based files
+  *
+  * On success, it returns the number of blocks being mapped or allocate.
+@@ -1312,39 +1311,33 @@ static pgoff_t ext4_num_dirty_pages(stru
+  *
+  * It returns the error in case of allocation failure.
+  */
+-int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
+-                  unsigned int max_blocks, struct buffer_head *bh,
+-                  int flags)
++int ext4_map_blocks(handle_t *handle, struct inode *inode,
++                  struct ext4_map_blocks *map, int flags)
+ {
+       int retval;
++ 
++      map->m_flags = 0;
++      ext_debug("ext4_map_blocks(): inode %lu, flag %d, max_blocks %u,"
++                "logical block %lu\n", inode->i_ino, flags, map->m_len,
++                (unsigned long) map->m_lblk);
+-      clear_buffer_mapped(bh);
+-      clear_buffer_unwritten(bh);
+-
+-      ext_debug("ext4_get_blocks(): inode %lu, flag %d, max_blocks %u,"
+-                "logical block %lu\n", inode->i_ino, flags, max_blocks,
+-                (unsigned long)block);
+       /*
+        * Try to see if we can get the block without requesting a new
+        * file system block.
+        */
+       down_read((&EXT4_I(inode)->i_data_sem));
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+-              retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
+-                              bh, 0);
++              retval = ext4_ext_map_blocks(handle, inode, map, 0);
+       } else {
+-              retval = ext4_ind_get_blocks(handle, inode, block, max_blocks,
+-                                           bh, 0);
++              retval = ext4_ind_map_blocks(handle, inode, map, 0);
+       }
+       up_read((&EXT4_I(inode)->i_data_sem));
+-      if (retval > 0 && buffer_mapped(bh)) {
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode, "file system corruption",
+-                                             block, bh->b_blocknr, retval);
+-              if (ret != 0) {
+-                      bh->b_blocknr = 0;
++                                      map->m_lblk, map->m_pblk, retval);
++              if (ret != 0)
+                       return ret;
+-              }
+       }
+       /* If it is only a block(s) look up */
+@@ -1358,7 +1351,7 @@ int ext4_get_blocks(handle_t *handle, st
+        * ext4_ext_get_block() returns th create = 0
+        * with buffer head unmapped.
+        */
+-      if (retval > 0 && buffer_mapped(bh))
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED)
+               return retval;
+       /*
+@@ -1371,7 +1364,7 @@ int ext4_get_blocks(handle_t *handle, st
+        * of BH_Unwritten and BH_Mapped flags being simultaneously
+        * set on the buffer_head.
+        */
+-      clear_buffer_unwritten(bh);
++      map->m_flags &= ~EXT4_MAP_UNWRITTEN;
+       /*
+        * New blocks allocate and/or writing to uninitialized extent
+@@ -1394,13 +1387,11 @@ int ext4_get_blocks(handle_t *handle, st
+        * could have changed the inode type in between
+        */
+       if (ext4_test_inode_flag(inode, EXT4_INODE_EXTENTS)) {
+-              retval =  ext4_ext_get_blocks(handle, inode, block, max_blocks,
+-                                            bh, flags);
++              retval = ext4_ext_map_blocks(handle, inode, map, flags);
+       } else {
+-              retval = ext4_ind_get_blocks(handle, inode, block,
+-                                           max_blocks, bh, flags);
++              retval = ext4_ind_map_blocks(handle, inode, map, flags);
+-              if (retval > 0 && buffer_new(bh)) {
++              if (retval > 0 && map->m_flags & EXT4_MAP_NEW) {
+                       /*
+                        * We allocated new blocks which will result in
+                        * i_data's format changing.  Force the migrate
+@@ -1423,17 +1414,39 @@ int ext4_get_blocks(handle_t *handle, st
+               EXT4_I(inode)->i_delalloc_reserved_flag = 0;
+       up_write((&EXT4_I(inode)->i_data_sem));
+-      if (retval > 0 && buffer_mapped(bh)) {
++      if (retval > 0 && map->m_flags & EXT4_MAP_MAPPED) {
+               int ret = check_block_validity(inode, "file system "
+                                              "corruption after allocation",
+-                                             block, bh->b_blocknr, retval);
++                                             map->m_lblk, map->m_pblk,
++                                             retval);
+               if (ret != 0) {
+-                      bh->b_blocknr = 0;
+                       return ret;
+               }
+       }
+       return retval;
+ }
++EXPORT_SYMBOL(ext4_map_blocks);
++
++int ext4_get_blocks(handle_t *handle, struct inode *inode, sector_t block,
++                  unsigned int max_blocks, struct buffer_head *bh,
++                  int flags)
++{
++      struct ext4_map_blocks map;
++      int ret;
++
++      map.m_lblk = block;
++      map.m_len = max_blocks;
++
++      ret = ext4_map_blocks(handle, inode, &map, flags);
++      if (ret < 0)
++              return ret;
++
++      bh->b_blocknr = map.m_pblk;
++      bh->b_size = inode->i_sb->s_blocksize * map.m_len;
++      bh->b_bdev = inode->i_sb->s_bdev;
++      bh->b_state = (bh->b_state & ~EXT4_MAP_FLAGS) | map.m_flags;
++      return ret;
++}
+ /* Maximum number of blocks we map for direct IO at once. */
+ #define DIO_MAX_BLOCKS 4096
index 96c9b89..b14d599 100644 (file)
@@ -5,11 +5,11 @@ current and unsafe implementation with ext4_ext_path[] array
 re-[sizing,allocation], even with more recent and related patches
 that will be integrated in more recent Kernels.
 
 re-[sizing,allocation], even with more recent and related patches
 that will be integrated in more recent Kernels.
 
-Index: linux-2.6.32-504.el6.x86_64/fs/ext4/ext4.h
+Index: linux-stage/fs/ext4/ext4.h
 ===================================================================
 ===================================================================
---- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/ext4.h
-+++ linux-2.6.32-504.el6.x86_64/fs/ext4/ext4.h
-@@ -1147,6 +1147,9 @@
+--- linux-stage.orig/fs/ext4/ext4.h    2016-07-15 10:55:51.000000000 +0300
++++ linux-stage/fs/ext4/ext4.h 2016-07-15 10:56:19.000000000 +0300
+@@ -1153,6 +1153,9 @@ struct ext4_sb_info {
        unsigned long s_ext_extents;
  #endif
  
        unsigned long s_ext_extents;
  #endif
  
@@ -19,32 +19,11 @@ Index: linux-2.6.32-504.el6.x86_64/fs/ext4/ext4.h
        /* for buddy allocator */
        struct ext4_group_info ***s_group_info;
        struct inode *s_buddy_cache;
        /* for buddy allocator */
        struct ext4_group_info ***s_group_info;
        struct inode *s_buddy_cache;
-Index: linux-2.6.32-504.el6.x86_64/fs/ext4/super.c
+Index: linux-stage/fs/ext4/extents.c
 ===================================================================
 ===================================================================
---- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/super.c
-+++ linux-2.6.32-504.el6.x86_64/fs/ext4/super.c
-@@ -3529,6 +3529,8 @@
-               if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
-                       goto failed_mount3;
-+      ext4_ext_init(sb); /* needed before using extent-mapped journal */
-+
-       /*
-        * The first inode we look at is the journal inode.  Don't try
-        * root first: it may be modified in the journal!
-@@ -3722,7 +3724,6 @@
-               goto failed_mount4a;
-       }
--      ext4_ext_init(sb);
-       err = ext4_mb_init(sb, needs_recovery);
-       if (err) {
-               ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",
-Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
-===================================================================
---- linux-2.6.32-504.el6.x86_64.orig/fs/ext4/extents.c
-+++ linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
-@@ -699,8 +699,9 @@
+--- linux-stage.orig/fs/ext4/extents.c 2016-07-15 10:55:51.000000000 +0300
++++ linux-stage/fs/ext4/extents.c      2016-07-15 10:56:19.000000000 +0300
+@@ -698,8 +698,9 @@ ext4_ext_find_extent(struct inode *inode
  
        /* account possible depth increase */
        if (!path) {
  
        /* account possible depth increase */
        if (!path) {
@@ -56,7 +35,7 @@ Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
                if (!path)
                        return ERR_PTR(-ENOMEM);
                alloc = 1;
                if (!path)
                        return ERR_PTR(-ENOMEM);
                alloc = 1;
-@@ -1915,11 +1916,8 @@
+@@ -1907,11 +1908,8 @@ static int ext4_fill_fiemap_extents(stru
                /* find extent for this block */
                down_read(&EXT4_I(inode)->i_data_sem);
  
                /* find extent for this block */
                down_read(&EXT4_I(inode)->i_data_sem);
  
@@ -70,19 +49,17 @@ Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
  
                path = ext4_ext_find_extent(inode, block, path);
                if (IS_ERR(path)) {
  
                path = ext4_ext_find_extent(inode, block, path);
                if (IS_ERR(path)) {
-@@ -2664,8 +2662,9 @@
+@@ -2656,7 +2654,8 @@ again:
                        path[k].p_block =
                                le16_to_cpu(path[k].p_hdr->eh_entries)+1;
        } else {
 -              path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
                        path[k].p_block =
                                le16_to_cpu(path[k].p_hdr->eh_entries)+1;
        } else {
 -              path = kzalloc(sizeof(struct ext4_ext_path) * (depth + 1),
--                             GFP_NOFS);
 +              path = kzalloc(sizeof(struct ext4_ext_path) *
 +                             EXT4_SB(inode->i_sb)->s_max_ext_tree_depth,
 +              path = kzalloc(sizeof(struct ext4_ext_path) *
 +                             EXT4_SB(inode->i_sb)->s_max_ext_tree_depth,
-+                             GFP_NOFS);
+                              GFP_NOFS);
                if (path == NULL) {
                        ext4_journal_stop(handle);
                if (path == NULL) {
                        ext4_journal_stop(handle);
-                       return -ENOMEM;
-@@ -2790,13 +2789,15 @@
+@@ -2781,13 +2780,15 @@ out:
   */
  void ext4_ext_init(struct super_block *sb)
  {
   */
  void ext4_ext_init(struct super_block *sb)
  {
@@ -100,7 +77,7 @@ Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
  #ifdef AGGRESSIVE_TEST
                printk(", aggressive tests");
  #endif
  #ifdef AGGRESSIVE_TEST
                printk(", aggressive tests");
  #endif
-@@ -2805,14 +2806,35 @@
+@@ -2796,14 +2797,35 @@ void ext4_ext_init(struct super_block *s
  #endif
  #ifdef EXTENTS_STATS
                printk(", stats");
  #endif
  #ifdef EXTENTS_STATS
                printk(", stats");
@@ -140,17 +117,24 @@ Index: linux-2.6.32-504.el6.x86_64/fs/ext4/extents.c
        }
  }
  
        }
  }
  
-@@ -4614,11 +4636,8 @@
-                       break;
-               }
--              if (ext_depth(inode) != depth) {
--                      /* depth was changed. we have to realloc path */
--                      kfree(path);
--                      path = NULL;
--              }
-+              /* path of max possible depth will be allocated during
-+               * first pass, so its space can be re-used for each loop */
+Index: linux-stage/fs/ext4/super.c
+===================================================================
+--- linux-stage.orig/fs/ext4/super.c   2016-07-15 10:55:51.000000000 +0300
++++ linux-stage/fs/ext4/super.c        2016-07-15 10:56:19.000000000 +0300
+@@ -3529,6 +3529,8 @@ static int ext4_fill_super(struct super_
+               if (ext4_multi_mount_protect(sb, le64_to_cpu(es->s_mmp_block)))
+                       goto failed_mount3;
  
  
-               block = cbex.ec_block + cbex.ec_len;
++      ext4_ext_init(sb); /* needed before using extent-mapped journal */
++
+       /*
+        * The first inode we look at is the journal inode.  Don't try
+        * root first: it may be modified in the journal!
+@@ -3722,7 +3724,6 @@ no_journal:
+               goto failed_mount4a;
        }
        }
+-      ext4_ext_init(sb);
+       err = ext4_mb_init(sb, needs_recovery);
+       if (err) {
+               ext4_msg(sb, KERN_ERR, "failed to initalize mballoc (%d)",
index daeda62..e057b99 100644 (file)
@@ -2,7 +2,6 @@ rhel6.3/ext4-use-vzalloc-in-ext4_fill_flex_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
-rhel6.3/ext4-map_inode_page-2.6.18.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
index d656b85..42434ef 100644 (file)
@@ -2,7 +2,6 @@ rhel6.3/ext4-use-vzalloc-in-ext4_fill_flex_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
-rhel6.3/ext4-map_inode_page-2.6.18.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
@@ -28,8 +27,7 @@ rhel6.3/ext4-large-eas.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
-rhel6.5/ext4-ext-walk-space.patch
-rhel6.3/ext4-store-tree-generation-at-find.patch
+rhel6.5/ext4-add-new-abstraction-ext4_map_blocks.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
index e6fae81..96400b0 100644 (file)
@@ -2,7 +2,6 @@ rhel6.3/ext4-use-vzalloc-in-ext4_fill_flex_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
-rhel6.3/ext4-map_inode_page-2.6.18.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
@@ -27,8 +26,7 @@ rhel6.3/ext4-large-eas.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
-rhel6.5/ext4-ext-walk-space.patch
-rhel6.3/ext4-store-tree-generation-at-find.patch
+rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
index c25d944..67f4bde 100644 (file)
@@ -2,7 +2,6 @@ rhel6.3/ext4-use-vzalloc-in-ext4_fill_flex_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
-rhel6.3/ext4-map_inode_page-2.6.18.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
@@ -27,8 +26,7 @@ rhel6.3/ext4-large-eas.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.3/ext4-journal-callback.patch
-rhel6.5/ext4-ext-walk-space.patch
-rhel6.3/ext4-store-tree-generation-at-find.patch
+rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.3/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
index 9e31c93..3c4ab71 100644 (file)
@@ -2,7 +2,6 @@ rhel6.3/ext4-use-vzalloc-in-ext4_fill_flex_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
 rhel6.3/ext4-introduce-ext4_kvmalloc-ext4_kzalloc-and-ext4_kvfree.patch
 rhel6.3/ext4-add-missing-kfree-on-error-return-path-in-add_new_gdb.patch
 rhel6.3/ext4-use-ext4_kvzalloc-ext4_kvmalloc-for-s_group_desc-and-s_group_info.patch
-rhel6.3/ext4-map_inode_page-2.6.18.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
 rhel6.3/export-ext4-2.6.patch
 rhel6.3/ext4-remove-cond_resched-calls.patch
 rhel6.3/ext4-nlink-2.6.patch
@@ -27,8 +26,7 @@ rhel6.3/ext4-large-eas.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.8/ext4-journal-callback.patch
 rhel6.3/ext4-disable-mb-cache.patch
 rhel6.3/ext4-nocmtime-2.6.patch
 rhel6.8/ext4-journal-callback.patch
-rhel6.5/ext4-ext-walk-space.patch
-rhel6.3/ext4-store-tree-generation-at-find.patch
+rhel6.6/ext4-add-new-abstraction-ext4_map_blocks.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.8/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch
 rhel6.3/ext4-large-dir.patch
 rhel6.8/ext4-pdirop.patch
 rhel6.4/ext4-extra-isize.patch