lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <4D6D5C1C.8080204@linux.vnet.ibm.com>
Date:	Tue, 01 Mar 2011 13:50:36 -0700
From:	Allison Henderson <achender@...ux.vnet.ibm.com>
To:	Dave Young <hidave.darkstar@...il.com>
CC:	linux-ext4@...r.kernel.org
Subject: Re: [Ext4 punch hole 3/5] Ext4 Punch Hole Support: Punch out extents

On 3/1/2011 12:38 AM, Dave Young wrote:
> On Tue, Mar 1, 2011 at 11:08 AM, Allison Henderson
> <achender@...ux.vnet.ibm.com>  wrote:
>> This patch modifes the truncate routines to support hole punching
>> Below is a brief summary of the pacthes changes:
>>
>> - Added new function "ext_ext4_rm_leaf_punch_hole".
>>         This routine is very similar to ext_ext4_rm_leaf except that
>>         it punches a hole in a leaf instead of just removing the tail
>>         or removing the entire leaf all together
> 
> These two functions are almost duplicate,
> merge them as one function would be better

Alrighty, initially they were separated to make development easier, but it hasnt deviated a whole lot from the original ext_ext4_rm_leaf routine, so I will see if I can get them merged back together.

> 
> Also as Andreas Dilger said coding style problems need fix as well
> 
>>
>> - Implemented the "remove head" case in the ext_remove_blocks routine
>>         This routine is used by ext_ext4_rm_leaf to remove the tail
>>         of an extent during a truncate.  The new ext_ext4_rm_leaf_punch_hole
>>         routine will now also use it to remove the head of an extent in the
>>         case that the hole covers a region of blocks at the beginning
>>         of an extent.
>>
>> - Added "stop" param to ext4_ext_remove_space routine
>>         This function has been modified to accept a stop parameter.  If stop
>>         is not EXT_MAX_BLOCK, the routine will call ext_ext4_rm_leaf_punch_hole
>>         instead of ext_ext4_rm_leaf.
>>
>> - Added new "ext4_ext_release_blocks" routine
>>         This routine is basically the ext4_ext_truncate routine, but
>>         modified to accept a "stop" param in addition to "start".  The existing
>>         ext4_ext_truncate routine has now become a wrapper to this
>>         function.  The stop parameter just passed through to ext4_ext_remove_space
>>
>> Signed-off-by: Allison Henderson<achender@...ibm.com>
>> ---
>> :100644 100644 ab2e42e... efbc3ef... M  fs/ext4/extents.c
>>   fs/ext4/extents.c |  265 +++++++++++++++++++++++++++++++++++++++++++++++++++--
>>   1 files changed, 256 insertions(+), 9 deletions(-)
>>
>> diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c
>> index ab2e42e..efbc3ef 100644
>> --- a/fs/ext4/extents.c
>> +++ b/fs/ext4/extents.c
>> @@ -2159,8 +2159,16 @@ static int ext4_remove_blocks(handle_t *handle, struct inode *inode,
>>                 ext4_free_blocks(handle, inode, 0, start, num, flags);
>>         } else if (from == le32_to_cpu(ex->ee_block)
>>                    &&  to<= le32_to_cpu(ex->ee_block) + ee_len - 1) {
>> -               printk(KERN_INFO "strange request: removal %u-%u from %u:%u\n",
>> -                       from, to, le32_to_cpu(ex->ee_block), ee_len);
>> +               /* head removal */
>> +               ext4_lblk_t num;
>> +               ext4_fsblk_t start;
>> +
>> +               num = to - from;
>> +               start = ext4_ext_pblock(ex);
>> +
>> +               ext_debug("free first %u blocks starting %llu\n", num, start);
>> +               ext4_free_blocks(handle, inode, 0, start, num, flags);
>> +
>>         } else {
>>                 printk(KERN_INFO "strange request: removal(2) "
>>                                 "%u-%u from %u:%u\n",
>> @@ -2401,6 +2409,214 @@ out:
>>   }
>>
>>   /*
>> + * ext4_ext_rm_leaf_punch_hole() Removes the extents associated with the
>> + * blocks appearing between "start" and "stop", and splits the extents
>> + * if "start" and "stop" appear in the same extent
>> + */
>> +static int
>> +ext4_ext_rm_leaf_punch_hole(handle_t *handle, struct inode *inode,
>> +               struct ext4_ext_path *path, ext4_lblk_t start, ext4_lblk_t stop)
>> +{
>> +       int err = 0, correct_index = 0;
>> +       int depth = ext_depth(inode), credits;
>> +       struct ext4_extent_header *eh;
>> +       ext4_lblk_t a, b, block;
>> +       unsigned int num;
>> +       ext4_lblk_t ex_ee_block;
>> +       unsigned short ex_ee_len;
>> +       unsigned int uninitialized = 0;
>> +       struct ext4_extent *ex, *i_ex;
>> +
>> +       /* the header must be checked already in ext4_ext_remove_space() */
>> +       ext_debug("truncate since %u in leaf\n", start);
>> +       if (!path[depth].p_hdr)
>> +               path[depth].p_hdr = ext_block_hdr(path[depth].p_bh);
>> +
>> +       eh = path[depth].p_hdr;
>> +       if (unlikely(path[depth].p_hdr == NULL)) {
>> +               EXT4_ERROR_INODE(inode, "path[%d].p_hdr == NULL", depth);
>> +               return -EIO;
>> +       }
>> +
>> +       /* find where to start removing */
>> +       ex = EXT_LAST_EXTENT(eh);
>> +
>> +       ex_ee_block = le32_to_cpu(ex->ee_block);
>> +       ex_ee_len = ext4_ext_get_actual_len(ex);
>> +
>> +       while (ex>= EXT_FIRST_EXTENT(eh)&&
>> +                       ex_ee_block + ex_ee_len>  start ) {
>> +               if (ext4_ext_is_uninitialized(ex))
>> +                       uninitialized = 1;
>> +               else
>> +                       uninitialized = 0;
>> +
>> +               ext_debug("remove ext %u:[%d]%d\n", ex_ee_block,
>> +                        uninitialized, ex_ee_len);
>> +               path[depth].p_ext = ex;
>> +
>> +               a = ex_ee_block>  start ? ex_ee_block : start;
>> +               b = ex_ee_block+ex_ee_len - 1<  stop ? ex_ee_block+ex_ee_len - 1 : stop;
>> +
>> +               ext_debug("  border %u:%u\n", a, b);
>> +
>> +               /* If this extent is beyond the end of the hole, skip it  */
>> +               if(stop<= ex_ee_block){
>> +                       ex--;
>> +                       ex_ee_block = le32_to_cpu(ex->ee_block);
>> +                       ex_ee_len = ext4_ext_get_actual_len(ex);
>> +                       continue;
>> +               }
>> +               else if (a != ex_ee_block&&  b != ex_ee_block + ex_ee_len - 1) {
>> +                       /*
>> +                        * If this is a truncate, then this condition should
>> +                        * never happen becase at least one of the end points
>> +                        * needs to be on the edge of the extent.
>> +                        */
>> +                       if(stop == EXT_MAX_BLOCK){
>> +                               ext_debug("  bad truncate %u:%u\n", start, stop);
>> +                               block = 0;
>> +                               num = 0;
>> +                               err = -EIO;
>> +                               goto out;
>> +                       }
>> +                       /*
>> +                        * else this is a hole punch, so the extent needs to
>> +                        * be split since neither edge of the hole is on the
>> +                        * extent edge
>> +                        */
>> +                       else{
>> +                               err = ext4_split_extents(handle,inode, b,path,0);
>> +                               if(err)
>> +                                       goto out;
>> +
>> +                               ex_ee_len = ext4_ext_get_actual_len(ex);
>> +
>> +                               b = ex_ee_block+ex_ee_len - 1<  stop ? ex_ee_block+ex_ee_len - 1 : stop;
>> +
>> +                               /* Then remove tail of this extent */
>> +                               block = ex_ee_block;
>> +                               num = a - block;
>> +                       }
>> +               }
>> +               else if (a != ex_ee_block) {
>> +                       /* remove tail of the extent */
>> +                       block = ex_ee_block;
>> +                       num = a - block;
>> +               }
>> +               else if (b != ex_ee_block + ex_ee_len - 1) {
>> +                       /* remove head of the extent */
>> +                       block = b;
>> +                       num =  ex_ee_block+ex_ee_len - b;
>> +
>> +                       /* If this is a truncate, this condition should never happen */
>> +                       if(stop == EXT_MAX_BLOCK){
>> +                               err = -EIO;
>> +                               goto out;
>> +                       }
>> +               }
>> +               else {
>> +                       /* remove whole extent: excellent! */
>> +                       block = ex_ee_block;
>> +                       num = 0;
>> +                       if (a != ex_ee_block){
>> +                               err = -EIO;
>> +                               goto out;
>> +                       }
>> +
>> +                       if (b != ex_ee_block + ex_ee_len - 1){
>> +                               err = -EIO;
>> +                               goto out;
>> +                       }
>> +               }
>> +
>> +               /*
>> +                * 3 for leaf, sb, and inode plus 2 (bmap and group
>> +                * descriptor) for each block group; assume two block
>> +                * groups plus ex_ee_len/blocks_per_block_group for
>> +                * the worst case
>> +                */
>> +               credits = 7 + 2*(ex_ee_len/EXT4_BLOCKS_PER_GROUP(inode->i_sb));
>> +               if (ex == EXT_FIRST_EXTENT(eh)) {
>> +                       correct_index = 1;
>> +                       credits += (ext_depth(inode)) + 1;
>> +               }
>> +               credits += EXT4_MAXQUOTAS_TRANS_BLOCKS(inode->i_sb);
>> +               err = ext4_ext_truncate_extend_restart(handle, inode, credits);
>> +               if (err)
>> +                       goto out;
>> +
>> +               err = ext4_ext_get_access(handle, inode, path + depth);
>> +               if (err)
>> +                       goto out;
>> +
>> +               err = ext4_remove_blocks(handle, inode, ex, a, b);
>> +               if (err)
>> +                       goto out;
>> +
>> +               ex->ee_block = cpu_to_le32(block);
>> +               ex->ee_len = cpu_to_le16(num);
>> +
>> +               /*
>> +                * If this was a head removal, then we need to update
>> +                * the physical block since it is now at a different
>> +                * location
>> +                */
>> +               if (block != ex_ee_block)
>> +                       ext4_ext_store_pblock(ex, ext4_ext_pblock(ex)+(b-a) );
>> +
>> +               /*
>> +                * Do not mark uninitialized if all the blocks in the
>> +                * extent have been removed.
>> +                */
>> +               if (uninitialized&&  num)
>> +                       ext4_ext_mark_uninitialized(ex);
>> +
>> +               err = ext4_ext_dirty(handle, inode, path + depth);
>> +               if (err)
>> +                       goto out;
>> +
>> +               ext_debug("new extent: %u:%u:%llu\n", block, num,
>> +                               ext4_ext_pblock(ex));
>> +
>> +               if (num == 0) {
>> +
>> +                       /*
>> +                        * For hole punching, we need to scoot all the
>> +                        * extents up so that we dont have blank extents
>> +                        * in the middle
>> +                        */
>> +                       for(i_ex = ex; i_ex<  EXT_LAST_EXTENT(eh); i_ex++){
>> +                               memcpy(i_ex, i_ex+1, sizeof(struct ext4_extent));
>> +                       }
>> +
>> +                       /* now get rid of the extent at the end  */
>> +                       memset(i_ex, 0, sizeof(struct ext4_extent));
>> +
>> +                       le16_add_cpu(&eh->eh_entries, -1);
>> +               }
>> +
>> +               ex--;
>> +               ex_ee_block = le32_to_cpu(ex->ee_block);
>> +               ex_ee_len = ext4_ext_get_actual_len(ex);
>> +
>> +       }
>> +
>> +       if (correct_index&&  eh->eh_entries)
>> +               err = ext4_ext_correct_indexes(handle, inode, path);
>> +
>> +       /*
>> +        * If this leaf is free, then we should
>> +        * remove it from index block above
>> +        */
>> +       if (err == 0&&  eh->eh_entries == 0&&  path[depth].p_bh != NULL)
>> +               err = ext4_ext_rm_idx(handle, inode, path + depth);
>> +
>> +out:
>> +       return err;
>> +}
>> +
>> +/*
>>   * ext4_ext_more_to_rm:
>>   * returns 1 if current index has to be freed (even partial)
>>   */
>> @@ -2421,7 +2637,7 @@ ext4_ext_more_to_rm(struct ext4_ext_path *path)
>>         return 1;
>>   }
>>
>> -static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start)
>> +static int ext4_ext_remove_space(struct inode *inode, ext4_lblk_t start, ext4_lblk_t stop)
>>   {
>>         struct super_block *sb = inode->i_sb;
>>         int depth = ext_depth(inode);
>> @@ -2460,7 +2676,10 @@ again:
>>         while (i>= 0&&  err == 0) {
>>                 if (i == depth) {
>>                         /* this is leaf block */
>> -                       err = ext4_ext_rm_leaf(handle, inode, path, start);
>> +                       if(stop == EXT_MAX_BLOCK)
>> +                               err = ext4_ext_rm_leaf(handle, inode, path, start);
>> +                       else
>> +                               err = ext4_ext_rm_leaf_punch_hole(handle, inode, path, start, stop);
>>                         /* root level has p_bh == NULL, brelse() eats this */
>>                         brelse(path[i].p_bh);
>>                         path[i].p_bh = NULL;
>> @@ -3627,11 +3846,23 @@ out2:
>>         return err ? err : allocated;
>>   }
>>
>> -void ext4_ext_truncate(struct inode *inode)
>> +/*
>> + * ext4_ext_release_blocks
>> + *
>> + * Releases the blocks in a file starting at block "start"
>> + * and ending at block "stop".  Pass EXT_MAX_BLOCK
>> + * for "stop" to just truncate the file to the
>> + * "start" block
>> + *
>> + * @inode: The inode of the file to release blocks from
>> + * @start: The starting block of the hole
>> + * @stop:  The ending block of the hole
>> + *
>> + */
>> +static void ext4_ext_release_blocks(struct inode *inode, ext4_lblk_t start, ext4_lblk_t stop)
>>   {
>>         struct address_space *mapping = inode->i_mapping;
>>         struct super_block *sb = inode->i_sb;
>> -       ext4_lblk_t last_block;
>>         handle_t *handle;
>>         int err = 0;
>>
>> @@ -3670,9 +3901,7 @@ void ext4_ext_truncate(struct inode *inode)
>>         EXT4_I(inode)->i_disksize = inode->i_size;
>>         ext4_mark_inode_dirty(handle, inode);
>>
>> -       last_block = (inode->i_size + sb->s_blocksize - 1)
>> ->>  EXT4_BLOCK_SIZE_BITS(sb);
>> -       err = ext4_ext_remove_space(inode, last_block);
>> +       err = ext4_ext_remove_space(inode, start, stop);
>>
>>         /* In a multi-transaction truncate, we only make the final
>>          * transaction synchronous.
>> @@ -3698,6 +3927,24 @@ out_stop:
>>   }
>>
>>   /*
>> + * ext4_ext_truncate
>> + *
>> + * Truncate the file to the current i_size
>> + *
>> + * @inode: The file inode
>> + */
>> +void ext4_ext_truncate(struct inode *inode)
>> +{
>> +       struct super_block *sb = inode->i_sb;
>> +       ext4_lblk_t last_block;
>> +
>> +       last_block = (inode->i_size + sb->s_blocksize - 1)
>> +>>  EXT4_BLOCK_SIZE_BITS(sb);
>> +
>> +       ext4_ext_release_blocks(inode, last_block, EXT_MAX_BLOCK);
>> +
>> +}
>> +/*
>>   * ext4_ext_convert_blocks_uninit()
>>   * Converts a range of blocks to uninitialized
>>   *
>> --
>> 1.7.1
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
>> the body of a message to majordomo@...r.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
> 
> 
> 

Thx for the feed back :)

Allison Henderson

--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