diff options
-rw-r--r-- | fs/ext4/extents.c | 97 |
1 files changed, 50 insertions, 47 deletions
diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index 81bb9a67ec8e..c393fcfd038e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3346,21 +3346,18 @@ out: * c> Splits in three extents: Somone is splitting in middle of the extent * */ -static int ext4_split_extent(handle_t *handle, - struct inode *inode, - struct ext4_ext_path **ppath, - struct ext4_map_blocks *map, - int split_flag, - int flags) +static struct ext4_ext_path *ext4_split_extent(handle_t *handle, + struct inode *inode, + struct ext4_ext_path *path, + struct ext4_map_blocks *map, + int split_flag, int flags, + unsigned int *allocated) { - struct ext4_ext_path *path = *ppath; ext4_lblk_t ee_block; struct ext4_extent *ex; unsigned int ee_len, depth; - int err = 0; int unwritten; int split_flag1, flags1; - int allocated = map->m_len; depth = ext_depth(inode); ex = path[depth].p_ext; @@ -3378,33 +3375,25 @@ static int ext4_split_extent(handle_t *handle, split_flag1 |= EXT4_EXT_DATA_VALID1; path = ext4_split_extent_at(handle, inode, path, map->m_lblk + map->m_len, split_flag1, flags1); - if (IS_ERR(path)) { - err = PTR_ERR(path); - *ppath = NULL; - goto out; + if (IS_ERR(path)) + return path; + /* + * Update path is required because previous ext4_split_extent_at + * may result in split of original leaf or extent zeroout. + */ + path = ext4_find_extent(inode, map->m_lblk, path, flags); + if (IS_ERR(path)) + return path; + depth = ext_depth(inode); + ex = path[depth].p_ext; + if (!ex) { + EXT4_ERROR_INODE(inode, "unexpected hole at %lu", + (unsigned long) map->m_lblk); + ext4_free_ext_path(path); + return ERR_PTR(-EFSCORRUPTED); } - *ppath = path; - } else { - allocated = ee_len - (map->m_lblk - ee_block); - } - /* - * Update path is required because previous ext4_split_extent_at() may - * result in split of original leaf or extent zeroout. - */ - path = ext4_find_extent(inode, map->m_lblk, path, flags); - if (IS_ERR(path)) { - *ppath = NULL; - return PTR_ERR(path); - } - *ppath = path; - depth = ext_depth(inode); - ex = path[depth].p_ext; - if (!ex) { - EXT4_ERROR_INODE(inode, "unexpected hole at %lu", - (unsigned long) map->m_lblk); - return -EFSCORRUPTED; + unwritten = ext4_ext_is_unwritten(ex); } - unwritten = ext4_ext_is_unwritten(ex); if (map->m_lblk >= ee_block) { split_flag1 = split_flag & EXT4_EXT_DATA_VALID2; @@ -3415,17 +3404,18 @@ static int ext4_split_extent(handle_t *handle, } path = ext4_split_extent_at(handle, inode, path, map->m_lblk, split_flag1, flags); - if (IS_ERR(path)) { - err = PTR_ERR(path); - *ppath = NULL; - goto out; - } - *ppath = path; + if (IS_ERR(path)) + return path; } + if (allocated) { + if (map->m_lblk + map->m_len > ee_block + ee_len) + *allocated = ee_len - (map->m_lblk - ee_block); + else + *allocated = map->m_len; + } ext4_ext_show_leaf(inode, path); -out: - return err ? err : allocated; + return path; } /* @@ -3670,10 +3660,15 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, } fallback: - err = ext4_split_extent(handle, inode, ppath, &split_map, split_flag, - flags); - if (err > 0) - err = 0; + path = ext4_split_extent(handle, inode, path, &split_map, split_flag, + flags, NULL); + if (IS_ERR(path)) { + err = PTR_ERR(path); + *ppath = NULL; + goto out; + } + err = 0; + *ppath = path; out: /* If we have gotten a failure, don't zero out status tree */ if (!err) { @@ -3719,6 +3714,7 @@ static int ext4_split_convert_extents(handle_t *handle, struct ext4_extent *ex; unsigned int ee_len; int split_flag = 0, depth; + unsigned int allocated = 0; ext_debug(inode, "logical block %llu, max_blocks %u\n", (unsigned long long)map->m_lblk, map->m_len); @@ -3746,7 +3742,14 @@ static int ext4_split_convert_extents(handle_t *handle, split_flag |= (EXT4_EXT_MARK_UNWRIT2 | EXT4_EXT_DATA_VALID2); } flags |= EXT4_GET_BLOCKS_PRE_IO; - return ext4_split_extent(handle, inode, ppath, map, split_flag, flags); + path = ext4_split_extent(handle, inode, path, map, split_flag, flags, + &allocated); + if (IS_ERR(path)) { + *ppath = NULL; + return PTR_ERR(path); + } + *ppath = path; + return allocated; } static int ext4_convert_unwritten_extents_endio(handle_t *handle, |