On Fri, Aug 27, 2021 at 03:58:13PM +0100, Joao Martins wrote:
> #if defined(CONFIG_ARCH_HAS_PTE_DEVMAP) &&
> defined(CONFIG_TRANSPARENT_HUGEPAGE)
> static int __gup_device_huge(unsigned long pfn, unsigned long addr,
> unsigned long end, unsigned int flags,
> struct page **pages, int *nr)
> {
> - int nr_start = *nr;
> + int refs, nr_start = *nr;
> struct dev_pagemap *pgmap = NULL;
> int ret = 1;
>
> do {
> - struct page *page = pfn_to_page(pfn);
> + struct page *head, *page = pfn_to_page(pfn);
> + unsigned long next = addr + PAGE_SIZE;
>
> pgmap = get_dev_pagemap(pfn, pgmap);
> if (unlikely(!pgmap)) {
> @@ -2252,16 +2265,25 @@ static int __gup_device_huge(unsigned long pfn,
> unsigned long addr,
> ret = 0;
> break;
> }
> - SetPageReferenced(page);
> - pages[*nr] = page;
> - if (unlikely(!try_grab_page(page, flags))) {
> - undo_dev_pagemap(nr, nr_start, flags, pages);
> +
> + head = compound_head(page);
> + /* @end is assumed to be limited at most one compound page */
> + if (PageHead(head))
> + next = end;
> + refs = record_subpages(page, addr, next, pages + *nr);
> +
> + SetPageReferenced(head);
> + if (unlikely(!try_grab_compound_head(head, refs, flags))) {
> + if (PageHead(head))
> + ClearPageReferenced(head);
> + else
> + undo_dev_pagemap(nr, nr_start, flags, pages);
> ret = 0;
> break;
Why is this special cased for devmap?
Shouldn't everything processing pud/pmds/etc use the same basic loop
that is similar in idea to the 'for_each_compound_head' scheme in
unpin_user_pages_dirty_lock()?
Doesn't that work for all the special page type cases here?
Jason