Right, but you know from the first loop which order is applicable (and will be
fed to the second loop) and could just pte_unmap(pte) + tryalloc. If that fails,
remap and try with the next orders.
You mean something like this?
pte = pte_offset_map(vmf->pmd, vmf->address & PMD_MASK);
if (!pte)
return ERR_PTR(-EAGAIN);
order = highest_order(orders);
while (orders) {
addr = ALIGN_DOWN(vmf->address, PAGE_SIZE << order);
if (!pte_range_none(pte + pte_index(addr), 1 << order)) {
order = next_order(&orders, order);
continue;
}
pte_unmap(pte);
folio = vma_alloc_folio(gfp, order, vma, addr, true);
if (folio) {
clear_huge_page(&folio->page, vmf->address, 1 << order);
return folio;
}
pte = pte_offset_map(vmf->pmd, vmf->address & PMD_MASK);
if (!pte)
return ERR_PTR(-EAGAIN);
order = next_order(&orders, order);
}
pte_unmap(pte);
I don't really like that because if high order folio allocations fail, then you
are calling pte_range_none() again for the next lower order; once that check has
succeeded for an order it shouldn't be required for any lower orders. In this
case you also have lots of pte map/unmap.
Yes it is. Adding in some comments might help, like
The original version feels more efficient to me.
That would make the code certainly easier to understand. That "orders" magic of
constructing, filtering, walking is confusing :)
I might find some time today to see if there is an easy way to cleanup all what
I spelled out above. It really is a mess. But likely that cleanup could be
deferred (but you're touching it, so ... :) ).
I'm going to ignore the last 5 words. I heard the "that cleanup could be
deferred" part loud and clear though :)