Re: Question about e2fsprogs/e4defrag

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi,

On 07/17/2014 03:22 AM, Darrick J. Wong wrote:
> On Wed, Jul 16, 2014 at 12:16:37PM +0800, Xiaoguang Wang wrote:
>> Hi,
>>
>> When I run xfstests/tests/generic/018 for ext4 file system in RHEL7.0GA,
>> sometimes it fails and sometime it succeeds. After looking into this case, I
>> think it's not a kernel ext4 bug, it maybe an e4dfrag bug. I compiled the
>> newest e2fsprogs to have test, it seems this issue still exits, so I still
>> send a mail to this list to look for some help, thanks.
>>
>> The issue is that sometimes e4defrag does not defrag file correctly.
>> Steps to reproduce this issue:
>> 1. cd mntpoint
>> 2. rm -f lege
>> 3. for I in `seq 9 -1 0`;
>>        do dd if=/dev/zero of=lege bs=4k count=1 conv=notrunc seek=$I oflag=sync &>/dev/null;
>>    done;
>> 4. e4defrag -c -v lege
>>
>> Repeatedly execute the 2, 3, 4 steps until you get a file which have the similar extent layout like below:
>> ################################################################
>> [root@localhost test_e2fsprogs]# e4defrag -c -v lege
>> <File>
>> [ext 1]:        start 49365571: logical 0:      len 1
>> [ext 2]:        start 49365570: logical 1:      len 1
>> [ext 3]:        start 49365569: logical 2:      len 1
>> [ext 4]:        start 49365568: logical 3:      len 1
>> [ext 5]:        start 49365567: logical 4:      len 1
>> [ext 6]:        start 49365566: logical 5:      len 1
>> [ext 7]:        start 49365565: logical 6:      len 1
>> [ext 8]:        start 49365564: logical 7:      len 1
>> [ext 9]:        start 49365563: logical 8:      len 1
>> [ext 10]:       start 49365562: logical 9:      len 1
>>
>>  Total/best extents                             10/1
>>  Average size per extent                        4 KB
>>  Fragmentation score                            98
>>  [0-30 no problem: 31-55 a little bit fragmented: 56- needs defrag]
>>  This file (lege) needs defragmentation.
>>  Done.
>> ################################################################
>> The physical blocks are continuous but reversed.
>>
>> If we call e4defrag against this file, the output would be:
>> ################################################################
>> [root@localhost test_e2fsprogs]# /tmp/e4defrag -v lege 
>> ext4 defragmentation for lege
>> [1/1]lege:      100%  extents: 10 -> 10 [ OK ]
>>  Success:                       [1/1]
>> [root@localhost test_e2fsprogs]# /tmp/e4defrag -v -c lege 
>> <File>
>> [ext 1]:        start 49365571: logical 0:      len 1
>> [ext 2]:        start 49365570: logical 1:      len 1
>> [ext 3]:        start 49365569: logical 2:      len 1
>> [ext 4]:        start 49365568: logical 3:      len 1
>> [ext 5]:        start 49365567: logical 4:      len 1
>> [ext 6]:        start 49365566: logical 5:      len 1
>> [ext 7]:        start 49365565: logical 6:      len 1
>> [ext 8]:        start 49365564: logical 7:      len 1
>> [ext 9]:        start 49365563: logical 8:      len 1
>> [ext 10]:       start 49365562: logical 9:      len 1
>>
>>  Total/best extents                             10/1
>>  Average size per extent                        4 KB
>>  Fragmentation score                            98
>>  [0-30 no problem: 31-55 a little bit fragmented: 56- needs defrag]
>>  This file (lege) needs defragmentation.
>>  Done.
>> ################################################################
>> According to my understanding, this file is not defraged correctly and should
>> be convert into one extent.  Or because if the physical blocks are continuous
>> though reversed, we do not need to do defragment?
> 
> Oh, I think we /do/ need to defragment.  Granted, file readahead might paper
> over the symptoms, but since the user explicitly ran e4defrag we can try
> to do better.

