Milos Nikic, le ven. 09 oct. 2026 22:36:05 -0700, a ecrit:
> trunc_indirect took END - OFFSET as the index of the first entry to
> free at every level of indirection.  That is right for a single
> indirect block only; an entry of a double (triple) indirect block
> covers addr_per_block (addr_per_block^2) blocks.  A truncation to a
> size inside those ranges thus started at the wrong entry or freed
> nothing, leaving the blocks past the new end allocated.  A file that
> later grows over them gets their old contents back instead of zeros.
> 
> Steps to reproduce (with or without the journal):
> 
>   sudo settrans -ac /mnt/stress /hurd/ext2fs.static  /dev/sd0
> 
>   sudo dd if=/dev/urandom of=/mnt/stress/f bs=1M count=7
>   sudo truncate -s 6000000 /mnt/stress/f
>   sudo settrans -ga /mnt/stress && sudo /sbin/fsck.ext2 -fn /dev/sd0
>     Inode 16996, i_size is 6000000, should be 7340032.  Fix? no

Ah, thanks! I indeed had already seen such messages from times to times,
without gathering the time to investigate :)

Samuel

> ---
>  ext2fs/truncate.c | 22 +++++++++++++---------
>  1 file changed, 13 insertions(+), 9 deletions(-)
> 
> diff --git a/ext2fs/truncate.c b/ext2fs/truncate.c
> index 837fd02c3..082947d32 100644
> --- a/ext2fs/truncate.c
> +++ b/ext2fs/truncate.c
> @@ -111,13 +111,14 @@ trunc_direct (struct node *node, block_t end, struct 
> free_block_run *fbr)
>  
>  /* Free any blocks in NODE greater than or equal to END that are rooted in
>     the indirect block *P; OFFSET should be the block position that *P
> -   corresponds to.  For each block pointer in *P that should be freed,
> -   FREE_BLOCK is called with a pointer to the entry for that block, and the
> -   index of the entry within *P.  If every block in *P is freed, then *P is
> -   set to 0, otherwise it is left alone.  */
> +   corresponds to, and SPAN the number of file blocks each entry of *P
> +   covers (1 for a single indirect block).  For each block pointer in *P
> +   that should be freed, FREE_BLOCK is called with a pointer to the entry
> +   for that block, and the index of the entry within *P.  If every block in
> +   *P is freed, then *P is set to 0, otherwise it is left alone.  */
>  static void
>  trunc_indirect (struct node *node, block_t end,
> -             block_t *p, block_t offset,
> +             block_t *p, block_t offset, block_t span,
>               void (*free_block)(block_t *p, unsigned index),
>               struct free_block_run *fbr)
>  {
> @@ -128,7 +129,9 @@ trunc_indirect (struct node *node, block_t end,
>        unsigned index;
>        int modified = 0, all_freed = 1;
>        block_t *ind_bh = (block_t *) disk_cache_block_ref (*p);
> -      unsigned first = end < offset ? 0 : end - offset;
> +      /* The entry that holds END: it is truncated in part, and the ones
> +      after it are freed.  */
> +      unsigned first = end < offset ? 0 : (end - offset) / span;
>  
>        for (index = first; index < addr_per_block; index++)
>       if (ind_bh[index])
> @@ -177,7 +180,7 @@ trunc_single_indirect (struct node *node, block_t end,
>      {
>        free_block_run_free_ptr (fbr, p);
>      }
> -  trunc_indirect (node, end, p, offset, free_block, fbr);
> +  trunc_indirect (node, end, p, offset, 1, free_block, fbr);
>  }
>  
>  static void
> @@ -190,7 +193,7 @@ trunc_double_indirect (struct node *node, block_t end,
>        block_t entry_offs = offset + (index * addr_per_block);
>        trunc_single_indirect (node, end, p, entry_offs, fbr);
>      }
> -  trunc_indirect (node, end, p, offset, free_block, fbr);
> +  trunc_indirect (node, end, p, offset, addr_per_block, free_block, fbr);
>  }
>  
>  static void
> @@ -203,7 +206,8 @@ trunc_triple_indirect (struct node *node, block_t end,
>        block_t entry_offs = offset + (index * addr_per_block * 
> addr_per_block);
>        trunc_double_indirect (node, end, p, entry_offs, fbr);
>      }
> -  trunc_indirect (node, end, p, offset, free_block, fbr);
> +  trunc_indirect (node, end, p, offset, addr_per_block * addr_per_block,
> +               free_block, fbr);
>  }
>  
>  /* ---------------------------------------------------------------- */
> -- 
> 2.56.0
> 

-- 
Samuel
<c> tiens, je suis déçu
<c> quand on clique sur le bouton random de http://xkcd.com/221/ on ne tombe 
pas (toujours) sur http://xkcd.com/4/
<c> bon, j'envoie un bug-report à l'auteur

Reply via email to