This patch series add support for migrating compound pages if we find them in the
CMA area before taking long term page reference for VFIO.
Testing:
* TODO: test with hugetlb backed guest ram.
* Testing done with a code change as below
- if (is_migrate_cma_page(pages[i]) && migrate_allow) {
+ if (migrate_allow) {
...
+ migrate_allow = false;
Aneesh Kumar K.V (3):
mm: Export alloc_migrate_huge_page
powerpc/mm/iommu: Allow large IOMMU page size only for hugetlb backing
powerpc/mm/iommu: Allow migration of cma allocated pages during
mm_iommu_get
arch/powerpc/mm/mmu_context_iommu.c | 209 +++++++++++++++++-----------
include/linux/hugetlb.h | 2 +
mm/hugetlb.c | 4 +-
3 files changed, 128 insertions(+), 87 deletions(-)
--
2.17.1
Current code doesn't do page migration if the page allocated is a compound page.
With HugeTLB migration support, we can end up allocating hugetlb pages from
CMA region. Also THP pages can be allocated from CMA region. This patch updates
the code to handle compound pages correctly.
This add a new helper get_user_pages_cma_migrate. It does one get_user_pages
with right count, instead of doing one get_user_pages per page. That avoids
reading page table multiple times. The helper could possibly used by other
subystem if we have more users.
The patch also convert the hpas member of mm_iommu_table_group_mem_t to a union.
We use the same storage location to store pointers to struct page. We cannot
update alll the code path use struct page *, because we access hpas in real mode
and we can't do that struct page * to pfn conversion in real mode.
Signed-off-by: Aneesh Kumar K.V <redacted>
---
arch/powerpc/mm/mmu_context_iommu.c | 195 ++++++++++++++++++----------
1 file changed, 123 insertions(+), 72 deletions(-)
@@ -30,8 +31,18 @@ struct mm_iommu_table_group_mem_t {atomic64_tmapped;unsignedintpageshift;u64ua;/* userspace address */-u64entries;/* number of entries in hpas[] */-u64*hpas;/* vmalloc'ed */+u64entries;/* number of entries in hpages[] */+/*+*inmm_iommu_getwetemporarilyusethistostore+*structpageaddress.+*+*Weneedtoconvertuatohpainrealmode.Makeit+*simplerbystoringphysicalladdress.+*/+union{+structpage**hpages;/* vmalloc'ed */+phys_addr_t*hpas;+};};staticlongmm_iommu_adjust_locked_vm(structmm_struct*mm,
@@ -75,62 +86,112 @@ bool mm_iommu_preregistered(struct mm_struct *mm)EXPORT_SYMBOL_GPL(mm_iommu_preregistered);/*-*Takenfromalloc_migrate_targetwithchangestoremoveCMAallocations+*Takenfromalloc_migrate_target/alloc_migrate_huge_pagewithchangestoremove+*CMAallocations+*Isthistherightallocatorforhugetlb?*/structpage*new_iommu_non_cma_page(structpage*page,unsignedlongprivate){-gfp_tgfp_mask=GFP_USER;-structpage*new_page;+/* is this the right nid? */+intnid=numa_mem_id();+gfp_tgfp_mask=GFP_HIGHUSER;-if(PageCompound(page))-returnNULL;+if(PageHuge(page)){-if(PageHighMem(page))-gfp_mask|=__GFP_HIGHMEM;+structhstate*h=page_hstate(page);+/*+*Wedon'twanttodequeuefromthepoolbecausepoolpageswill+*mostlybefromtheCMAregion.+*/+returnalloc_migrate_huge_page(h,gfp_mask,nid,NULL);-/*-*Wedon'twanttheallocationtoforceanOOMifpossibe-*/-new_page=alloc_page(gfp_mask|__GFP_NORETRY|__GFP_NOWARN);-returnnew_page;+}elseif(PageTransHuge(page)){+structpage*thp;+gfp_tthp_gfpmask=GFP_TRANSHUGE&~__GFP_MOVABLE;++thp=__alloc_pages_node(nid,thp_gfpmask,HPAGE_PMD_ORDER);+if(!thp)+returnNULL;+prep_transhuge_page(thp);+returnthp;+}+return__alloc_pages_node(nid,gfp_mask,0);}-staticintmm_iommu_move_page_from_cma(structpage*page)+intget_user_pages_cma_migrate(unsignedlongstart,intnr_pages,intwrite,+structpage**pages){-intret=0;-LIST_HEAD(cma_migrate_pages);--/* Ignore huge pages for now */-if(PageCompound(page))-return-EBUSY;--lru_add_drain();-ret=isolate_lru_page(page);-if(ret)+inti,ret;+booldrain_allow=true;+boolmigrate_allow=true;+LIST_HEAD(cma_page_list);++get_user_again:+ret=get_user_pages_fast(start,nr_pages,write,pages);+if(ret<=0)returnret;-list_add(&page->lru,&cma_migrate_pages);-put_page(page);/* Drop the gup reference */--ret=migrate_pages(&cma_migrate_pages,new_iommu_non_cma_page,-NULL,0,MIGRATE_SYNC,MR_CONTIG_RANGE);-if(ret){-if(!list_empty(&cma_migrate_pages))-putback_movable_pages(&cma_migrate_pages);+for(i=0;i<ret;++i){+/*+*IfwegetapagefromtheCMAzone,sincewearegoingto+*bepinningtheseentries,wemightaswellmovethemout+*oftheCMAzoneifpossible.+*/+if(is_migrate_cma_page(pages[i])&&migrate_allow){+if(PageHuge(pages[i]))+isolate_huge_page(pages[i],&cma_page_list);+else{+structpage*head=compound_head(pages[i]);++if(!PageLRU(head)&&drain_allow){+lru_add_drain_all();+drain_allow=false;+}++if(!isolate_lru_page(head)){+list_add_tail(&head->lru,&cma_page_list);+mod_node_page_state(page_pgdat(head),+NR_ISOLATED_ANON++page_is_file_cache(head),+hpage_nr_pages(head));+}+}+}}--return0;+if(!list_empty(&cma_page_list)){+/*+*droptheaboveget_user_pagesreference.+*/+for(i=0;i<ret;++i)+put_page(pages[i]);++if(migrate_pages(&cma_page_list,new_iommu_non_cma_page,+NULL,0,MIGRATE_SYNC,MR_CONTIG_RANGE)){+/*+*someofthepagesfailedmigration.Doget_user_pages+*withoutmigration.+*/+migrate_allow=false;++if(!list_empty(&cma_page_list))+putback_movable_pages(&cma_page_list);+}+/*+*Wedidmigrateallthepages,Trytogetthepagereferencesagain+*migratinganynewCMApageswhichwefailedtoisolateearlier.+*/+drain_allow=true;+gotoget_user_again;+}+returnret;}longmm_iommu_get(structmm_struct*mm,unsignedlongua,unsignedlongentries,structmm_iommu_table_group_mem_t**pmem){structmm_iommu_table_group_mem_t*mem;-longi,j,ret=0,locked_entries=0;+longi,ret=0,locked_entries=0;unsignedintpageshift;-unsignedlongflags;-unsignedlongcur_ua;-structpage*page=NULL;mutex_lock(&mem_list_mutex);
@@ -177,47 +238,37 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,gotounlock_exit;}+ret=get_user_pages_cma_migrate(ua,entries,1,mem->hpages);+if(ret!=entries){+/* free the reference taken */+for(i=0;i<ret;i++)+put_page(mem->hpages[i]);++vfree(mem->hpas);+kfree(mem);+ret=-EFAULT;+gotounlock_exit;+}else+ret=0;++pageshift=PAGE_SHIFT;for(i=0;i<entries;++i){-cur_ua=ua+(i<<PAGE_SHIFT);-if(1!=get_user_pages_fast(cur_ua,-1/* pages */,1/* iswrite */,&page)){-ret=-EFAULT;-for(j=0;j<i;++j)-put_page(pfn_to_page(mem->hpas[j]>>-PAGE_SHIFT));-vfree(mem->hpas);-kfree(mem);-gotounlock_exit;-}+structpage*page=mem->hpages[i];/*-*IfwegetapagefromtheCMAzone,sincewearegoingto-*bepinningtheseentries,wemightaswellmovethemout-*oftheCMAzoneifpossible.NOTE:faultingin+migration-*canbeexpensive.Batchingcanbeconsideredlater+*Allowtouselargerthan64kIOMMUpages.Onlydothat+*ifwearebackedbyhugetlb.*/-if(is_migrate_cma_page(page)){-if(mm_iommu_move_page_from_cma(page))-gotopopulate;-if(1!=get_user_pages_fast(cur_ua,-1/* pages */,1/* iswrite */,-&page)){-ret=-EFAULT;-for(j=0;j<i;++j)-put_page(pfn_to_page(mem->hpas[j]>>-PAGE_SHIFT));-vfree(mem->hpas);-kfree(mem);-gotounlock_exit;-}-}-populate:-pageshift=PAGE_SHIFT;-if(mem->pageshift>PAGE_SHIFT&&PageHuge(page)){+if((mem->pageshift>PAGE_SHIFT)&&PageHuge(page)){structpage*head=compound_head(page);pageshift=compound_order(head)+PAGE_SHIFT;}mem->pageshift=min(mem->pageshift,pageshift);+/*+*Wedon'tneedstructpagereferenceanymore,switch+*physicalladdress.+*/mem->hpas[i]=page_to_pfn(page)<<PAGE_SHIFT;+}atomic64_set(&mem->mapped,1);
THP pages can get split during different code paths. An incremented reference
count do imply we will not split the compound page. But the pmd entry can be
converted to level 4 pte entries. Keep the code simpler by allowing large
IOMMU page size only if the guest ram is backed by hugetlb pages.
Signed-off-by: Aneesh Kumar K.V <redacted>
---
arch/powerpc/mm/mmu_context_iommu.c | 16 ++--------------
1 file changed, 2 insertions(+), 14 deletions(-)
@@ -212,21 +212,9 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,}populate:pageshift=PAGE_SHIFT;-if(mem->pageshift>PAGE_SHIFT&&PageCompound(page)){-pte_t*pte;+if(mem->pageshift>PAGE_SHIFT&&PageHuge(page)){structpage*head=compound_head(page);-unsignedintcompshift=compound_order(head);-unsignedintpteshift;--local_irq_save(flags);/* disables as well */-pte=find_linux_pte(mm->pgd,cur_ua,NULL,&pteshift);--/* Double check it is still the same pinned page */-if(pte&&pte_page(*pte)==head&&-pteshift==compshift+PAGE_SHIFT)-pageshift=max_t(unsignedint,pteshift,-PAGE_SHIFT);-local_irq_restore(flags);+pageshift=compound_order(head)+PAGE_SHIFT;}mem->pageshift=min(mem->pageshift,pageshift);mem->hpas[i]=page_to_pfn(page)<<PAGE_SHIFT;
This patch series add support for migrating compound pages if we find them in the
CMA area before taking long term page reference for VFIO.
We now call lru_add_drain_all instead of lru_add_drain() which means we
now have higher chances of isolate_lru_page succeeding. The patch also
migrate all the pages in one call, instead of one page at a time.
Testing:
* TODO: test with hugetlb backed guest ram.
* Testing done with a code change as below
- if (is_migrate_cma_page(pages[i]) && migrate_allow) {
+ if (migrate_allow) {
...
+ migrate_allow = false;
Aneesh Kumar K.V (3):
mm: Export alloc_migrate_huge_page
powerpc/mm/iommu: Allow large IOMMU page size only for hugetlb backing
powerpc/mm/iommu: Allow migration of cma allocated pages during
mm_iommu_get
arch/powerpc/mm/mmu_context_iommu.c | 209 +++++++++++++++++-----------
include/linux/hugetlb.h | 2 +
mm/hugetlb.c | 4 +-
3 files changed, 128 insertions(+), 87 deletions(-)
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
From: David Gibson <hidden> Date: 2018-09-04 04:07:43
On Mon, Sep 03, 2018 at 10:07:32PM +0530, Aneesh Kumar K.V wrote:
THP pages can get split during different code paths. An incremented reference
count do imply we will not split the compound page. But the pmd entry can be
converted to level 4 pte entries. Keep the code simpler by allowing large
IOMMU page size only if the guest ram is backed by hugetlb pages.
Signed-off-by: Aneesh Kumar K.V <redacted>
So, I oked this in earlier discussion, but I had another thought and
now I'm not so sure.
@@ -212,21 +212,9 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,}populate:pageshift=PAGE_SHIFT;-if(mem->pageshift>PAGE_SHIFT&&PageCompound(page)){-pte_t*pte;+if(mem->pageshift>PAGE_SHIFT&&PageHuge(page)){
We can definitely only support large IOMMU pages with static
hugepages, not THPs, so the change from PageCompound to PageHuge is
definitely correct and a good idea.
struct page *head = compound_head(page);
- unsigned int compshift = compound_order(head);
- unsigned int pteshift;
-
- local_irq_save(flags); /* disables as well */
- pte = find_linux_pte(mm->pgd, cur_ua, NULL, &pteshift);
-
- /* Double check it is still the same pinned page */
- if (pte && pte_page(*pte) == head &&
- pteshift == compshift + PAGE_SHIFT)
- pageshift = max_t(unsigned int, pteshift,
- PAGE_SHIFT);
- local_irq_restore(flags);
+ pageshift = compound_order(head) + PAGE_SHIFT;
But, my concern with this part is: are we totally certain there's no
way to get part of a hugetlbfs page mapped with regular sized PTEs
(probably in addition to the expected hugetlb mapping).
I'm thinking weirdness like mremap(), mapping another hugetlb using
process's address space via /proc/*/mem or maybe something even more
exotic.
Now, it's possible that we don't really care here - even if it's not
technically right for this mapping, we could argue that as long as the
process has access to part of the hugepage, the whole thing is fair
game for a DMA mapping. In that case merely double checking that this
mapping is properly aligned would suffice (i.e. that:
(ua >> PAGE_SHIFT) == (page's index within the compound page)
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
On Mon, Sep 03, 2018 at 10:07:32PM +0530, Aneesh Kumar K.V wrote:
quoted
THP pages can get split during different code paths. An incremented reference
count do imply we will not split the compound page. But the pmd entry can be
converted to level 4 pte entries. Keep the code simpler by allowing large
IOMMU page size only if the guest ram is backed by hugetlb pages.
Signed-off-by: Aneesh Kumar K.V <redacted>
So, I oked this in earlier discussion, but I had another thought and
now I'm not so sure.
@@ -212,21 +212,9 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,}populate:pageshift=PAGE_SHIFT;-if(mem->pageshift>PAGE_SHIFT&&PageCompound(page)){-pte_t*pte;+if(mem->pageshift>PAGE_SHIFT&&PageHuge(page)){
We can definitely only support large IOMMU pages with static
hugepages, not THPs, so the change from PageCompound to PageHuge is
definitely correct and a good idea.
quoted
struct page *head = compound_head(page);
- unsigned int compshift = compound_order(head);
- unsigned int pteshift;
-
- local_irq_save(flags); /* disables as well */
- pte = find_linux_pte(mm->pgd, cur_ua, NULL, &pteshift);
-
- /* Double check it is still the same pinned page */
- if (pte && pte_page(*pte) == head &&
- pteshift == compshift + PAGE_SHIFT)
- pageshift = max_t(unsigned int, pteshift,
- PAGE_SHIFT);
- local_irq_restore(flags);
+ pageshift = compound_order(head) + PAGE_SHIFT;
But, my concern with this part is: are we totally certain there's no
way to get part of a hugetlbfs page mapped with regular sized PTEs
(probably in addition to the expected hugetlb mapping).
We don't map hugetlb pages that way. They are always pmd mapped on
book3s64.
I'm thinking weirdness like mremap(), mapping another hugetlb using
process's address space via /proc/*/mem or maybe something even more
exotic.
Now, it's possible that we don't really care here - even if it's not
technically right for this mapping, we could argue that as long as the
process has access to part of the hugepage, the whole thing is fair
game for a DMA mapping. In that case merely double checking that this
mapping is properly aligned would suffice (i.e. that:
(ua >> PAGE_SHIFT) == (page's index within the compound page)
From: David Gibson <hidden> Date: 2018-09-18 05:21:52
On Mon, Sep 03, 2018 at 10:07:33PM +0530, Aneesh Kumar K.V wrote:
Current code doesn't do page migration if the page allocated is a compound page.
With HugeTLB migration support, we can end up allocating hugetlb pages from
CMA region. Also THP pages can be allocated from CMA region. This patch updates
the code to handle compound pages correctly.
This add a new helper get_user_pages_cma_migrate. It does one get_user_pages
with right count, instead of doing one get_user_pages per page. That avoids
reading page table multiple times. The helper could possibly used by other
subystem if we have more users.
The patch also convert the hpas member of mm_iommu_table_group_mem_t to a union.
We use the same storage location to store pointers to struct page. We cannot
update alll the code path use struct page *, because we access hpas in real mode
and we can't do that struct page * to pfn conversion in real mode.
Signed-off-by: Aneesh Kumar K.V <redacted>
This approach doesn't seem quite right to me. It's specific to pages
mapped into the IOMMU. It's true that will address the obvious case
we have, of vfio-using guests fragmenting the CMA for other guests.
But AFAICT, fragmenting the CMA coud happen with *any* locked memory,
not just things that are IOMMU mapped for VFIO. So, for example a
guest not using vfio, but using -realtime mlock=on, or an unrelated
program using locked memory (e.g. gpg or something else that locks
memory for security reasons).
AFAICT this approach won't fix the problem for that case.
@@ -30,8 +31,18 @@ struct mm_iommu_table_group_mem_t {atomic64_tmapped;unsignedintpageshift;u64ua;/* userspace address */-u64entries;/* number of entries in hpas[] */-u64*hpas;/* vmalloc'ed */+u64entries;/* number of entries in hpages[] */+/*+*inmm_iommu_getwetemporarilyusethistostore+*structpageaddress.+*+*Weneedtoconvertuatohpainrealmode.Makeit+*simplerbystoringphysicalladdress.+*/+union{+structpage**hpages;/* vmalloc'ed */+phys_addr_t*hpas;+};};staticlongmm_iommu_adjust_locked_vm(structmm_struct*mm,
@@ -75,62 +86,112 @@ bool mm_iommu_preregistered(struct mm_struct *mm)EXPORT_SYMBOL_GPL(mm_iommu_preregistered);/*-*Takenfromalloc_migrate_targetwithchangestoremoveCMAallocations+*Takenfromalloc_migrate_target/alloc_migrate_huge_pagewithchangestoremove+*CMAallocations+*Isthistherightallocatorforhugetlb?*/structpage*new_iommu_non_cma_page(structpage*page,unsignedlongprivate){-gfp_tgfp_mask=GFP_USER;-structpage*new_page;+/* is this the right nid? */+intnid=numa_mem_id();+gfp_tgfp_mask=GFP_HIGHUSER;-if(PageCompound(page))-returnNULL;+if(PageHuge(page)){-if(PageHighMem(page))-gfp_mask|=__GFP_HIGHMEM;+structhstate*h=page_hstate(page);+/*+*Wedon'twanttodequeuefromthepoolbecausepoolpageswill+*mostlybefromtheCMAregion.+*/+returnalloc_migrate_huge_page(h,gfp_mask,nid,NULL);-/*-*Wedon'twanttheallocationtoforceanOOMifpossibe-*/-new_page=alloc_page(gfp_mask|__GFP_NORETRY|__GFP_NOWARN);-returnnew_page;+}elseif(PageTransHuge(page)){+structpage*thp;+gfp_tthp_gfpmask=GFP_TRANSHUGE&~__GFP_MOVABLE;++thp=__alloc_pages_node(nid,thp_gfpmask,HPAGE_PMD_ORDER);+if(!thp)+returnNULL;+prep_transhuge_page(thp);+returnthp;+}+return__alloc_pages_node(nid,gfp_mask,0);}-staticintmm_iommu_move_page_from_cma(structpage*page)+intget_user_pages_cma_migrate(unsignedlongstart,intnr_pages,intwrite,+structpage**pages){-intret=0;-LIST_HEAD(cma_migrate_pages);--/* Ignore huge pages for now */-if(PageCompound(page))-return-EBUSY;--lru_add_drain();-ret=isolate_lru_page(page);-if(ret)+inti,ret;+booldrain_allow=true;+boolmigrate_allow=true;+LIST_HEAD(cma_page_list);++get_user_again:+ret=get_user_pages_fast(start,nr_pages,write,pages);+if(ret<=0)returnret;-list_add(&page->lru,&cma_migrate_pages);-put_page(page);/* Drop the gup reference */--ret=migrate_pages(&cma_migrate_pages,new_iommu_non_cma_page,-NULL,0,MIGRATE_SYNC,MR_CONTIG_RANGE);-if(ret){-if(!list_empty(&cma_migrate_pages))-putback_movable_pages(&cma_migrate_pages);+for(i=0;i<ret;++i){+/*+*IfwegetapagefromtheCMAzone,sincewearegoingto+*bepinningtheseentries,wemightaswellmovethemout+*oftheCMAzoneifpossible.+*/+if(is_migrate_cma_page(pages[i])&&migrate_allow){+if(PageHuge(pages[i]))+isolate_huge_page(pages[i],&cma_page_list);+else{+structpage*head=compound_head(pages[i]);++if(!PageLRU(head)&&drain_allow){+lru_add_drain_all();+drain_allow=false;+}++if(!isolate_lru_page(head)){+list_add_tail(&head->lru,&cma_page_list);+mod_node_page_state(page_pgdat(head),+NR_ISOLATED_ANON++page_is_file_cache(head),+hpage_nr_pages(head));+}+}+}}--return0;+if(!list_empty(&cma_page_list)){+/*+*droptheaboveget_user_pagesreference.+*/+for(i=0;i<ret;++i)+put_page(pages[i]);++if(migrate_pages(&cma_page_list,new_iommu_non_cma_page,+NULL,0,MIGRATE_SYNC,MR_CONTIG_RANGE)){+/*+*someofthepagesfailedmigration.Doget_user_pages+*withoutmigration.+*/+migrate_allow=false;++if(!list_empty(&cma_page_list))+putback_movable_pages(&cma_page_list);+}+/*+*Wedidmigrateallthepages,Trytogetthepagereferencesagain+*migratinganynewCMApageswhichwefailedtoisolateearlier.+*/+drain_allow=true;+gotoget_user_again;+}+returnret;}longmm_iommu_get(structmm_struct*mm,unsignedlongua,unsignedlongentries,structmm_iommu_table_group_mem_t**pmem){structmm_iommu_table_group_mem_t*mem;-longi,j,ret=0,locked_entries=0;+longi,ret=0,locked_entries=0;unsignedintpageshift;-unsignedlongflags;-unsignedlongcur_ua;-structpage*page=NULL;mutex_lock(&mem_list_mutex);
@@ -177,47 +238,37 @@ long mm_iommu_get(struct mm_struct *mm, unsigned long ua, unsigned long entries,gotounlock_exit;}+ret=get_user_pages_cma_migrate(ua,entries,1,mem->hpages);+if(ret!=entries){+/* free the reference taken */+for(i=0;i<ret;i++)+put_page(mem->hpages[i]);++vfree(mem->hpas);+kfree(mem);+ret=-EFAULT;+gotounlock_exit;+}else+ret=0;++pageshift=PAGE_SHIFT;for(i=0;i<entries;++i){-cur_ua=ua+(i<<PAGE_SHIFT);-if(1!=get_user_pages_fast(cur_ua,-1/* pages */,1/* iswrite */,&page)){-ret=-EFAULT;-for(j=0;j<i;++j)-put_page(pfn_to_page(mem->hpas[j]>>-PAGE_SHIFT));-vfree(mem->hpas);-kfree(mem);-gotounlock_exit;-}+structpage*page=mem->hpages[i];/*-*IfwegetapagefromtheCMAzone,sincewearegoingto-*bepinningtheseentries,wemightaswellmovethemout-*oftheCMAzoneifpossible.NOTE:faultingin+migration-*canbeexpensive.Batchingcanbeconsideredlater+*Allowtouselargerthan64kIOMMUpages.Onlydothat+*ifwearebackedbyhugetlb.*/-if(is_migrate_cma_page(page)){-if(mm_iommu_move_page_from_cma(page))-gotopopulate;-if(1!=get_user_pages_fast(cur_ua,-1/* pages */,1/* iswrite */,-&page)){-ret=-EFAULT;-for(j=0;j<i;++j)-put_page(pfn_to_page(mem->hpas[j]>>-PAGE_SHIFT));-vfree(mem->hpas);-kfree(mem);-gotounlock_exit;-}-}-populate:-pageshift=PAGE_SHIFT;-if(mem->pageshift>PAGE_SHIFT&&PageHuge(page)){+if((mem->pageshift>PAGE_SHIFT)&&PageHuge(page)){structpage*head=compound_head(page);pageshift=compound_order(head)+PAGE_SHIFT;}mem->pageshift=min(mem->pageshift,pageshift);+/*+*Wedon'tneedstructpagereferenceanymore,switch+*physicalladdress.+*/mem->hpas[i]=page_to_pfn(page)<<PAGE_SHIFT;+}atomic64_set(&mem->mapped,1);
--
David Gibson | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au | minimalist, thank you. NOT _the_ _other_
| _way_ _around_!
http://www.ozlabs.org/~dgibson
On Mon, Sep 03, 2018 at 10:07:33PM +0530, Aneesh Kumar K.V wrote:
quoted
Current code doesn't do page migration if the page allocated is a compound page.
With HugeTLB migration support, we can end up allocating hugetlb pages from
CMA region. Also THP pages can be allocated from CMA region. This patch updates
the code to handle compound pages correctly.
This add a new helper get_user_pages_cma_migrate. It does one get_user_pages
with right count, instead of doing one get_user_pages per page. That avoids
reading page table multiple times. The helper could possibly used by other
subystem if we have more users.
The patch also convert the hpas member of mm_iommu_table_group_mem_t to a union.
We use the same storage location to store pointers to struct page. We cannot
update alll the code path use struct page *, because we access hpas in real mode
and we can't do that struct page * to pfn conversion in real mode.
Signed-off-by: Aneesh Kumar K.V <redacted>
This approach doesn't seem quite right to me. It's specific to pages
mapped into the IOMMU. It's true that will address the obvious case
we have, of vfio-using guests fragmenting the CMA for other guests.
But AFAICT, fragmenting the CMA coud happen with *any* locked memory,
not just things that are IOMMU mapped for VFIO. So, for example a
guest not using vfio, but using -realtime mlock=on, or an unrelated
program using locked memory (e.g. gpg or something else that locks
memory for security reasons).
AFAICT this approach won't fix the problem for that case.
yes and we should be migrate away pages that we allocated out of CMA
region before we pin/mlock them. This handle the long term pin w.r.t
vfio. For mlock too we should do that.
-aneesh