Yeah, agree.
> 
>> I have checked the e4defrag source code, whether to do real defragment
>> depends on some conditions, please
>> see this code(e4defrag.c).
>> --main
>>   --file_defrag
>>     
>> In file_defrag(), there is such a judgement:
>> "if (file_frags_start <= best || orig_physical_cnt <= donor_physical_cnt)", If this returns true, the e4defrag will
>> not call call_defrag() to do real defragment work.
>>
>> Here file_frags_start: number of file fragments before defrag
>>      orig_physical_cnt: number of original file's continuous physical region
>>      donor_physical_cnt: number of donor file's continuous physical region
>>
>> In this "lege" file, the orig_physical_cnt is 1, and donor_physical_cnt is also 1, so the "if" is satisfied and
>> call_defrag() won't be called.
> 
> This is a curious corner case of e4defrag -- if you look in get_file_extents(),
> the list of extents is insertion-sorted by physical block, which means that
> get_physical_count() (stupidly) looks only for gaps in the runs of physical
> blocks.  Therefore, e4defrag thinks that this "lege" file has one physical
> extent.  Ignoring logical block ordering, this is true, but as you point out,
> this leaves the "file written backwards" case in a fragmented state.  So let's
> not ignore the logical block ordering:
> 
> What I think we really need to do here is make get_physical_count() smarter --
> if there's a gap either in the physical or logical offsets of extents, then we
> need to increment *_physical_cnt so that we later decide to defragment the
> file.
> 
> (Please keep reading)
I checked the code again, you are right, thanks for your explanation
 
> 
>> Here I'd like to know the comparison "orig_physical_cnt <=
>> donor_physical_cnt" is useful? According to my understanding, what should we
>> have comparison are number of extents or average extent size.
>>
>> When I have this change:
>> diff --git a/misc/e4defrag.c b/misc/e4defrag.c
>> index a204793..cd95698 100644
>> --- a/misc/e4defrag.c
>> +++ b/misc/e4defrag.c
>> @@ -1598,8 +1598,7 @@ check_improvement:
>>                 extents_before_defrag += file_frags_start;
>>         }
>>  
>> -       if (file_frags_start <= best ||
>> -                       orig_physical_cnt <= donor_physical_cnt) {
>> +       if (file_frags_start <= best) { 
> 
> This is incorrect, since the point of the "orig_physical_cnt <=
> donor_physical_cnt" check is to ensure that we don't increase the fragmentation
> of a file by swapping it with pieces from a donor file whose contents are
> spread out over a larger number of runs of physical blocks.

Ah, I see. I hadn't realized that, thanks.
> 
> (It does, however, force defragmentation for all files, so you get the results
> you wanted.)
> 
> Please try the patch at the end of this message on for size.  It fixes things
> on my test VM; does it fix yours?

Yeah, it works, thanks.
Would you send a new version patch to fix this issue, or should I do it?

Regards,
Xiaoguang Wang
> 
> --D
> 
>>                 printf("\033[79;0H\033[K[%u/%u]%s:\t%3d%%",
>>                         defraged_file_count, total_count, file, 100);
>>                 if (mode_flag & DETAIL)
>>
>> Then the "lege" file could be defraged correctly.
>> ##################################################################
>> [root@localhost test_e2fsprogs]# /tmp/e4defrag -v  lege
>> ext4 defragmentation for lege
>> [1/1]lege:      100%  extents: 10 -> 1  [ OK ]
>>  Success:                       [1/1]
>> [root@localhost test_e2fsprogs]# /tmp/e4defrag -v -c lege
>> <File>
>> [ext 1]:        start 49366583: logical 0:      len 10
>>
>>  Total/best extents                             1/1
>>  Average size per extent                        40 KB
>>  Fragmentation score                            0
>>  [0-30 no problem: 31-55 a little bit fragmented: 56- needs defrag]
>>  This file (lege) does not need defragmentation.
>>  Done.
>> ##################################################################
>>
>> Any opinion or suggestions will be appreciated!
>> If I'm wrong, please correct me, thanks!
>>
>> Regards,
>> Xiaoguang Wang
> 
> diff --git a/misc/e4defrag.c b/misc/e4defrag.c
> index a204793..d0eac60 100644
> --- a/misc/e4defrag.c
> +++ b/misc/e4defrag.c
> @@ -888,7 +888,9 @@ static int get_physical_count(struct fiemap_extent_list *physical_list_head)
>  
>  	do {
>  		if ((ext_list_tmp->data.physical + ext_list_tmp->data.len)
> -				!= ext_list_tmp->next->data.physical) {
> +				!= ext_list_tmp->next->data.physical ||
> +		    (ext_list_tmp->data.logical + ext_list_tmp->data.len)
> +				!= ext_list_tmp->next->data.logical) {
>  			/* This extent and next extent are not continuous. */
>  			ret++;
>  		}
> .
> 

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




[Index of Archives]     [Reiser Filesystem Development]     [Ceph FS]     [Kernel Newbies]     [Security]     [Netfilter]     [Bugtraq]     [Linux FS]     [Yosemite National Park]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Device Mapper]     [Linux Media]

  Powered by Linux