[Ocfs2-tools-devel] [PATCH 1/1] Add truncate for "clear sparse" function in tunefs,

Mark Fasheh mark.fasheh at oracle.com
Tue Nov 13 11:26:11 PST 2007


This patch fails the following scenario:

$ ./reserve_space foo resv 0 0 $[10*1024*1024]File:
foo
cmd = foo
l_whence = 0
l_start = 0
l_len = 10485760

$ ./truncate foo 65536
Truncating foo to 65536

[reserve_space and truncate are taken from ocfs2-test]

$ debugfs.ocfs2 /dev/sde2
debugfs: stat foo
        Inode: 72890   Mode: 0644   Generation: 4289956910 (0xffb38c2e)
        FS Generation: 2776784650 (0xa5825f0a)
        Type: Regular   Attr: 0x0   Flags: Valid 
        User: 0 (root)   Group: 0 (root)   Size: 65536
        Links: 1   Clusters: 2560
        ctime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
        atime: 0x4739f671 -- Wed Dec 31 16:00:00 1969
        mtime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
        dtime: 0x0 -- Wed Dec 31 16:00:00 1969
        ctime_nsec: 0x3897a5e6 -- 949462502
        atime_nsec: 0x010a910e -- 17469710
        mtime_nsec: 0x3897a5e6 -- 949462502
        Last Extblk: 0
        Sub Alloc Slot: 0   Sub Alloc Bit: 185
        Tree Depth: 0   Count: 243   Next Free Rec: 1
        ## Offset        Clusters       Block#          Flags
        0  0             2560           96769           0x0

$ tunefs.ocfs2 --fs-features=nounwritten /dev/sde2
tunefs.ocfs2 1.4.0
We have 9688495 clusters free and need 0 clusters for sparse files, 0
clusters for more extent blocks and will need to clear 0 clusters of
unwritten extents.
Modify feature "nounwritten" for the volume
Proceed (y/N): y
Wrote Superblock

$ debugfs.ocfs2 /dev/sde2debugfs.ocfs2 1.4.0
debugfs: stat foo
        Inode: 72890   Mode: 0644   Generation: 4289956910 (0xffb38c2e)
        FS Generation: 2776784650 (0xa5825f0a)
        Type: Regular   Attr: 0x0   Flags: Valid 
        User: 0 (root)   Group: 0 (root)   Size: 65536
        Links: 1   Clusters: 2560
        ctime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
        atime: 0x4739f671 -- Wed Dec 31 16:00:00 1969
        mtime: 0x4739f672 -- Wed Dec 31 16:00:00 1969
        dtime: 0x0 -- Wed Dec 31 16:00:00 1969
        ctime_nsec: 0x3897a5e6 -- 949462502
        atime_nsec: 0x010a910e -- 17469710
        mtime_nsec: 0x3897a5e6 -- 949462502
        Last Extblk: 0
        Sub Alloc Slot: 0   Sub Alloc Bit: 185
        Tree Depth: 0   Count: 243   Next Free Rec: 1
        ## Offset        Clusters       Block#          Flags
        0  0             2560           96769           0x0

So, the existing unwritten extents code zero's the entire extent because
it's straddling i_size. Otherwise, the file isn't getting truncate which is
not what I think you expected to happen.

I found the problem, it's noted below...


On Tue, Nov 13, 2007 at 04:41:26PM +0800, tao.ma wrote:
> take 2
> 
> Modification from V1 to V2:
> Move truncate process to the end of operation.
> We may need to truncate an unwritten extent sometime. So if we truncate the file
> first, the unwritten extent information stored in clear_ctxt may be outdated.
> So move it to the end.
> 
> Signed-off-by: Tao Ma <tao.ma at oracle.com>
> ---
>  tunefs.ocfs2/sparse_file.c |   65 +++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 58 insertions(+), 7 deletions(-)
> 
> diff --git a/tunefs.ocfs2/sparse_file.c b/tunefs.ocfs2/sparse_file.c
> index 8ef6710..06782f6 100644
> --- a/tunefs.ocfs2/sparse_file.c
> +++ b/tunefs.ocfs2/sparse_file.c
> @@ -67,10 +67,14 @@ struct unwritten_list {
>   * unwritten_list. Since filling up a hole may need a new extent record and
>   * lead to some new extent block, the total hole number in the sparse file
>   * will also be recorded.
> + *
> + * Some sparse file may also have some clusters which exceed the limit of
> + * i_size, and they should be truncated.
>   */
>  struct sparse_file {
>  	uint64_t blkno;
>  	uint32_t holes_num;
> +	int truncate;
>  	struct hole_list *holes;
>  	struct unwritten_list *unwritten;
>  	struct sparse_file *next;
> @@ -208,6 +212,7 @@ static void list_sparse_iterate(void *priv_data,
>   * Iterate a file.
>   * Call "func" when we meet with a hole.
>   * Call "unwritten_func" when we meet with unwritten clusters.
> + * Call "seen_exceed" when we see some clusters exceed i_size.
>   */
>  static errcode_t iterate_file(ocfs2_filesys *fs,
>  			      struct ocfs2_dinode *di,
> @@ -218,10 +223,12 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
>  						     uint32_t start,
>  						     uint32_t len,
>  						     uint64_t p_start),
> +			      void (*seen_exceed)(void *priv_data),
>  			      void *priv_data)
>  {
>  	errcode_t ret;
>  	uint32_t clusters, v_cluster = 0, p_cluster, num_clusters;
> +	uint32_t get_clusters = 0;
>  	uint64_t p_blkno;
>  	uint16_t extent_flags;
>  	ocfs2_cached_inode *ci = NULL;
> @@ -250,7 +257,8 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
>  
>  			if (func)
>  				func(priv_data, v_cluster, num_clusters);
> -		}
> +		} else
> +			get_clusters += num_clusters;
>  
>  		if ((extent_flags & OCFS2_EXT_UNWRITTEN) && unwritten_func) {
>  			p_blkno = ocfs2_clusters_to_blocks(fs, p_cluster);
> @@ -261,6 +269,17 @@ static errcode_t iterate_file(ocfs2_filesys *fs,
>  		v_cluster += num_clusters;
>  	}
>  
> +	/*
> +	 * If there are some extra clusters we need to record them.
> +	 * There are 2 scenarios:
> +	 * 1. there are more cotinguous clusters allocated in which case
> +	 *    get_clusters > di->i_clusters
> +	 * 2. there are more clusters allocated after i_size in which case
> +	 *    get_clusters < di->i_clusters
> +	 */
> +	if (get_clusters != di->i_clusters && seen_exceed)
> +		seen_exceed(priv_data);

This needs to compare against 'clusters' (as computed above in that
function), not 'i_clusters'. i_clusters will always equal the total number
of clusters in the inode, irregardless of i_size, so you won't hit this in
the case that the last extent includes i_size, but goes too far.
	--Mark

--
Mark Fasheh
Senior Software Developer, Oracle
mark.fasheh at oracle.com



More information about the Ocfs2-tools-devel mailing list