Re: RFC for new feature to move pages from one vma to another without split

From: David Hildenbrand
Date: Thu Apr 13 2023 - 04:11:38 EST


On 12.04.23 17:58, Peter Xu wrote:
On Wed, Apr 12, 2023 at 10:47:52AM +0200, David Hildenbrand wrote:
Personally it was always a mistery to me on how vm_pgoff works with
anonymous vmas and why it needs to be setup with vm_start >> PAGE_SHIFT.

Just now I tried to apply below oneliner change:

@@ -1369,7 +1369,7 @@ unsigned long do_mmap(struct file *file, unsigned long addr,
/*
* Set pgoff according to addr for anon_vma.
*/
- pgoff = addr >> PAGE_SHIFT;
+ pgoff = 0;
break;
default:
return -EINVAL;

The kernel even boots without a major problem so far..

I think it's for RMAP purposes.

Take a look at linear_page_index() and how it's, for example, used in
ksm_might_need_to_copy() alongside page->index.

From what I read, the vma's vm_pgoff is set before setup any page->index
within the vma, while the latter will be calculated out of the vma pgoff
with linear_page_index() (in __page_set_anon_rmap()).

folio->index = linear_page_index(vma, address);

I think I missed something, but it seems to me any comparisions between
page->index and linear_page_index() will just keep working for anonymous
even if we change vma pgoff to 0 when vma is mapped.

Do you perhaps mean this is needed for ksm only? I really am not familiar
enough with ksm, especially when it's swapped out. I do see that
ksm_might_need_to_copy() wants to avoid reusing a page if anon_vma is setup
not for current vma, but I don't know when it'll happen.

if (PageKsm(page)) {
if (page_stable_node(page) &&
!(ksm_run & KSM_RUN_UNMERGE))
return page; /* no need to copy it */
} else if (!anon_vma) {
return page; /* no need to copy it */
} else if (page->index == linear_page_index(vma, address) &&
anon_vma->root == vma->anon_vma->root) {
return page; /* still no need to copy it */
}

I think when all these paths don't trigger (aka, we need to copy) it means
there's anon_vma assigned to the page but not the right one (even though I
don't know how that could happen..). Meanwhile I don't see either on how
vma pg_off affects this (and I assume a real KSM page ignores page->index
completely).

I think you are right with folio->index = linear_page_index(vma, address).

I did not check the code yet, but thinking about it I figured out why we want to set pgoff to the start of the VMA in the address space for anonymous memory:

For RMAP and friends (relying on linear_page_index), folio->index has to match the index within the VMA. If would set pgoff to something else, we'd have less VMA merging opportunities. So your system might work, but you'd end up with many anon VMAs.


Imagine the following:

[ anon0 ][ fd ][ anon1 ]

Unmap the fd:

[ anon0 ][ hole ][ anon1 ]

Mmap anon:

[ anon0 ][ anon2 ][ anon1 ]


We can now merge all 3 VMAs into one, even if the first and latter already map pages.


A simpler and more common example is probably:

[ anon0 ]

Mmmap anon1 before the existing one

[ anon1 ][ anon0 ]

Which we can merge into a single one.



Mapping after an existing one could work, but one would have to carefully set pgoff based on the size of the previous anon VMA ... which is more complicated

So instead, we consider the whole address space as a virtual, anon file, starting at offset 0. The pgoff of a VMA is then simply the offset in that virtual file (easily computed from the start of the VMA), and VMA merging is just the same as for an ordinary file.

--
Thanks,

David / dhildenb