Hi Xiaogang,
thanks for sending this.
The last + 1 change to last_align_down matches the reproduced split-tail
failure and fixes the inclusive-last issue there. I think the head-side
condition still uses the inclusive end of the generated head range in
places where the exclusive split boundary is needed.
In svm_range_split_head() the call is:
r = svm_range_split(prange, new_start, prange->last, &head);
This is case 2 in svm_range_split(): the generated range is
[old_start, new_start - 1], where old_start is the original prange start.
So for the head range:
head->last + 1 == new_start
and new_start is the split boundary that should be checked for 2MB
alignment. That would make the head-side condition:
if (huge_page_mapping && new_start > start_align &&
new_start < last_align_down && !IS_ALIGNED(new_start, 512))
list_add(&head->update_list, remap_list);
With an original page range [0, 1023], start_align is 0 and
last_align_down is 1024 after the last + 1 change.
For new_start = 512, the generated head is [0, 511]. The split boundary
is 512-page aligned, so this condition should not add the head to
remap_list, but checking !IS_ALIGNED(head->last, 512) checks 511 and
evaluates true.
For new_start = 513, the generated head is [0, 512]. The split boundary
is not 512-page aligned, so this condition should add the head to
remap_list, but checking !IS_ALIGNED(head->last, 512) checks 512 and
evaluates false.
This is the head-side issue Philip pointed out in the review of the
original change:
https://lore.kernel.org/all/[email protected]/
I posted a v2 that keeps your tail-side last + 1 fix and uses new_start
for the head-side split-boundary checks:
https://lore.kernel.org/all/[email protected]/
Thanks,
Gerhard