Summary
Linux's (v6.0) documentation for struct folio claims that
It may be mapped into userspace at an address which is at an arbitrary page offset, ...
However, it does not seem to be possible to correctly maintain rmap for pages in the folio unless used as a transparent hugepage (THP), which implies that the userspace address is also aligned to the THP size. Is there a correct way to maintain rmap for folios which are not used for THP?
Detailed explanation
A folio is a physically, virtually and logically contiguous set of bytes with a power-of-two size (kernel doc). The struct folio is the head of a compound page. As per this LWN article, the use of folios targets a particular issue, separating APIs which work on the head page of a compound page from those which work with all pages. Hugepages are one motivating usecase.
For example, consider a folio of order 2, with physical pages (pfn, pfn+1, pfn+2, pfn+3). This folio will be aligned to a 4-page boundary in physical address (pfn & 0x3 == 0), and in kernel virtual addresses.
As per the doc, the kernel allows a folio to be mapped at unaligned userspace virtual address (vpn, vpn+1, vpn+2, vpn+3 where vfn & 0x3 != 0). This also implies that the use of a folio is not exclusively for THPs. Of course, when mapping pfn at vpn, I would also like to correctly maintain a rmap. In my use case, the folio is not a THP, and not the correct order for either a 2MB or 1GB hugepage.
However, the current rmap code seems to only work if folios are used for THPs. For example, page_add_new_rmap contains the following code:
void page_add_new_anon_rmap(struct page *page,
struct vm_area_struct *vma, unsigned long address)
{
const bool compound = PageCompound(page);
int nr = compound ? thp_nr_pages(page) : 1;
if (compound) {
VM_BUG_ON_PAGE(!PageTransHuge(page), page);
....
}
}
Questions
- Is the current Linux implementation of
folioandrmaponly for THPs - Is there a "correct" way to map a folio while also maintaining the
rmap?