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

Reply via email to