From: Allison Henderson Subject: Re: [PATCH v2 3/3] ext4:Reimplement convert and split_unwritten. Date: Fri, 13 May 2011 10:53:30 -0700 Message-ID: <4DCD701A.8000006@linux.vnet.ibm.com> References: <1304388301-9452-1-git-send-email-xiaoqiangnk@gmail.com> <1304388301-9452-4-git-send-email-xiaoqiangnk@gmail.com> <1305235594.9708.75.camel@mingming-laptop> <4DCD5E87.5000607@linux.vnet.ibm.com> Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Cc: Mingming Cao , linux-ext4@vger.kernel.org, tytso@mit.edu To: Yongqiang Yang Return-path: Received: from e8.ny.us.ibm.com ([32.97.182.138]:44609 "EHLO e8.ny.us.ibm.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1756534Ab1EMRxp (ORCPT ); Fri, 13 May 2011 13:53:45 -0400 Received: from d01relay07.pok.ibm.com (d01relay07.pok.ibm.com [9.56.227.147]) by e8.ny.us.ibm.com (8.14.4/8.13.1) with ESMTP id p4DHRPHJ020878 for ; Fri, 13 May 2011 13:27:25 -0400 Received: from d01av04.pok.ibm.com (d01av04.pok.ibm.com [9.56.224.64]) by d01relay07.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id p4DHrfgi1388728 for ; Fri, 13 May 2011 13:53:41 -0400 Received: from d01av04.pok.ibm.com (loopback [127.0.0.1]) by d01av04.pok.ibm.com (8.14.4/8.13.1/NCO v10.0 AVout) with ESMTP id p4DHrdpZ007995 for ; Fri, 13 May 2011 13:53:41 -0400 In-Reply-To: <4DCD5E87.5000607@linux.vnet.ibm.com> Sender: linux-ext4-owner@vger.kernel.org List-ID: On 5/13/2011 9:38 AM, Allison Henderson wrote: > On 5/12/2011 7:06 PM, Yongqiang Yang wrote: >> On Fri, May 13, 2011 at 5:26 AM, Mingming Cao wrote: >>> On Mon, 2011-05-02 at 19:05 -0700, Yongqiang Yang wrote: >>>> v0->v1: >>>> -- ext4_ext_convert_initialized() zeroout whole extent when the >>>> extent's >>>> length is less than 14. >>>> >>>> convert and split unwritten are reimplemented based on >>>> ext4_split_extent() >>>> added in last patch. >>>> >>>> Signed-off-by: Yongqiang Yang >>>> Tested-by: Allison Henderson >>>> --- >>>> fs/ext4/extents.c | 480 >>>> ++++++++--------------------------------------------- >>>> 1 files changed, 72 insertions(+), 408 deletions(-) >>>> >>>> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c >>>> index db1d67c..9e7c7b3 100644 >>>> --- a/fs/ext4/extents.c >>>> +++ b/fs/ext4/extents.c >>>> @@ -2757,17 +2757,13 @@ static int >>>> ext4_ext_convert_to_initialized(handle_t *handle, >>>> struct ext4_map_blocks *map, >>>> struct ext4_ext_path *path) >>>> { >>>> - struct ext4_extent *ex, newex, orig_ex; >>>> - struct ext4_extent *ex1 = NULL; >>>> - struct ext4_extent *ex2 = NULL; >>>> - struct ext4_extent *ex3 = NULL; >>>> - struct ext4_extent_header *eh; >>>> + struct ext4_map_blocks split_map; >>>> + struct ext4_extent zero_ex; >>>> + struct ext4_extent *ex; >>>> ext4_lblk_t ee_block, eof_block; >>>> unsigned int allocated, ee_len, depth; >>>> - ext4_fsblk_t newblock; >>>> int err = 0; >>>> - int ret = 0; >>>> - int may_zeroout; >>>> + int split_flag = 0; >>>> >>>> ext_debug("ext4_ext_convert_to_initialized: inode %lu, logical" >>>> "block %llu, max_blocks %u\n", inode->i_ino, >>>> @@ -2779,280 +2775,87 @@ static int >>>> ext4_ext_convert_to_initialized(handle_t *handle, >>>> 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 - (map->m_lblk - ee_block); >>>> - newblock = map->m_lblk - ee_block + ext4_ext_pblock(ex); >>>> - >>>> - ex2 = ex; >>>> - orig_ex.ee_block = ex->ee_block; >>>> - orig_ex.ee_len = cpu_to_le16(ee_len); >>>> - ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex)); >>>> >>>> + WARN_ON(map->m_lblk< ee_block); >>>> /* >>>> * It is safe to convert extent to initialized via explicit >>>> * zeroout only if extent is fully insde i_size or new_size. >>>> */ >>>> - may_zeroout = ee_block + ee_len<= eof_block; >>>> + split_flag |= ee_block + ee_len<= eof_block ? EXT4_EXT_MAY_ZEROOUT >>>> : 0; >>>> >>>> - err = ext4_ext_get_access(handle, inode, path + depth); >>>> - if (err) >>>> - goto out; >>>> /* If extent has less than 2*EXT4_EXT_ZERO_LEN zerout directly */ >>>> - if (ee_len<= 2*EXT4_EXT_ZERO_LEN&& may_zeroout) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> + if (ee_len<= 2*EXT4_EXT_ZERO_LEN&& >>>> + (EXT4_EXT_MAY_ZEROOUT& split_flag)) { >>>> + err = ext4_ext_zeroout(inode, ex); >>>> if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zeroed the full extent */ >>>> - return allocated; >>>> - } >>>> - >>>> - /* ex1: ee_block to map->m_lblk - 1 : uninitialized */ >>>> - if (map->m_lblk> ee_block) { >>>> - ex1 = ex; >>>> - ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block); >>>> - ext4_ext_mark_uninitialized(ex1); >>>> - ex2 =&newex; >>>> - } >>>> - /* >>>> - * for sanity, update the length of the ex2 extent before >>>> - * we insert ex3, if ex1 is NULL. This is to avoid temporary >>>> - * overlap of blocks. >>>> - */ >>>> - if (!ex1&& allocated> map->m_len) >>>> - ex2->ee_len = cpu_to_le16(map->m_len); >>>> - /* ex3: to ee_block + ee_len : uninitialised */ >>>> - 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) { >>>> - /* >>>> - * 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 >>>> - * initialized extent >>>> - */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = cpu_to_le16(ee_len - allocated); >>>> - ext4_ext_mark_uninitialized(ex); >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - >>>> - ex3 =&newex; >>>> - 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, >>>> - ex3, 0); >>>> - if (err == -ENOSPC) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, >>>> - ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* blocks available from map->m_lblk */ >>>> - return allocated; >>>> - >>>> - } else if (err) >>>> - goto fix_extent_len; >>>> - >>>> - /* >>>> - * We need to zero out the second half because >>>> - * an fallocate request can update file size and >>>> - * converting the second half to initialized extent >>>> - * implies that we can leak some junk data to user >>>> - * space. >>>> - */ >>>> - err = ext4_ext_zeroout(inode, ex3); >>>> - if (err) { >>>> - /* >>>> - * We should actually mark the >>>> - * second half as uninit and return error >>>> - * Insert would have changed the extent >>>> - */ >>>> - depth = ext_depth(inode); >>>> - ext4_ext_drop_refs(path); >>>> - path = ext4_ext_find_extent(inode, map->m_lblk, >>>> - path); >>>> - if (IS_ERR(path)) { >>>> - err = PTR_ERR(path); >>>> - return err; >>>> - } >>>> - /* get the second half extent details */ >>>> - ex = path[depth].p_ext; >>>> - err = ext4_ext_get_access(handle, inode, >>>> - path + depth); >>>> - if (err) >>>> - return err; >>>> - ext4_ext_mark_uninitialized(ex); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - return err; >>>> - } >>>> - >>>> - /* zeroed the second half */ >>>> - return allocated; >>>> - } >>>> - ex3 =&newex; >>>> - 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, 0); >>>> - if (err == -ENOSPC&& may_zeroout) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zeroed the full extent */ >>>> - /* blocks available from map->m_lblk */ >>>> - return allocated; >>>> - >>>> - } else if (err) >>>> - goto fix_extent_len; >>>> - /* >>>> - * The depth, and hence eh& ex might change >>>> - * as part of the insert above. >>>> - */ >>>> - newdepth = ext_depth(inode); >>>> - /* >>>> - * update the extent length after successful insert of the >>>> - * split extent >>>> - */ >>>> - ee_len -= ext4_ext_get_actual_len(ex3); >>>> - orig_ex.ee_len = cpu_to_le16(ee_len); >>>> - may_zeroout = ee_block + ee_len<= eof_block; >>>> - >>>> - depth = newdepth; >>>> - ext4_ext_drop_refs(path); >>>> - path = ext4_ext_find_extent(inode, map->m_lblk, path); >>>> - if (IS_ERR(path)) { >>>> - err = PTR_ERR(path); >>>> goto out; >>>> - } >>>> - eh = path[depth].p_hdr; >>>> - ex = path[depth].p_ext; >>>> - if (ex2 !=&newex) >>>> - ex2 = ex; >>>> >>>> err = ext4_ext_get_access(handle, inode, path + depth); >>>> if (err) >>>> goto out; >>>> - >>>> - allocated = 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&& >>>> - map->m_lblk != ee_block&& may_zeroout) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zero out the first half */ >>>> - /* blocks available from map->m_lblk */ >>>> - return allocated; >>>> - } >>>> - } >>>> - /* >>>> - * If there was a change of depth as part of the >>>> - * insertion of ex3 above, we need to update the length >>>> - * of the ex1 extent again here >>>> - */ >>>> - if (ex1&& ex1 != ex) { >>>> - ex1 = ex; >>>> - ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block); >>>> - ext4_ext_mark_uninitialized(ex1); >>>> - ex2 =&newex; >>>> - } >>>> - /* 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) >>>> - goto insert; >>>> - /* >>>> - * New (initialized) extent starts from the first block >>>> - * in the current extent. i.e., ex2 == ex >>>> - * We have to see if it can be merged with the extent >>>> - * on the left. >>>> - */ >>>> - if (ex2> EXT_FIRST_EXTENT(eh)) { >>>> - /* >>>> - * To merge left, pass "ex2 - 1" to try_to_merge(), >>>> - * since it merges towards right _only_. >>>> - */ >>>> - ret = ext4_ext_try_to_merge(inode, path, ex2 - 1); >>>> - if (ret) { >>>> - err = ext4_ext_correct_indexes(handle, inode, path); >>>> - if (err) >>>> - goto out; >>>> - depth = ext_depth(inode); >>>> - ex2--; >>>> - } >>>> + ext4_ext_mark_initialized(ex); >>>> + ext4_ext_try_to_merge(inode, path, ex); >>>> + err = ext4_ext_dirty(handle, inode, path + depth); >>>> + goto out; >>>> } >>>> + >>>> /* >>>> - * Try to Merge towards right. This might be required >>>> - * only when the whole extent is being written to. >>>> - * i.e. ex2 == ex and ex3 == NULL. >>>> + * four cases: >>>> + * 1. split the extent into three extents. >>>> + * 2. split the extent into two extents, zeroout the first half. >>>> + * 3. split the extent into two extents, zeroout the second half. >>>> + * 4. split the extent into two extents with out zeroout. >>>> */ >>>> - if (!ex3) { >>>> - ret = ext4_ext_try_to_merge(inode, path, ex2); >>>> - if (ret) { >>>> - err = ext4_ext_correct_indexes(handle, inode, path); >>>> + split_map.m_lblk = map->m_lblk; >>>> + split_map.m_len = map->m_len; >>>> + >>>> + if (allocated> map->m_len) { >>>> + if (allocated<= EXT4_EXT_ZERO_LEN&& >>>> + (EXT4_EXT_MAY_ZEROOUT& split_flag)) { >>>> + /* case 3 */ >>>> + zero_ex.ee_block = >>>> + cpu_to_le32(map->m_lblk + map->m_len); >>>> + zero_ex.ee_len = cpu_to_le16(allocated - map->m_len); >>> Hmm, the original code zero out the entire [map->m_lblk, allocated], >>> where here we only zero out a portion of it. it doesnt match the split >>> len below also. >> Yeah, I just zero out a portion of it which is not the requested. I >> think the requested part will have non-zero data. >>> >>> >>>> + ext4_ext_store_pblock(&zero_ex, >>>> + ext4_ext_pblock(ex) + map->m_lblk - ee_block); >>>> + err = ext4_ext_zeroout(inode,&zero_ex); >>>> if (err) >>>> goto out; >>>> + split_map.m_lblk = map->m_lblk; >>>> + split_map.m_len = allocated; >>>> + } else if ((map->m_lblk - ee_block + map->m_len< >>>> + EXT4_EXT_ZERO_LEN)&& >>>> + (EXT4_EXT_MAY_ZEROOUT& split_flag)) { >>>> + /* case 2 */ >>>> + if (map->m_lblk != ee_block) { >>>> + zero_ex.ee_block = ex->ee_block; >>>> + zero_ex.ee_len = cpu_to_le16(map->m_lblk - >>>> + ee_block); >>> similar to above, the original code zero out the entire [ex->ee_block, >>> map->m_lblk - ee_block + map->m_len], where here we only zero out a >>> portion of it. same to the mismatch of the split len also. >> Similar to above. Just a optimization. >>> >>> >>>> + ext4_ext_store_pblock(&zero_ex, >>>> + ext4_ext_pblock(ex)); >>>> + err = ext4_ext_zeroout(inode,&zero_ex); >>>> + if (err) >>>> + goto out; >>>> + } >>>> + >>>> - allocated = map->m_lblk - ee_block + map->m_len; >>>> + >>>> + split_map.m_lblk = ee_block; >>>> + split_map.m_len = map->m_lblk - ee_block + map->m_len; >> + allocated = map->m_len; >>> >>> I am also puzzled whether the zeroed-out extent get marked as >>> initialized, as done in original patch. The whole point of zero out is >>> to avoid frequent split of the unitizlized extent if the extent is >>> short. I will take a closer look at the previous patch. >>> >>> Another issue, upon success, "allocated" will return from this function. >>> But here allocated is the zero out length that start from ee_block, not >>> the length from map->m_lblk. this is wrong, the caller >>> ext4_ext_map_blocks expecting the length of mapped blocks from >>> map->m_lblk. We now return more mapped blocks than what really done. I >>> suspect the fsx error come from this bug. >> Yeah. it is a bug. >> >> Hi Allison, >> >> Could you test with modification above? Here is a bug. I will also >> test it. >> >> Thank you. > > Hi all, > > Well, I tried the above fix this morning, but it looks like it was only > able to run about a half hour. Some good news though, last night I tried > just changing "zero_ex.ee_len = cpu_to_le16(allocated - map->m_len);" to > "zero_ex.ee_len = cpu_to_le16(allocated);" in case 3 and it ran all > night with no problems. Maybe we need both changes then. I'll start > another test run today. > > Allison Henderson Ah, nevermind, I just realized I need to move zero_ex.ee_block too. Just to be clear, here is the fix I am testing now: zero_ex.ee_block = - cpu_to_le32(map->m_lblk + map->m_len); - zero_ex.ee_len = cpu_to_le16(allocated - map->m_len); + cpu_to_le32(map->m_lblk); + zero_ex.ee_len = cpu_to_le16(allocated); ext4_ext_store_pblock(&zero_ex, ext4_ext_pblock(ex) + map->m_lblk - ee_block); err = ext4_ext_zeroout(inode, &zero_ex); @@ -2842,10 +2842,9 @@ static int ext4_ext_convert_to_initialized(handle_t *handle, goto out; } - allocated = map->m_lblk - ee_block + map->m_len; - split_map.m_lblk = ee_block; - split_map.m_len = allocated; + split_map.m_len = map->m_lblk - ee_block + map->m_len; + allocated = map->m_len; } } > >>> >>>> } >>> >>> >>>> } >>>> - /* Mark modified extent as dirty */ >>>> - err = ext4_ext_dirty(handle, inode, path + depth); >>>> - goto out; >>>> -insert: >>>> - err = ext4_ext_insert_extent(handle, inode, path,&newex, 0); >>>> - if (err == -ENOSPC&& may_zeroout) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zero out the first half */ >>>> - return allocated; >>>> - } else if (err) >>>> - goto fix_extent_len; >>>> + >>>> + allocated = ext4_split_extent(handle, inode, path, >>>> +&split_map, split_flag, 0); >>>> + if (allocated< 0) >>>> + err = allocated; >>>> + >>>> out: >>>> - ext4_ext_show_leaf(inode, path); >>>> return err ? err : allocated; >>>> - >>>> -fix_extent_len: >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_mark_uninitialized(ex); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - return err; >>>> } >>>> >>>> /* >>>> @@ -3083,15 +2886,11 @@ static int >>>> ext4_split_unwritten_extents(handle_t *handle, >>>> struct ext4_ext_path *path, >>>> int flags) >>>> { >>>> - struct ext4_extent *ex, newex, orig_ex; >>>> - struct ext4_extent *ex1 = NULL; >>>> - struct ext4_extent *ex2 = NULL; >>>> - struct ext4_extent *ex3 = NULL; >>>> - ext4_lblk_t ee_block, eof_block; >>>> - unsigned int allocated, ee_len, depth; >>>> - ext4_fsblk_t newblock; >>>> - int err = 0; >>>> - int may_zeroout; >>>> + ext4_lblk_t eof_block; >>>> + ext4_lblk_t ee_block; >>>> + struct ext4_extent *ex; >>>> + unsigned int ee_len; >>>> + int split_flag = 0, depth; >>>> >>>> ext_debug("ext4_split_unwritten_extents: inode %lu, logical" >>>> "block %llu, max_blocks %u\n", inode->i_ino, >>>> @@ -3101,155 +2900,20 @@ static int >>>> ext4_split_unwritten_extents(handle_t *handle, >>>> inode->i_sb->s_blocksize_bits; >>>> if (eof_block< map->m_lblk + map->m_len) >>>> eof_block = map->m_lblk + map->m_len; >>>> - >>>> - depth = ext_depth(inode); >>>> - ex = path[depth].p_ext; >>>> - ee_block = le32_to_cpu(ex->ee_block); >>>> - ee_len = ext4_ext_get_actual_len(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; >>>> - orig_ex.ee_len = cpu_to_le16(ee_len); >>>> - ext4_ext_store_pblock(&orig_ex, ext4_ext_pblock(ex)); >>>> - >>>> /* >>>> * It is safe to convert extent to initialized via explicit >>>> * zeroout only if extent is fully insde i_size or new_size. >>>> */ >>>> - may_zeroout = ee_block + ee_len<= eof_block; >>>> - >>>> - /* >>>> - * If the uninitialized extent begins at the same logical >>>> - * block where the write begins, and the write completely >>>> - * covers the extent, then we don't need to split it. >>>> - */ >>>> - 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 map->m_lblk - 1 : uninitialized */ >>>> - if (map->m_lblk> ee_block) { >>>> - ex1 = ex; >>>> - ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block); >>>> - ext4_ext_mark_uninitialized(ex1); >>>> - ex2 =&newex; >>>> - } >>>> - /* >>>> - * for sanity, update the length of the ex2 extent before >>>> - * we insert ex3, if ex1 is NULL. This is to avoid temporary >>>> - * overlap of blocks. >>>> - */ >>>> - if (!ex1&& allocated> map->m_len) >>>> - ex2->ee_len = cpu_to_le16(map->m_len); >>>> - /* ex3: to ee_block + ee_len : uninitialised */ >>>> - if (allocated> map->m_len) { >>>> - unsigned int newdepth; >>>> - ex3 =&newex; >>>> - 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) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zeroed the full extent */ >>>> - /* blocks available from map->m_lblk */ >>>> - return allocated; >>>> - >>>> - } else if (err) >>>> - goto fix_extent_len; >>>> - /* >>>> - * The depth, and hence eh& ex might change >>>> - * as part of the insert above. >>>> - */ >>>> - newdepth = ext_depth(inode); >>>> - /* >>>> - * update the extent length after successful insert of the >>>> - * split extent >>>> - */ >>>> - ee_len -= ext4_ext_get_actual_len(ex3); >>>> - orig_ex.ee_len = cpu_to_le16(ee_len); >>>> - may_zeroout = ee_block + ee_len<= eof_block; >>>> - >>>> - depth = newdepth; >>>> - ext4_ext_drop_refs(path); >>>> - path = ext4_ext_find_extent(inode, map->m_lblk, path); >>>> - if (IS_ERR(path)) { >>>> - err = PTR_ERR(path); >>>> - goto out; >>>> - } >>>> - ex = path[depth].p_ext; >>>> - if (ex2 !=&newex) >>>> - ex2 = ex; >>>> + depth = ext_depth(inode); >>>> + ex = path[depth].p_ext; >>>> + ee_block = le32_to_cpu(ex->ee_block); >>>> + ee_len = ext4_ext_get_actual_len(ex); >>>> >>>> - err = ext4_ext_get_access(handle, inode, path + depth); >>>> - if (err) >>>> - goto out; >>>> + split_flag |= ee_block + ee_len<= eof_block ? EXT4_EXT_MAY_ZEROOUT >>>> : 0; >>>> + split_flag |= EXT4_EXT_MARK_UNINIT2; >>>> >>>> - allocated = map->m_len; >>>> - } >>>> - /* >>>> - * If there was a change of depth as part of the >>>> - * insertion of ex3 above, we need to update the length >>>> - * of the ex1 extent again here >>>> - */ >>>> - if (ex1&& ex1 != ex) { >>>> - ex1 = ex; >>>> - ex1->ee_len = cpu_to_le16(map->m_lblk - ee_block); >>>> - ext4_ext_mark_uninitialized(ex1); >>>> - ex2 =&newex; >>>> - } >>>> - /* >>>> - * 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(map->m_lblk); >>>> - ext4_ext_store_pblock(ex2, newblock); >>>> - ex2->ee_len = cpu_to_le16(allocated); >>>> - ext4_ext_mark_uninitialized(ex2); >>>> - if (ex2 != ex) >>>> - goto insert; >>>> - /* Mark modified extent as dirty */ >>>> - err = ext4_ext_dirty(handle, inode, path + depth); >>>> - ext_debug("out here\n"); >>>> - goto out; >>>> -insert: >>>> - err = ext4_ext_insert_extent(handle, inode, path,&newex, flags); >>>> - if (err == -ENOSPC&& may_zeroout) { >>>> - err = ext4_ext_zeroout(inode,&orig_ex); >>>> - if (err) >>>> - goto fix_extent_len; >>>> - /* update the extent length and mark as initialized */ >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - /* zero out the first half */ >>>> - return allocated; >>>> - } else if (err) >>>> - goto fix_extent_len; >>>> -out: >>>> - ext4_ext_show_leaf(inode, path); >>>> - return err ? err : allocated; >>>> - >>>> -fix_extent_len: >>>> - ex->ee_block = orig_ex.ee_block; >>>> - ex->ee_len = orig_ex.ee_len; >>>> - ext4_ext_store_pblock(ex, ext4_ext_pblock(&orig_ex)); >>>> - ext4_ext_mark_uninitialized(ex); >>>> - ext4_ext_dirty(handle, inode, path + depth); >>>> - return err; >>>> + flags |= EXT4_GET_BLOCKS_PRE_IO; >>>> + return ext4_split_extent(handle, inode, path, map, split_flag, >>>> flags); >>>> } >>>> >>>> static int ext4_convert_unwritten_extents_endio(handle_t *handle, >>> >>> >>> >> >> >> > > -- > To unsubscribe from this list: send the line "unsubscribe linux-ext4" in > the body of a message to majordomo@vger.kernel.org > More majordomo info at http://vger.kernel.org/majordomo-info.html