On 29.10.18 г. 14:21 ч., Nikolay Borisov wrote:
> 
> 
> On 29.10.18 г. 9:51 ч., Nikolay Borisov wrote:
>>
>>
>> On 29.10.18 г. 7:53 ч., Qu Wenruo wrote:
>>> [snip]
>>>>> The cause sounds valid, however would you please explain more about how
>>>>> such cleaning on unrelated delalloc range happens?
>>>>
>>>> So in my case the following happened - 2 block groups were created as
>>>> delalloc ranges in the - 0-1m and 1m-128m. Their respective pages were
>>>> dirtied, so when page 0 - 0-4k when into writepage_delalloc,
>>>> find_lock_delalloc_range would return the range 0-1m. So the call to
>>>> fill_delalloc instantiates OE 0-1m and writeback continues as expected.
>>>>
>>>> Now, when the 2nd page from range 0-1m is again set for writeback and
>>>> find_lock_delalloc_range is called with delalloc_start ==  4096 it will
>>>> actually return the range 1m-128m.
>>>
>>> IMHO this looks strange and may need extra investigation.
>>>
>>> Normally I would expect it returns the range 0~1M or 4K~1M.
>>
>> It cannot return 4k-1m since the writeback for the first page has
>> already dealt with this range. Also take a look in writepage_delalloc
>> how find_lock_delalloc_range is called : for 'start' it's passed the
>> page offset, calculated in __extent_writepage. And when
>> find_delalloc_range is called it just searches for an extent which ends
>> after passed start value. In find_delalloc_range  first    tree_search
>> is called which returns the 1m-128m range, then we go in the while(1)
>> loop on the first itertaion found is 0 so *end is populated with 128m ,
>> found is set to 1 and *start is set to 1m.
>>
>> On the second iteration the check  if (found && (state->start !=
>> cur_start || (state->state & EXTENT_BOUNDARY)))
>>
>> is triggered since the next extent found will have EXTENT_BOUNDARY since
>> it will be the next block group from relocation. EXTENT_BOUNDARY will be
>> set from relocate_file_extent_cluster' main loop:
>>
>>           if (nr < cluster->nr &&
>>
>>                     page_start + offset == cluster->boundary[nr]) {
>>
>>                         set_extent_bits(&BTRFS_I(inode)->io_tree,
>>
>>                                         page_start, page_end,
>>
>>                                         EXTENT_BOUNDARY);
>>
>>                         nr++;
>>
>>                 }
> 
> So it seems I was wrong w.r.t to sequence of events that result in the  extra 
> extent being returned. 
> Here is what I got after further investigation. First let's look at the 
> relocation side: 
> 
> 
> btrfs-4018  [001] ....   186.783244: relocate_file_extent_cluster: Setting 
> EXTENT_BOUNDARY for page: 0000000074cc47c4 page_offset: 0 end: 4095 <- first 
> page of range 0-1m
> btrfs-4018  [001] ....   186.783248: relocate_file_extent_cluster: Setting 
> DELALLOC for page: 0000000074cc47c4 page_offset: 0 block group:1104150528 
> btrfs-4018  [001] ....   186.783286: relocate_file_extent_cluster: Setting 
> DELALLOC for page: 000000004a28475a page_offset: 4096 block group:1104150528 
> <- 2nd page of range 0-1m 
> btrfs-4018  [001] ....   186.784855: relocate_file_extent_cluster: Setting 
> EXTENT_BOUNDARY for page: 00000000f58f50dc page_offset: 1048576 end: 1052671 
> < - 1st page of range 1m-128m
> 
> Mind the addresses of the given pages, they are all predicated on btrfs_ino 
> == 260, which is the ino for relocation inode. 
> 
> So the assumption is that when writing back page 000000004a28475a we cannot 
> really be processing range >1m since it will
> be outside of the range for the page, but this is not the case. Now on the 
> writeback side: 
> 
> kworker/u12:1-68    [002] ....   188.100471: find_lock_delalloc_range: 
> Processing delalloc range: 0 - 1048575 for page: 0000000074cc47c4 < - 
> writeback for first page of range 0-1m happens 
> so we naturally instantiate this range.
> 
> kworker/u12:1-68    [002] ...1   188.106523: 
> find_delalloc_range.constprop.25: 1213015261107184058: Got start: 1048576 end 
> 1052671 <- This is output from find_delalloc_range when start (the offset of 
> the passed page to find_lock_delalloc_range is 4096 i.e it's the 2nd page for 
> range 0-1m). So we find 1m - 1m + 4k on the first iteration of the loop in 
> find_delalloc_range, at this point *start = 1048576 and *end = 1052671 and 
> cached_state = the extent _state representing this first 4k range of the 
> larger 1m-128m range.
> 
> kworker/u12:1-68    [002] ...1   188.106526: 
> find_delalloc_range.constprop.25: 1213015261107184058: Got start: 1052672 end 
> 135266303 - We loop for the second time, this time we find the 1m+4k - 128m 
> range and actually trigger the (total_bytes >= max_bytes) check
> 
> kworker/u12:1-68    [002] ...1   188.106526: 
> find_delalloc_range.constprop.25: 1213015261107184058: returning from 
> total_bytes >= max_bytes
> 
> kworker/u12:1-68    [002] ....   188.106528: 
> find_delalloc_range.constprop.25: 1213015261107184058: Returning 
> cached_state->start: 1048576 cached_state->end: 1052671 *start = 1048576 *end 
> = 135266303 <--- this is what is returned from find_delalloc_range - 
> cached_state and *start and *end differ, since *end was set to 128m right 
> before we hit the total_bytes check. 
> 
> kworker/u12:1-68    [002] ....   188.106529: find_lock_delalloc_range: 
> Processing delalloc range: 1048576 - 135266303 for page: 000000004a28475a 
> <--- after we return from find_delalloc_range this is what 
> fin_lock_delalloc_range is processing - the next delalloc range 1m-128m but 
> the page passed is indeed the 2nd page for the previous range as evident from 
> the address 000000004a28475a
> kworker/u12:1-68    [002] ....   188.113870: run_delalloc_nocow: 
> btrfs_reloc_clone_csums err for OE[1048576 134217728] page->offset: 4096 end: 
> 8191 <--- here we just create the OE in run_delalloc_nocow. 
> 
> The only thing which I'm now struggling to rationalize is why 
> find_delalloc_range finds an extent_state in the range 1048576-1052671 and 
> then finds another range 1052672 - 135266303, shouldn't in fact it 
> find just 1048576 - 135266303. Perhaps it's due to the search being performed 
> in the io_extent tree and not the extent_tree. 

And the explanation: 

btrfs-3230  [004] ...1    74.499205: merge_state: PREV: Didn't merge 
state[1052672-1056767 state: 36] with other[1048576-1052671 state: 548]
btrfs-3230  [004] ...1    74.499205: merge_state: NEXT: Didn't merge 
state[1052672-1056767 state: 36] with other[1056768-4128767 state: 4]

36 is EXTENT_UPTODATE|EXTENT_DELALLOC and 548 is 
EXTENT_UPTODATE|EXTENT_DELALLOC|EXTENT_BOUNDARY 
set by the relocation code. Now I'm convinced that the problem is really that 
find_delalloc_range only guarantees
to return a delalloc extent that ends after *start so returning one which is 
outside of our range is a valid execution.  

<SNIP>
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> 
> <snip>
> 

Reply via email to