The MM subsystem is trying to shrink struct page. This patchset
introduces a memory descriptor for page table tracking - struct ptdesc.
This patchset introduces ptdesc, splits ptdesc from struct page, and
converts many callers of page table constructor/destructors to use ptdescs.
Ptdesc is a foundation to further standardize page tables, and eventually
allow for dynamic allocation of page tables independent of struct page.
However, the use of pages for page table tracking is quite deeply
ingrained and varied across archictectures, so there is still a lot of
work to be done before that can happen.
This is rebased on next-20230609.
v4:
Got more Acked-bys
Fixed m68k compilation issue
Dropped unnecessary casts
Cleanup some fields in struct ptdesc
Vishal Moola (Oracle) (34):
mm: Add PAGE_TYPE_OP folio functions
s390: Use _pt_s390_gaddr for gmap address tracking
s390: Use pt_frag_refcount for pagetables
pgtable: Create struct ptdesc
mm: add utility functions for ptdesc
mm: Convert pmd_pgtable_page() to pmd_ptdesc()
mm: Convert ptlock_alloc() to use ptdescs
mm: Convert ptlock_ptr() to use ptdescs
mm: Convert pmd_ptlock_init() to use ptdescs
mm: Convert ptlock_init() to use ptdescs
mm: Convert pmd_ptlock_free() to use ptdescs
mm: Convert ptlock_free() to use ptdescs
mm: Create ptdesc equivalents for pgtable_{pte,pmd}_page_{ctor,dtor}
powerpc: Convert various functions to use ptdescs
x86: Convert various functions to use ptdescs
s390: Convert various gmap functions to use ptdescs
s390: Convert various pgalloc functions to use ptdescs
mm: Remove page table members from struct page
pgalloc: Convert various functions to use ptdescs
arm: Convert various functions to use ptdescs
arm64: Convert various functions to use ptdescs
csky: Convert __pte_free_tlb() to use ptdescs
hexagon: Convert __pte_free_tlb() to use ptdescs
loongarch: Convert various functions to use ptdescs
m68k: Convert various functions to use ptdescs
mips: Convert various functions to use ptdescs
nios2: Convert __pte_free_tlb() to use ptdescs
openrisc: Convert __pte_free_tlb() to use ptdescs
riscv: Convert alloc_{pmd, pte}_late() to use ptdescs
sh: Convert pte_free_tlb() to use ptdescs
sparc64: Convert various functions to use ptdescs
sparc: Convert pgtable_pte_page_{ctor, dtor}() to ptdesc equivalents
um: Convert {pmd, pte}_free_tlb() to use ptdescs
mm: Remove pgtable_{pmd, pte}_page_{ctor, dtor}() wrappers
Documentation/mm/split_page_table_lock.rst | 12 +-
.../zh_CN/mm/split_page_table_lock.rst | 14 +-
arch/arm/include/asm/tlb.h | 12 +-
arch/arm/mm/mmu.c | 6 +-
arch/arm64/include/asm/tlb.h | 14 +-
arch/arm64/mm/mmu.c | 7 +-
arch/csky/include/asm/pgalloc.h | 4 +-
arch/hexagon/include/asm/pgalloc.h | 8 +-
arch/loongarch/include/asm/pgalloc.h | 27 ++-
arch/loongarch/mm/pgtable.c | 7 +-
arch/m68k/include/asm/mcf_pgalloc.h | 41 ++--
arch/m68k/include/asm/sun3_pgalloc.h | 8 +-
arch/m68k/mm/motorola.c | 4 +-
arch/mips/include/asm/pgalloc.h | 31 +--
arch/mips/mm/pgtable.c | 7 +-
arch/nios2/include/asm/pgalloc.h | 8 +-
arch/openrisc/include/asm/pgalloc.h | 8 +-
arch/powerpc/mm/book3s64/mmu_context.c | 10 +-
arch/powerpc/mm/book3s64/pgtable.c | 32 +--
arch/powerpc/mm/pgtable-frag.c | 46 ++--
arch/riscv/include/asm/pgalloc.h | 8 +-
arch/riscv/mm/init.c | 16 +-
arch/s390/include/asm/pgalloc.h | 4 +-
arch/s390/include/asm/tlb.h | 4 +-
arch/s390/mm/gmap.c | 222 +++++++++++-------
arch/s390/mm/pgalloc.c | 126 +++++-----
arch/sh/include/asm/pgalloc.h | 9 +-
arch/sparc/mm/init_64.c | 17 +-
arch/sparc/mm/srmmu.c | 5 +-
arch/um/include/asm/pgalloc.h | 18 +-
arch/x86/mm/pgtable.c | 46 ++--
arch/x86/xen/mmu_pv.c | 2 +-
include/asm-generic/pgalloc.h | 62 +++--
include/asm-generic/tlb.h | 11 +
include/linux/mm.h | 155 ++++++++----
include/linux/mm_types.h | 14 --
include/linux/page-flags.h | 20 +-
include/linux/pgtable.h | 60 +++++
mm/memory.c | 8 +-
39 files changed, 664 insertions(+), 449 deletions(-)
--
2.40.1
No folio equivalents for page type operations have been defined, so
define them for later folio conversions.
Also changes the Page##uname macros to take in const struct page* since
we only read the memory here.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/page-flags.h | 20 ++++++++++++++++++--
1 file changed, 18 insertions(+), 2 deletions(-)
s390 uses page->index to keep track of page tables for the guest address
space. In an attempt to consolidate the usage of page fields in s390,
replace _pt_pad_2 with _pt_s390_gaddr to replace page->index in gmap.
This will help with the splitting of struct ptdesc from struct page, as
well as allow s390 to use _pt_frag_refcount for fragmented page table
tracking.
Since page->_pt_s390_gaddr aliases with mapping, ensure its set to NULL
before freeing the pages as well.
This also reverts commit 7e25de77bc5ea ("s390/mm: use pmd_pgtable_page()
helper in __gmap_segment_gaddr()") which had s390 use
pmd_pgtable_page() to get a gmap page table, as pmd_pgtable_page()
should be used for more generic process page tables.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/s390/mm/gmap.c | 56 +++++++++++++++++++++++++++-------------
include/linux/mm_types.h | 2 +-
2 files changed, 39 insertions(+), 19 deletions(-)
@@ -70,7 +70,7 @@ static struct gmap *gmap_alloc(unsigned long limit)page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)gotoout_free;-page->index=0;+page->_pt_s390_gaddr=0;list_add(&page->lru,&gmap->crst_list);table=page_to_virt(page);crst_table_init(table,etype);
@@ -187,16 +187,20 @@ static void gmap_free(struct gmap *gmap)if(!(gmap_is_shadow(gmap)&&gmap->removed))gmap_flush_tlb(gmap);/* Free all segment & region tables. */-list_for_each_entry_safe(page,next,&gmap->crst_list,lru)+list_for_each_entry_safe(page,next,&gmap->crst_list,lru){+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);+}gmap_radix_tree_free(&gmap->guest_to_host);gmap_radix_tree_free(&gmap->host_to_guest);/* Free additional data for a shadow gmap */if(gmap_is_shadow(gmap)){/* Free all page tables. */-list_for_each_entry_safe(page,next,&gmap->pt_list,lru)+list_for_each_entry_safe(page,next,&gmap->pt_list,lru){+page->_pt_s390_gaddr=0;page_table_free_pgste(page);+}gmap_rmap_radix_tree_free(&gmap->host_to_rmap);/* Release reference to the parent */gmap_put(gmap->parent);
@@ -318,12 +322,14 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,list_add(&page->lru,&gmap->crst_list);*table=__pa(new)|_REGION_ENTRY_LENGTH|(*table&_REGION_ENTRY_TYPE_MASK);-page->index=gaddr;+page->_pt_s390_gaddr=gaddr;page=NULL;}spin_unlock(&gmap->guest_table_lock);-if(page)+if(page){+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);+}return0;}
@@ -336,12 +342,14 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,staticunsignedlong__gmap_segment_gaddr(unsignedlong*entry){structpage*page;-unsignedlongoffset;+unsignedlongoffset,mask;offset=(unsignedlong)entry/sizeof(unsignedlong);offset=(offset&(PTRS_PER_PMD-1))*PMD_SIZE;-page=pmd_pgtable_page((pmd_t*)entry);-returnpage->index+offset;+mask=~(PTRS_PER_PMD*sizeof(pmd_t)-1);+page=virt_to_page((void*)((unsignedlong)entry&mask));++returnpage->_pt_s390_gaddr+offset;}/**
@@ -1467,6 +1479,7 @@ static void gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr)/* Free region 3 table */page=phys_to_page(r3t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}
@@ -1495,6 +1508,7 @@ static void __gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr,/* Free region 3 table */page=phys_to_page(r3t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}}
@@ -1525,6 +1539,7 @@ static void gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr)/* Free region 2 table */page=phys_to_page(r2t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}
@@ -1557,6 +1572,7 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,/* Free region 2 table */page=phys_to_page(r2t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}}
@@ -1762,9 +1778,9 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=r2t&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_r2t=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1814,6 +1830,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -1846,9 +1863,9 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=r3t&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_r3t=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1898,6 +1915,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -1930,9 +1948,9 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=sgt&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_sgt=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1982,6 +2000,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -2014,9 +2033,9 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,if(table&&!(*table&_SEGMENT_ENTRY_INVALID)){/* Shadow page tables are full pages (pte+pgste) */page=pfn_to_page(*table>>PAGE_SHIFT);-*pgt=page->index&~GMAP_SHADOW_FAKE_TABLE;+*pgt=page->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;*dat_protection=!!(*table&_SEGMENT_ENTRY_PROTECT);-*fake=!!(page->index&GMAP_SHADOW_FAKE_TABLE);+*fake=!!(page->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);rc=0;}else{rc=-EAGAIN;
@@ -2054,9 +2073,9 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,page=page_table_alloc_pgste(sg->mm);if(!page)return-ENOMEM;-page->index=pgt&_SEGMENT_ENTRY_ORIGIN;+page->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_pgt=page_to_phys(page);/* Install shadow page table */spin_lock(&sg->guest_table_lock);
@@ -2101,6 +2120,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;page_table_free_pgste(page);returnrc;
s390 currently uses _refcount to identify fragmented page tables.
The page table struct already has a member pt_frag_refcount used by
powerpc, so have s390 use that instead of the _refcount field as well.
This improves the safety for _refcount and the page table tracking.
This also allows us to simplify the tracking since we can once again use
the lower byte of pt_frag_refcount instead of the upper byte of _refcount.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/s390/mm/pgalloc.c | 38 +++++++++++++++-----------------------
1 file changed, 15 insertions(+), 23 deletions(-)
@@ -182,20 +182,17 @@ void page_table_free_pgste(struct page *page)*Asfollowsfromtheabove,nounallocatedorfullyallocatedparent*pagesarecontainedinmm_context_t::pgtable_list.*-*Theupperbyte(bits24-31)oftheparentpage_refcountisused+*Thelowerbyte(bits0-7)oftheparentpagept_frag_refcountisused*fortrackingcontained2KB-pgtablesandhasthefollowingformat:**PPAA-*01234567upperbyte(bits24-31)ofstructpage::_refcount+*01234567upperbyte(bits0-7)ofstructpage::pt_frag_refcount*||||*|||+---upper2KB-pgtableisallocated*||+----lower2KB-pgtableisallocated*|+-------upper2KB-pgtableispendingforremoval*+--------lower2KB-pgtableispendingforremoval*-*(Seecommit620b4e903179("s390: use _refcount for pgtables")onwhy-*using_refcountispossible).-**When2KB-pgtableisallocatedthecorrespondingAAbitissetto1.*Theparentpageiseither:*-addedtomm_context_t::pgtable_listincasethesecondhalfofthe
@@ -243,11 +240,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm)if(!list_empty(&mm->context.pgtable_list)){page=list_first_entry(&mm->context.pgtable_list,structpage,lru);-mask=atomic_read(&page->_refcount)>>24;+mask=atomic_read(&page->pt_frag_refcount);/**Thependingremovalbitsmustalsobechecked.*Failuretodosomightleadtoanimpossible-*valueof(i.e0x13or0x23)writtento_refcount.+*valueof(i.e0x13or0x23)writtento+*pt_frag_refcount.*Suchvaluesviolatetheassumptionthatpendingand*allocationbitsaremutuallyexclusive,andtherest*ofthecodeunrailsasresult.Thatcouldleadto
@@ -259,8 +257,8 @@ unsigned long *page_table_alloc(struct mm_struct *mm)bit=mask&1;/* =1 -> second 2K */if(bit)table+=PTRS_PER_PTE;-atomic_xor_bits(&page->_refcount,-0x01U<<(bit+24));+atomic_xor_bits(&page->pt_frag_refcount,+0x01U<<bit);list_del(&page->lru);}}
@@ -281,12 +279,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm)table=(unsignedlong*)page_to_virt(page);if(mm_alloc_pgste(mm)){/* Return 4K page table with PGSTEs */-atomic_xor_bits(&page->_refcount,0x03U<<24);+atomic_xor_bits(&page->pt_frag_refcount,0x03U);memset64((u64*)table,_PAGE_INVALID,PTRS_PER_PTE);memset64((u64*)table+PTRS_PER_PTE,0,PTRS_PER_PTE);}else{/* Return the first 2K fragment of the page */-atomic_xor_bits(&page->_refcount,0x01U<<24);+atomic_xor_bits(&page->pt_frag_refcount,0x01U);memset64((u64*)table,_PAGE_INVALID,2*PTRS_PER_PTE);spin_lock_bh(&mm->context.lock);list_add(&page->lru,&mm->context.pgtable_list);
Introduce utility functions setting the foundation for ptdescs. These
will also assist in the splitting out of ptdesc from struct page.
Functions that focus on the descriptor are prefixed with ptdesc_* while
functions that focus on the pagetable are prefixed with pagetable_*.
pagetable_alloc() is defined to allocate new ptdesc pages as compound
pages. This is to standardize ptdescs by allowing for one allocation
and one free function, in contrast to 2 allocation and 2 free functions.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/asm-generic/tlb.h | 11 +++++++
include/linux/mm.h | 61 +++++++++++++++++++++++++++++++++++++++
include/linux/pgtable.h | 12 ++++++++
3 files changed, 84 insertions(+)
Converts pmd_pgtable_page() to pmd_ptdesc() and all its callers. This
removes some direct accesses to struct page, working towards splitting
out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 6 +++---
mm/memory.c | 4 ++--
2 files changed, 5 insertions(+), 5 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/x86/xen/mmu_pv.c | 2 +-
include/linux/mm.h | 14 +++++++-------
2 files changed, 8 insertions(+), 8 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm.h | 10 +++++-----
mm/memory.c | 4 ++--
2 files changed, 7 insertions(+), 7 deletions(-)
@@ -246,15 +246,15 @@ static void destroy_contexts(mm_context_t *ctx)staticvoidpmd_frag_destroy(void*pmd_frag){intcount;-structpage*page;+structptdesc*ptdesc;-page=virt_to_page(pmd_frag);+ptdesc=virt_to_ptdesc(pmd_frag);/* drop all the pending references */count=((unsignedlong)pmd_frag&~PAGE_MASK)>>PMD_FRAG_SIZE_SHIFT;/* We allow PTE_FRAG_NR fragments from a PTE page */-if(atomic_sub_and_test(PMD_FRAG_NR-count,&page->pt_frag_refcount)){-pgtable_pmd_page_dtor(page);-__free_page(page);+if(atomic_sub_and_test(PMD_FRAG_NR-count,&ptdesc->pt_frag_refcount)){+pagetable_pmd_dtor(ptdesc);+pagetable_free(ptdesc);}}
@@ -18,15 +18,15 @@voidpte_frag_destroy(void*pte_frag){intcount;-structpage*page;+structptdesc*ptdesc;-page=virt_to_page(pte_frag);+ptdesc=virt_to_ptdesc(pte_frag);/* drop all the pending references */count=((unsignedlong)pte_frag&~PAGE_MASK)>>PTE_FRAG_SIZE_SHIFT;/* We allow PTE_FRAG_NR fragments from a PTE page */-if(atomic_sub_and_test(PTE_FRAG_NR-count,&page->pt_frag_refcount)){-pgtable_pte_page_dtor(page);-__free_page(page);+if(atomic_sub_and_test(PTE_FRAG_NR-count,&ptdesc->pt_frag_refcount)){+pagetable_pte_dtor(ptdesc);+pagetable_free(ptdesc);}}
In order to split struct ptdesc from struct page, convert various
functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/x86/mm/pgtable.c | 46 +++++++++++++++++++++++++------------------
1 file changed, 27 insertions(+), 19 deletions(-)
@@ -232,16 +235,21 @@ static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[], int count)gfp&=~__GFP_ACCOUNT;for(i=0;i<count;i++){-pmd_t*pmd=(pmd_t*)__get_free_page(gfp);-if(!pmd)+pmd_t*pmd=NULL;+structptdesc*ptdesc=pagetable_alloc(gfp,0);++if(!ptdesc)failed=true;-if(pmd&&!pgtable_pmd_page_ctor(virt_to_page(pmd))){-free_page((unsignedlong)pmd);-pmd=NULL;+if(ptdesc&&!pagetable_pmd_ctor(ptdesc)){+pagetable_free(ptdesc);+ptdesc=NULL;failed=true;}-if(pmd)+if(ptdesc){mm_inc_nr_pmds(mm);+pmd=ptdesc_address(ptdesc);+}+pmds[i]=pmd;}
@@ -830,7 +838,7 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr)free_page((unsignedlong)pmd_sv);-pgtable_pmd_page_dtor(virt_to_page(pmd));+pagetable_pmd_dtor(virt_to_ptdesc(pmd));free_page((unsignedlong)pmd);return1;
In order to split struct ptdesc from struct page, convert various
functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/s390/mm/gmap.c | 230 ++++++++++++++++++++++++--------------------
1 file changed, 128 insertions(+), 102 deletions(-)
@@ -67,12 +67,12 @@ static struct gmap *gmap_alloc(unsigned long limit)spin_lock_init(&gmap->guest_table_lock);spin_lock_init(&gmap->shadow_lock);refcount_set(&gmap->ref_count,1);-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)gotoout_free;-page->_pt_s390_gaddr=0;-list_add(&page->lru,&gmap->crst_list);-table=page_to_virt(page);+ptdesc->_pt_s390_gaddr=0;+list_add(&ptdesc->pt_list,&gmap->crst_list);+table=ptdesc_to_virt(ptdesc);crst_table_init(table,etype);gmap->table=table;gmap->asce=atype|_ASCE_TABLE_LENGTH|
@@ -181,25 +181,25 @@ static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)*/staticvoidgmap_free(structgmap*gmap){-structpage*page,*next;+structptdesc*ptdesc,*next;/* Flush tlb of all gmaps (if not already done for shadows) */if(!(gmap_is_shadow(gmap)&&gmap->removed))gmap_flush_tlb(gmap);/* Free all segment & region tables. */-list_for_each_entry_safe(page,next,&gmap->crst_list,lru){-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+list_for_each_entry_safe(ptdesc,next,&gmap->crst_list,pt_list){+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}gmap_radix_tree_free(&gmap->guest_to_host);gmap_radix_tree_free(&gmap->host_to_guest);/* Free additional data for a shadow gmap */if(gmap_is_shadow(gmap)){-/* Free all page tables. */-list_for_each_entry_safe(page,next,&gmap->pt_list,lru){-page->_pt_s390_gaddr=0;-page_table_free_pgste(page);+/* Free all ptdesc tables. */+list_for_each_entry_safe(ptdesc,next,&gmap->pt_list,pt_list){+ptdesc->_pt_s390_gaddr=0;+page_table_free_pgste(ptdesc_page(ptdesc));}gmap_rmap_radix_tree_free(&gmap->host_to_rmap);/* Release reference to the parent */
@@ -308,27 +308,27 @@ EXPORT_SYMBOL_GPL(gmap_get_enabled);staticintgmap_alloc_table(structgmap*gmap,unsignedlong*table,unsignedlonginit,unsignedlonggaddr){-structpage*page;+structptdesc*ptdesc;unsignedlong*new;/* since we dont free the gmap table until gmap_free we can unlock */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-new=page_to_virt(page);+new=ptdesc_to_virt(ptdesc);crst_table_init(new,init);spin_lock(&gmap->guest_table_lock);if(*table&_REGION_ENTRY_INVALID){-list_add(&page->lru,&gmap->crst_list);+list_add(&ptdesc->pt_list,&gmap->crst_list);*table=__pa(new)|_REGION_ENTRY_LENGTH|(*table&_REGION_ENTRY_TYPE_MASK);-page->_pt_s390_gaddr=gaddr;-page=NULL;+ptdesc->_pt_s390_gaddr=gaddr;+ptdesc=NULL;}spin_unlock(&gmap->guest_table_lock);-if(page){-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+if(ptdesc){+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}return0;}
@@ -341,15 +341,15 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,*/staticunsignedlong__gmap_segment_gaddr(unsignedlong*entry){-structpage*page;+structptdesc*ptdesc;unsignedlongoffset,mask;offset=(unsignedlong)entry/sizeof(unsignedlong);offset=(offset&(PTRS_PER_PMD-1))*PMD_SIZE;mask=~(PTRS_PER_PMD*sizeof(pmd_t)-1);-page=virt_to_page((void*)((unsignedlong)entry&mask));+ptdesc=virt_to_ptdesc((void*)((unsignedlong)entry&mask));-returnpage->_pt_s390_gaddr+offset;+returnptdesc->_pt_s390_gaddr+offset;}/**
@@ -1345,6 +1345,7 @@ static void gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr)unsignedlong*ste;phys_addr_tsto,pgt;structpage*page;+structptdesc*ptdesc;BUG_ON(!gmap_is_shadow(sg));ste=gmap_table_walk(sg,raddr,1);/* get segment pointer */
@@ -1571,9 +1593,11 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,r1t[i]=_REGION1_ENTRY_EMPTY;/* Free region 2 table */page=phys_to_page(r2t);-list_del(&page->lru);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);++ptdesc=page_ptdesc(page);+list_del(&ptdesc->pt_list);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}}
@@ -1770,18 +1794,18 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_r2t;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg));/* Allocate a shadow region second table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_r2t=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_r2t=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,4);/* get region-1 pointer */
@@ -1802,7 +1826,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,_REGION_ENTRY_TYPE_R1|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=(r2t&_REGION_ENTRY_PROTECT);-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -1830,8 +1854,8 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_r2t);
@@ -1855,18 +1879,18 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_r3t;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg));/* Allocate a shadow region second table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_r3t=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_r3t=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,3);/* get region-2 pointer */
@@ -1887,7 +1911,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,_REGION_ENTRY_TYPE_R2|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=(r3t&_REGION_ENTRY_PROTECT);-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -1915,8 +1939,8 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_r3t);
@@ -1940,18 +1964,18 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_sgt;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg)||(sgt&_REGION3_ENTRY_LARGE));/* Allocate a shadow segment table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_sgt=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_sgt=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,2);/* get region-3 pointer */
@@ -1972,7 +1996,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,_REGION_ENTRY_TYPE_R3|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=sgt&_REGION_ENTRY_PROTECT;-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -2000,8 +2024,8 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
@@ -2024,8 +2048,9 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,int*fake){unsignedlong*table;-structpage*page;intrc;+structpage*page;+structptdesc*ptdesc;BUG_ON(!gmap_is_shadow(sg));spin_lock(&sg->guest_table_lock);
@@ -2033,9 +2058,10 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,if(table&&!(*table&_SEGMENT_ENTRY_INVALID)){/* Shadow page tables are full pages (pte+pgste) */page=pfn_to_page(*table>>PAGE_SHIFT);-*pgt=page->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;+ptdesc=page_ptdesc(page);+*pgt=ptdesc->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;*dat_protection=!!(*table&_SEGMENT_ENTRY_PROTECT);-*fake=!!(page->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);+*fake=!!(ptdesc->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);rc=0;}else{rc=-EAGAIN;
@@ -2064,19 +2090,19 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,{unsignedlongraddr,origin;unsignedlong*table;-structpage*page;+structptdesc*ptdesc;phys_addr_ts_pgt;intrc;BUG_ON(!gmap_is_shadow(sg)||(pgt&_SEGMENT_ENTRY_LARGE));/* Allocate a shadow page table */-page=page_table_alloc_pgste(sg->mm);-if(!page)+ptdesc=page_ptdesc(page_table_alloc_pgste(sg->mm));+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_pgt=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_pgt=page_to_phys(ptdesc_page(ptdesc));/* Install shadow page table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,1);/* get segment pointer */
@@ -2094,7 +2120,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,/* mark as invalid as long as the parent table is not protected */*table=(unsignedlong)s_pgt|_SEGMENT_ENTRY|(pgt&_SEGMENT_ENTRY_PROTECT)|_SEGMENT_ENTRY_INVALID;-list_add(&page->lru,&sg->pt_list);+list_add(&ptdesc->pt_list,&sg->pt_list);if(fake){/* nothing to protect for fake tables */*table&=~_SEGMENT_ENTRY_INVALID;
@@ -2120,8 +2146,8 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-page_table_free_pgste(page);+ptdesc->_pt_s390_gaddr=0;+page_table_free_pgste(ptdesc_page(ptdesc));returnrc;}
@@ -2863,10 +2889,10 @@ int s390_replace_asce(struct gmap *gmap)if((gmap->asce&_ASCE_TYPE_MASK)==_ASCE_TYPE_SEGMENT)return-EINVAL;-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-table=page_to_virt(page);+table=ptdesc_to_virt(ptdesc);memcpy(table,gmap->table,1UL<<(CRST_ALLOC_ORDER+PAGE_SHIFT));/*
@@ -2875,7 +2901,7 @@ int s390_replace_asce(struct gmap *gmap)*itwillbefreedwhentheVMistorndown.*/spin_lock(&gmap->guest_table_lock);-list_add(&page->lru,&gmap->crst_list);+list_add(&ptdesc->pt_list,&gmap->crst_list);spin_unlock(&gmap->guest_table_lock);/* Set new table origin while preserving existing ASCE control bits */
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/s390/include/asm/pgalloc.h | 4 +-
arch/s390/include/asm/tlb.h | 4 +-
arch/s390/mm/pgalloc.c | 108 ++++++++++++++++----------------
3 files changed, 59 insertions(+), 57 deletions(-)
@@ -140,21 +140,21 @@ static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)structpage*page_table_alloc_pgste(structmm_struct*mm){-structpage*page;+structptdesc*ptdesc;u64*table;-page=alloc_page(GFP_KERNEL);-if(page){-table=(u64*)page_to_virt(page);+ptdesc=pagetable_alloc(GFP_KERNEL,0);+if(ptdesc){+table=(u64*)ptdesc_to_virt(ptdesc);memset64(table,_PAGE_INVALID,PTRS_PER_PTE);memset64(table+PTRS_PER_PTE,0,PTRS_PER_PTE);}-returnpage;+returnptdesc_page(ptdesc);}voidpage_table_free_pgste(structpage*page){-__free_page(page);+pagetable_free(page_ptdesc(page));}#endif /* CONFIG_PGSTE */
@@ -230,7 +230,7 @@ void page_table_free_pgste(struct page *page)unsignedlong*page_table_alloc(structmm_struct*mm){unsignedlong*table;-structpage*page;+structptdesc*ptdesc;unsignedintmask,bit;/* Try to get a fragment of a 4K page as a 2K page table */
@@ -238,9 +238,9 @@ unsigned long *page_table_alloc(struct mm_struct *mm)table=NULL;spin_lock_bh(&mm->context.lock);if(!list_empty(&mm->context.pgtable_list)){-page=list_first_entry(&mm->context.pgtable_list,-structpage,lru);-mask=atomic_read(&page->pt_frag_refcount);+ptdesc=list_first_entry(&mm->context.pgtable_list,+structptdesc,pt_list);+mask=atomic_read(&ptdesc->pt_frag_refcount);/**Thependingremovalbitsmustalsobechecked.*Failuretodosomightleadtoanimpossible
@@ -253,13 +253,13 @@ unsigned long *page_table_alloc(struct mm_struct *mm)*/mask=(mask|(mask>>4))&0x03U;if(mask!=0x03U){-table=(unsignedlong*)page_to_virt(page);+table=(unsignedlong*)ptdesc_to_virt(ptdesc);bit=mask&1;/* =1 -> second 2K */if(bit)table+=PTRS_PER_PTE;-atomic_xor_bits(&page->pt_frag_refcount,+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x01U<<bit);-list_del(&page->lru);+list_del(&ptdesc->pt_list);}}spin_unlock_bh(&mm->context.lock);
@@ -267,27 +267,27 @@ unsigned long *page_table_alloc(struct mm_struct *mm)returntable;}/* Allocate a fresh page */-page=alloc_page(GFP_KERNEL);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL,0);+if(!ptdesc)returnNULL;-if(!pgtable_pte_page_ctor(page)){-__free_page(page);+if(!pagetable_pte_ctor(ptdesc)){+pagetable_free(ptdesc);returnNULL;}-arch_set_page_dat(page,0);+arch_set_page_dat(ptdesc_page(ptdesc),0);/* Initialize page table */-table=(unsignedlong*)page_to_virt(page);+table=(unsignedlong*)ptdesc_to_virt(ptdesc);if(mm_alloc_pgste(mm)){/* Return 4K page table with PGSTEs */-atomic_xor_bits(&page->pt_frag_refcount,0x03U);+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x03U);memset64((u64*)table,_PAGE_INVALID,PTRS_PER_PTE);memset64((u64*)table+PTRS_PER_PTE,0,PTRS_PER_PTE);}else{/* Return the first 2K fragment of the page */-atomic_xor_bits(&page->pt_frag_refcount,0x01U);+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x01U);memset64((u64*)table,_PAGE_INVALID,2*PTRS_PER_PTE);spin_lock_bh(&mm->context.lock);-list_add(&page->lru,&mm->context.pgtable_list);+list_add(&ptdesc->pt_list,&mm->context.pgtable_list);spin_unlock_bh(&mm->context.lock);}returntable;
@@ -309,9 +309,8 @@ static void page_table_release_check(struct page *page, void *table,voidpage_table_free(structmm_struct*mm,unsignedlong*table){unsignedintmask,bit,half;-structpage*page;+structptdesc*ptdesc=virt_to_ptdesc(table);-page=virt_to_page(table);if(!mm_alloc_pgste(mm)){/* Free 2K page table fragment of a 4K page */bit=((unsignedlong)table&~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
The page table members are now split out into their own ptdesc struct.
Remove them from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/linux/mm_types.h | 14 --------------
include/linux/pgtable.h | 3 ---
2 files changed, 17 deletions(-)
@@ -141,20 +141,6 @@ struct page {struct{/* Tail pages of compound page */unsignedlongcompound_head;/* Bit zero is set */};-struct{/* Page table pages */-unsignedlong_pt_pad_1;/* compound_head */-pgtable_tpmd_huge_pte;/* protected by page->ptl */-unsignedlong_pt_s390_gaddr;/* mapping */-union{-structmm_struct*pt_mm;/* x86 pgds only */-atomic_tpt_frag_refcount;/* powerpc */-};-#if ALLOC_SPLIT_PTLOCKS-spinlock_t*ptl;-#else-spinlock_tptl;-#endif-};struct{/* ZONE_DEVICE pages *//** @pgmap: Points to the hosting device page map. */structdev_pagemap*pgmap;
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/asm-generic/pgalloc.h | 62 +++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 25 deletions(-)
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
late_alloc() also uses the __get_free_pages() helper function. Convert
this to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/arm/include/asm/tlb.h | 12 +++++++-----
arch/arm/mm/mmu.c | 6 +++---
2 files changed, 10 insertions(+), 8 deletions(-)
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/arm64/include/asm/tlb.h | 14 ++++++++------
arch/arm64/mm/mmu.c | 7 ++++---
2 files changed, 12 insertions(+), 9 deletions(-)
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/loongarch/include/asm/pgalloc.h | 27 +++++++++++++++------------
arch/loongarch/mm/pgtable.c | 7 ++++---
2 files changed, 19 insertions(+), 15 deletions(-)
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/m68k/include/asm/mcf_pgalloc.h | 41 ++++++++++++++--------------
arch/m68k/include/asm/sun3_pgalloc.h | 8 +++---
arch/m68k/mm/motorola.c | 4 +--
3 files changed, 27 insertions(+), 26 deletions(-)
@@ -201,7 +201,7 @@ int free_pointer_table(void *table, int type)list_del(dp);mmu_page_dtor((void*)page);if(type==TABLE_PTE)-pgtable_pte_page_dtor(virt_to_page((void*)page));+pagetable_pte_dtor(virt_to_ptdesc((void*)page));free_page(page);return1;}elseif(ptable_list[type].next!=dp){
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/mips/include/asm/pgalloc.h | 31 +++++++++++++++++--------------
arch/mips/mm/pgtable.c | 7 ++++---
2 files changed, 21 insertions(+), 17 deletions(-)
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Palmer Dabbelt <redacted>
---
arch/riscv/include/asm/pgalloc.h | 8 ++++----
arch/riscv/mm/init.c | 16 ++++++----------
2 files changed, 10 insertions(+), 14 deletions(-)
Part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents. Also cleans up some spacing issues.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
---
arch/sh/include/asm/pgalloc.h | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
Part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents. Also cleans up some spacing issues.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/um/include/asm/pgalloc.h | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
@@ -53,7 +53,7 @@ Support of split page table lock by an architecture =================================================== There's no need in special enabling of PTE split page table lock: everything-required is done by pgtable_pte_page_ctor() and pgtable_pte_page_dtor(), which+required is done by pagetable_pte_ctor() and pagetable_pte_dtor(), which must be called on PTE table allocation / freeing. Make sure the architecture doesn't use slab allocator for page table
@@ -63,8 +63,8 @@ This field shares storage with page->ptl. PMD split lock only makes sense if you have more than two page table levels.-PMD split lock enabling requires pgtable_pmd_page_ctor() call on PMD table-allocation and pgtable_pmd_page_dtor() on freeing.+PMD split lock enabling requires pagetable_pmd_ctor() call on PMD table+allocation and pagetable_pmd_dtor() on freeing. Allocation usually happens in pmd_alloc_one(), freeing in pmd_free() and pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing
@@ -72,7 +72,7 @@ paths: i.e X86_PAE preallocate few PMDs on pgd_alloc(). With everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK.-NOTE: pgtable_pte_page_ctor() and pgtable_pmd_page_ctor() can fail -- it must+NOTE: pagetable_pte_ctor() and pagetable_pmd_ctor() can fail -- it must be handled properly. page->ptl
@@ -92,7 +92,7 @@ trick: split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access;-The spinlock_t allocated in pgtable_pte_page_ctor() for PTE table and in-pgtable_pmd_page_ctor() for PMD table.+The spinlock_t allocated in pagetable_pte_ctor() for PTE table and in+pagetable_pmd_ctor() for PMD table. Please, never access page->ptl directly -- use appropriate helper.
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/sparc/mm/init_64.c | 17 +++++++++--------
1 file changed, 9 insertions(+), 8 deletions(-)
On Mon, Jun 12, 2023 at 11:05 PM Vishal Moola (Oracle)
[off-list ref] wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Geert Uytterhoeven <geert@linux-m68k.org>
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
I don't think you can just apply this patch, as the new functions
were only introduced in [PATCH v4 05/34] of this series.
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:04:32
On Mon, Jun 12, 2023 at 02:03:50PM -0700, Vishal Moola (Oracle) wrote:
No folio equivalents for page type operations have been defined, so
define them for later folio conversions.
Also changes the Page##uname macros to take in const struct page* since
we only read the memory here.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:15:33
On Mon, Jun 12, 2023 at 02:03:51PM -0700, Vishal Moola (Oracle) wrote:
s390 uses page->index to keep track of page tables for the guest address
space. In an attempt to consolidate the usage of page fields in s390,
replace _pt_pad_2 with _pt_s390_gaddr to replace page->index in gmap.
This will help with the splitting of struct ptdesc from struct page, as
well as allow s390 to use _pt_frag_refcount for fragmented page table
tracking.
Since page->_pt_s390_gaddr aliases with mapping, ensure its set to NULL
before freeing the pages as well.
I'm looking at the final result and unless I've missed something, setting
of _pt_s390_gaddr to 0 is always followed by pagetable_free().
Can't we have pagetable_free() take care of zeroing _pt_s390_gaddr?
I think patch 16 ("s390: Convert various gmap functions to use ptdescs")
would be the right place for that.
Otherwise:
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
quoted hunk
This also reverts commit 7e25de77bc5ea ("s390/mm: use pmd_pgtable_page()
helper in __gmap_segment_gaddr()") which had s390 use
pmd_pgtable_page() to get a gmap page table, as pmd_pgtable_page()
should be used for more generic process page tables.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
arch/s390/mm/gmap.c | 56 +++++++++++++++++++++++++++-------------
include/linux/mm_types.h | 2 +-
2 files changed, 39 insertions(+), 19 deletions(-)
@@ -70,7 +70,7 @@ static struct gmap *gmap_alloc(unsigned long limit)page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)gotoout_free;-page->index=0;+page->_pt_s390_gaddr=0;list_add(&page->lru,&gmap->crst_list);table=page_to_virt(page);crst_table_init(table,etype);
@@ -187,16 +187,20 @@ static void gmap_free(struct gmap *gmap)if(!(gmap_is_shadow(gmap)&&gmap->removed))gmap_flush_tlb(gmap);/* Free all segment & region tables. */-list_for_each_entry_safe(page,next,&gmap->crst_list,lru)+list_for_each_entry_safe(page,next,&gmap->crst_list,lru){+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);+}gmap_radix_tree_free(&gmap->guest_to_host);gmap_radix_tree_free(&gmap->host_to_guest);/* Free additional data for a shadow gmap */if(gmap_is_shadow(gmap)){/* Free all page tables. */-list_for_each_entry_safe(page,next,&gmap->pt_list,lru)+list_for_each_entry_safe(page,next,&gmap->pt_list,lru){+page->_pt_s390_gaddr=0;page_table_free_pgste(page);+}gmap_rmap_radix_tree_free(&gmap->host_to_rmap);/* Release reference to the parent */gmap_put(gmap->parent);
@@ -318,12 +322,14 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,list_add(&page->lru,&gmap->crst_list);*table=__pa(new)|_REGION_ENTRY_LENGTH|(*table&_REGION_ENTRY_TYPE_MASK);-page->index=gaddr;+page->_pt_s390_gaddr=gaddr;page=NULL;}spin_unlock(&gmap->guest_table_lock);-if(page)+if(page){+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);+}return0;}
@@ -336,12 +342,14 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,staticunsignedlong__gmap_segment_gaddr(unsignedlong*entry){structpage*page;-unsignedlongoffset;+unsignedlongoffset,mask;offset=(unsignedlong)entry/sizeof(unsignedlong);offset=(offset&(PTRS_PER_PMD-1))*PMD_SIZE;-page=pmd_pgtable_page((pmd_t*)entry);-returnpage->index+offset;+mask=~(PTRS_PER_PMD*sizeof(pmd_t)-1);+page=virt_to_page((void*)((unsignedlong)entry&mask));++returnpage->_pt_s390_gaddr+offset;}/**
@@ -1467,6 +1479,7 @@ static void gmap_unshadow_r3t(struct gmap *sg, unsigned long raddr)/* Free region 3 table */page=phys_to_page(r3t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}
@@ -1495,6 +1508,7 @@ static void __gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr,/* Free region 3 table */page=phys_to_page(r3t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}}
@@ -1525,6 +1539,7 @@ static void gmap_unshadow_r2t(struct gmap *sg, unsigned long raddr)/* Free region 2 table */page=phys_to_page(r2t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}
@@ -1557,6 +1572,7 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,/* Free region 2 table */page=phys_to_page(r2t);list_del(&page->lru);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);}}
@@ -1762,9 +1778,9 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=r2t&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_r2t=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1814,6 +1830,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -1846,9 +1863,9 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=r3t&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_r3t=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1898,6 +1915,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -1930,9 +1948,9 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);if(!page)return-ENOMEM;-page->index=sgt&_REGION_ENTRY_ORIGIN;+page->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_sgt=page_to_phys(page);/* Install shadow region second table */spin_lock(&sg->guest_table_lock);
@@ -1982,6 +2000,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;__free_pages(page,CRST_ALLOC_ORDER);returnrc;}
@@ -2014,9 +2033,9 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,if(table&&!(*table&_SEGMENT_ENTRY_INVALID)){/* Shadow page tables are full pages (pte+pgste) */page=pfn_to_page(*table>>PAGE_SHIFT);-*pgt=page->index&~GMAP_SHADOW_FAKE_TABLE;+*pgt=page->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;*dat_protection=!!(*table&_SEGMENT_ENTRY_PROTECT);-*fake=!!(page->index&GMAP_SHADOW_FAKE_TABLE);+*fake=!!(page->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);rc=0;}else{rc=-EAGAIN;
@@ -2054,9 +2073,9 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,page=page_table_alloc_pgste(sg->mm);if(!page)return-ENOMEM;-page->index=pgt&_SEGMENT_ENTRY_ORIGIN;+page->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;if(fake)-page->index|=GMAP_SHADOW_FAKE_TABLE;+page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;s_pgt=page_to_phys(page);/* Install shadow page table */spin_lock(&sg->guest_table_lock);
@@ -2101,6 +2120,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);+page->_pt_s390_gaddr=0;page_table_free_pgste(page);returnrc;
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:22:19
On Mon, Jun 12, 2023 at 02:03:52PM -0700, Vishal Moola (Oracle) wrote:
s390 currently uses _refcount to identify fragmented page tables.
The page table struct already has a member pt_frag_refcount used by
powerpc, so have s390 use that instead of the _refcount field as well.
This improves the safety for _refcount and the page table tracking.
This also allows us to simplify the tracking since we can once again use
the lower byte of pt_frag_refcount instead of the upper byte of _refcount.
Signed-off-by: Vishal Moola (Oracle) <redacted>
One nit below, otherwise
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
* || ||
* || |+--- upper 2KB-pgtable is allocated
* || +---- lower 2KB-pgtable is allocated
* |+------- upper 2KB-pgtable is pending for removal
* +-------- lower 2KB-pgtable is pending for removal
*
- * (See commit 620b4e903179 ("s390: use _refcount for pgtables") on why
- * using _refcount is possible).
- *
* When 2KB-pgtable is allocated the corresponding AA bit is set to 1.
* The parent page is either:
* - added to mm_context_t::pgtable_list in case the second half of the
@@ -243,11 +240,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm) if (!list_empty(&mm->context.pgtable_list)) { page = list_first_entry(&mm->context.pgtable_list, struct page, lru);- mask = atomic_read(&page->_refcount) >> 24;+ mask = atomic_read(&page->pt_frag_refcount); /* * The pending removal bits must also be checked. * Failure to do so might lead to an impossible- * value of (i.e 0x13 or 0x23) written to _refcount.+ * value of (i.e 0x13 or 0x23) written to+ * pt_frag_refcount. * Such values violate the assumption that pending and * allocation bits are mutually exclusive, and the rest * of the code unrails as result. That could lead to
@@ -259,8 +257,8 @@ unsigned long *page_table_alloc(struct mm_struct *mm) bit = mask & 1; /* =1 -> second 2K */ if (bit) table += PTRS_PER_PTE;- atomic_xor_bits(&page->_refcount,- 0x01U << (bit + 24));+ atomic_xor_bits(&page->pt_frag_refcount,+ 0x01U << bit); list_del(&page->lru); } }
@@ -281,12 +279,12 @@ unsigned long *page_table_alloc(struct mm_struct *mm) table = (unsigned long *) page_to_virt(page); if (mm_alloc_pgste(mm)) { /* Return 4K page table with PGSTEs */- atomic_xor_bits(&page->_refcount, 0x03U << 24);+ atomic_xor_bits(&page->pt_frag_refcount, 0x03U); memset64((u64 *)table, _PAGE_INVALID, PTRS_PER_PTE); memset64((u64 *)table + PTRS_PER_PTE, 0, PTRS_PER_PTE); } else { /* Return the first 2K fragment of the page */- atomic_xor_bits(&page->_refcount, 0x01U << 24);+ atomic_xor_bits(&page->pt_frag_refcount, 0x01U); memset64((u64 *)table, _PAGE_INVALID, 2 * PTRS_PER_PTE); spin_lock_bh(&mm->context.lock); list_add(&page->lru, &mm->context.pgtable_list);
@@ -323,22 +321,19 @@ void page_table_free(struct mm_struct *mm, unsigned long *table) * will happen outside of the critical section from this * function or from __tlb_remove_table() */- mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, 0x11U << bit); if (mask & 0x03U) list_add(&page->lru, &mm->context.pgtable_list); else list_del(&page->lru); spin_unlock_bh(&mm->context.lock);- mask = atomic_xor_bits(&page->_refcount, 0x10U << (bit + 24));- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, 0x10U << bit); if (mask != 0x00U) return; half = 0x01U << bit; } else { half = 0x03U;- mask = atomic_xor_bits(&page->_refcount, 0x03U << 24);- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, 0x03U); } page_table_release_check(page, table, half, mask);
@@ -368,8 +363,7 @@ void page_table_free_rcu(struct mmu_gather *tlb, unsigned long *table, * outside of the critical section from __tlb_remove_table() or from * page_table_free() */- mask = atomic_xor_bits(&page->_refcount, 0x11U << (bit + 24));- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, 0x11U << bit); if (mask & 0x03U) list_add_tail(&page->lru, &mm->context.pgtable_list); else
@@ -391,14 +385,12 @@ void __tlb_remove_table(void *_table) return; case 0x01U: /* lower 2K of a 4K page table */ case 0x02U: /* higher 2K of a 4K page table */- mask = atomic_xor_bits(&page->_refcount, mask << (4 + 24));- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, mask << 4); if (mask != 0x00U) return; break; case 0x03U: /* 4K page table with pgstes */- mask = atomic_xor_bits(&page->_refcount, 0x03U << 24);- mask >>= 24;+ mask = atomic_xor_bits(&page->pt_frag_refcount, 0x03U); break; }
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:35:34
On Mon, Jun 12, 2023 at 02:03:53PM -0700, Vishal Moola (Oracle) wrote:
Currently, page table information is stored within struct page. As part
of simplifying struct page, create struct ptdesc for page table
information.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:48:48
On Mon, Jun 12, 2023 at 02:03:54PM -0700, Vishal Moola (Oracle) wrote:
quoted hunk
Introduce utility functions setting the foundation for ptdescs. These
will also assist in the splitting out of ptdesc from struct page.
Functions that focus on the descriptor are prefixed with ptdesc_* while
functions that focus on the pagetable are prefixed with pagetable_*.
pagetable_alloc() is defined to allocate new ptdesc pages as compound
pages. This is to standardize ptdescs by allowing for one allocation
and one free function, in contrast to 2 allocation and 2 free functions.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/asm-generic/tlb.h | 11 +++++++
include/linux/mm.h | 61 +++++++++++++++++++++++++++++++++++++++
include/linux/pgtable.h | 12 ++++++++
3 files changed, 84 insertions(+)
I think the order should be switched here to emphasize that primarily this
method allocates memory for page tables. How about
pagetable_alloc allocates memory for the page tables as well as a page
table descriptor that describes the allocated memory
+ *
+ * Return: The ptdesc describing the allocated page tables.
+ */
+static inline struct ptdesc *pagetable_alloc(gfp_t gfp, unsigned int order)
+{
+ struct page *page = alloc_pages(gfp | __GFP_COMP, order);
+
+ return page_ptdesc(page);
+}
+
+/**
+ * pagetable_free - Free pagetables
+ * @pt: The page table descriptor
+ *
+ * pagetable_free frees a page table descriptor as well as all page
+ * tables described by said ptdesc.
@@ -2992,6 +3048,11 @@ static inline void mark_page_reserved(struct page *page) adjust_managed_page_count(page, -1); }+static inline void free_reserved_ptdesc(struct ptdesc *pt)+{+ free_reserved_page(ptdesc_page(pt));+}+ /* * Default method to free all the __init memory into the buddy system. * The freed pages will be poisoned with pattern "poison" if it's within
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:51:54
On Mon, Jun 12, 2023 at 02:03:55PM -0700, Vishal Moola (Oracle) wrote:
Converts pmd_pgtable_page() to pmd_ptdesc() and all its callers. This
removes some direct accesses to struct page, working towards splitting
out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:52:20
On Mon, Jun 12, 2023 at 02:03:56PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:52:47
On Mon, Jun 12, 2023 at 02:03:57PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:53:18
On Mon, Jun 12, 2023 at 02:03:58PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:58:33
On Mon, Jun 12, 2023 at 02:03:59PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 13:59:52
On Mon, Jun 12, 2023 at 02:04:00PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:00:57
On Mon, Jun 12, 2023 at 02:04:01PM -0700, Vishal Moola (Oracle) wrote:
This removes some direct accesses to struct page, working towards
splitting out struct ptdesc from struct page.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:11:31
On Mon, Jun 12, 2023 at 02:04:02PM -0700, Vishal Moola (Oracle) wrote:
Creates pagetable_pte_ctor(), pagetable_pmd_ctor(), pagetable_pte_dtor(),
and pagetable_pmd_dtor() and make the original pgtable
constructor/destructors wrappers.
Nit: either "creates ... makes" or "create ... make"
I like the second form more.
This comment is more to patch 1 ("mm: Add PAGE_TYPE_OP folio functions")
It would be better to have _pgtable here, as "table" does not necessary
mean page table.
With PageType SetPageTable was fine, but with folio I think it should be
more explicit.
I'd add a third parameter to PAGE_TYPE_OPS for that.
@@ -246,15 +246,15 @@ static void destroy_contexts(mm_context_t *ctx)staticvoidpmd_frag_destroy(void*pmd_frag){intcount;-structpage*page;+structptdesc*ptdesc;-page=virt_to_page(pmd_frag);+ptdesc=virt_to_ptdesc(pmd_frag);/* drop all the pending references */count=((unsignedlong)pmd_frag&~PAGE_MASK)>>PMD_FRAG_SIZE_SHIFT;/* We allow PTE_FRAG_NR fragments from a PTE page */-if(atomic_sub_and_test(PMD_FRAG_NR-count,&page->pt_frag_refcount)){-pgtable_pmd_page_dtor(page);-__free_page(page);+if(atomic_sub_and_test(PMD_FRAG_NR-count,&ptdesc->pt_frag_refcount)){+pagetable_pmd_dtor(ptdesc);+pagetable_free(ptdesc);}}
@@ -18,15 +18,15 @@voidpte_frag_destroy(void*pte_frag){intcount;-structpage*page;+structptdesc*ptdesc;-page=virt_to_page(pte_frag);+ptdesc=virt_to_ptdesc(pte_frag);/* drop all the pending references */count=((unsignedlong)pte_frag&~PAGE_MASK)>>PTE_FRAG_SIZE_SHIFT;/* We allow PTE_FRAG_NR fragments from a PTE page */-if(atomic_sub_and_test(PTE_FRAG_NR-count,&page->pt_frag_refcount)){-pgtable_pte_page_dtor(page);-__free_page(page);+if(atomic_sub_and_test(PTE_FRAG_NR-count,&ptdesc->pt_frag_refcount)){+pagetable_pte_dtor(ptdesc);+pagetable_free(ptdesc);}}
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:28:08
On Mon, Jun 12, 2023 at 02:04:04PM -0700, Vishal Moola (Oracle) wrote:
In order to split struct ptdesc from struct page, convert various
functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
Nit: *get_free_page*()
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
More importantly, get_free_pages() ensures a page won't be allocated from
HIGHMEM, and for 32-bits this is a must.
@@ -232,16 +235,21 @@ static int preallocate_pmds(struct mm_struct *mm, pmd_t *pmds[], int count)gfp&=~__GFP_ACCOUNT;for(i=0;i<count;i++){-pmd_t*pmd=(pmd_t*)__get_free_page(gfp);-if(!pmd)+pmd_t*pmd=NULL;+structptdesc*ptdesc=pagetable_alloc(gfp,0);++if(!ptdesc)failed=true;-if(pmd&&!pgtable_pmd_page_ctor(virt_to_page(pmd))){-free_page((unsignedlong)pmd);-pmd=NULL;+if(ptdesc&&!pagetable_pmd_ctor(ptdesc)){+pagetable_free(ptdesc);+ptdesc=NULL;failed=true;}-if(pmd)+if(ptdesc){mm_inc_nr_pmds(mm);+pmd=ptdesc_address(ptdesc);+}+pmds[i]=pmd;}
@@ -830,7 +838,7 @@ int pud_free_pmd_page(pud_t *pud, unsigned long addr)free_page((unsignedlong)pmd_sv);-pgtable_pmd_page_dtor(virt_to_page(pmd));+pagetable_pmd_dtor(virt_to_ptdesc(pmd));free_page((unsignedlong)pmd);return1;
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:29:37
On Mon, Jun 12, 2023 at 02:04:05PM -0700, Vishal Moola (Oracle) wrote:
In order to split struct ptdesc from struct page, convert various
functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
With folding
ptdesc->_pt_s390_gaddr = 0;
into pagetable_free()
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
@@ -67,12 +67,12 @@ static struct gmap *gmap_alloc(unsigned long limit)spin_lock_init(&gmap->guest_table_lock);spin_lock_init(&gmap->shadow_lock);refcount_set(&gmap->ref_count,1);-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)gotoout_free;-page->_pt_s390_gaddr=0;-list_add(&page->lru,&gmap->crst_list);-table=page_to_virt(page);+ptdesc->_pt_s390_gaddr=0;+list_add(&ptdesc->pt_list,&gmap->crst_list);+table=ptdesc_to_virt(ptdesc);crst_table_init(table,etype);gmap->table=table;gmap->asce=atype|_ASCE_TABLE_LENGTH|
@@ -181,25 +181,25 @@ static void gmap_rmap_radix_tree_free(struct radix_tree_root *root)*/staticvoidgmap_free(structgmap*gmap){-structpage*page,*next;+structptdesc*ptdesc,*next;/* Flush tlb of all gmaps (if not already done for shadows) */if(!(gmap_is_shadow(gmap)&&gmap->removed))gmap_flush_tlb(gmap);/* Free all segment & region tables. */-list_for_each_entry_safe(page,next,&gmap->crst_list,lru){-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+list_for_each_entry_safe(ptdesc,next,&gmap->crst_list,pt_list){+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}gmap_radix_tree_free(&gmap->guest_to_host);gmap_radix_tree_free(&gmap->host_to_guest);/* Free additional data for a shadow gmap */if(gmap_is_shadow(gmap)){-/* Free all page tables. */-list_for_each_entry_safe(page,next,&gmap->pt_list,lru){-page->_pt_s390_gaddr=0;-page_table_free_pgste(page);+/* Free all ptdesc tables. */+list_for_each_entry_safe(ptdesc,next,&gmap->pt_list,pt_list){+ptdesc->_pt_s390_gaddr=0;+page_table_free_pgste(ptdesc_page(ptdesc));}gmap_rmap_radix_tree_free(&gmap->host_to_rmap);/* Release reference to the parent */
@@ -308,27 +308,27 @@ EXPORT_SYMBOL_GPL(gmap_get_enabled);staticintgmap_alloc_table(structgmap*gmap,unsignedlong*table,unsignedlonginit,unsignedlonggaddr){-structpage*page;+structptdesc*ptdesc;unsignedlong*new;/* since we dont free the gmap table until gmap_free we can unlock */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-new=page_to_virt(page);+new=ptdesc_to_virt(ptdesc);crst_table_init(new,init);spin_lock(&gmap->guest_table_lock);if(*table&_REGION_ENTRY_INVALID){-list_add(&page->lru,&gmap->crst_list);+list_add(&ptdesc->pt_list,&gmap->crst_list);*table=__pa(new)|_REGION_ENTRY_LENGTH|(*table&_REGION_ENTRY_TYPE_MASK);-page->_pt_s390_gaddr=gaddr;-page=NULL;+ptdesc->_pt_s390_gaddr=gaddr;+ptdesc=NULL;}spin_unlock(&gmap->guest_table_lock);-if(page){-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+if(ptdesc){+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}return0;}
@@ -341,15 +341,15 @@ static int gmap_alloc_table(struct gmap *gmap, unsigned long *table,*/staticunsignedlong__gmap_segment_gaddr(unsignedlong*entry){-structpage*page;+structptdesc*ptdesc;unsignedlongoffset,mask;offset=(unsignedlong)entry/sizeof(unsignedlong);offset=(offset&(PTRS_PER_PMD-1))*PMD_SIZE;mask=~(PTRS_PER_PMD*sizeof(pmd_t)-1);-page=virt_to_page((void*)((unsignedlong)entry&mask));+ptdesc=virt_to_ptdesc((void*)((unsignedlong)entry&mask));-returnpage->_pt_s390_gaddr+offset;+returnptdesc->_pt_s390_gaddr+offset;}/**
@@ -1345,6 +1345,7 @@ static void gmap_unshadow_pgt(struct gmap *sg, unsigned long raddr)unsignedlong*ste;phys_addr_tsto,pgt;structpage*page;+structptdesc*ptdesc;BUG_ON(!gmap_is_shadow(sg));ste=gmap_table_walk(sg,raddr,1);/* get segment pointer */
@@ -1571,9 +1593,11 @@ static void __gmap_unshadow_r1t(struct gmap *sg, unsigned long raddr,r1t[i]=_REGION1_ENTRY_EMPTY;/* Free region 2 table */page=phys_to_page(r2t);-list_del(&page->lru);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);++ptdesc=page_ptdesc(page);+list_del(&ptdesc->pt_list);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);}}
@@ -1770,18 +1794,18 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_r2t;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg));/* Allocate a shadow region second table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=r2t&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_r2t=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_r2t=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,4);/* get region-1 pointer */
@@ -1802,7 +1826,7 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,_REGION_ENTRY_TYPE_R1|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=(r2t&_REGION_ENTRY_PROTECT);-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -1830,8 +1854,8 @@ int gmap_shadow_r2t(struct gmap *sg, unsigned long saddr, unsigned long r2t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_r2t);
@@ -1855,18 +1879,18 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_r3t;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg));/* Allocate a shadow region second table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=r3t&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_r3t=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_r3t=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,3);/* get region-2 pointer */
@@ -1887,7 +1911,7 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,_REGION_ENTRY_TYPE_R2|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=(r3t&_REGION_ENTRY_PROTECT);-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -1915,8 +1939,8 @@ int gmap_shadow_r3t(struct gmap *sg, unsigned long saddr, unsigned long r3t,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_r3t);
@@ -1940,18 +1964,18 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,unsignedlongraddr,origin,offset,len;unsignedlong*table;phys_addr_ts_sgt;-structpage*page;+structptdesc*ptdesc;intrc;BUG_ON(!gmap_is_shadow(sg)||(sgt&_REGION3_ENTRY_LARGE));/* Allocate a shadow segment table */-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=sgt&_REGION_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_sgt=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_sgt=page_to_phys(ptdesc_page(ptdesc));/* Install shadow region second table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,2);/* get region-3 pointer */
@@ -1972,7 +1996,7 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,_REGION_ENTRY_TYPE_R3|_REGION_ENTRY_INVALID;if(sg->edat_level>=1)*table|=sgt&_REGION_ENTRY_PROTECT;-list_add(&page->lru,&sg->crst_list);+list_add(&ptdesc->pt_list,&sg->crst_list);if(fake){/* nothing to protect for fake tables */*table&=~_REGION_ENTRY_INVALID;
@@ -2000,8 +2024,8 @@ int gmap_shadow_sgt(struct gmap *sg, unsigned long saddr, unsigned long sgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-__free_pages(page,CRST_ALLOC_ORDER);+ptdesc->_pt_s390_gaddr=0;+pagetable_free(ptdesc);returnrc;}EXPORT_SYMBOL_GPL(gmap_shadow_sgt);
@@ -2024,8 +2048,9 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,int*fake){unsignedlong*table;-structpage*page;intrc;+structpage*page;+structptdesc*ptdesc;BUG_ON(!gmap_is_shadow(sg));spin_lock(&sg->guest_table_lock);
@@ -2033,9 +2058,10 @@ int gmap_shadow_pgt_lookup(struct gmap *sg, unsigned long saddr,if(table&&!(*table&_SEGMENT_ENTRY_INVALID)){/* Shadow page tables are full pages (pte+pgste) */page=pfn_to_page(*table>>PAGE_SHIFT);-*pgt=page->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;+ptdesc=page_ptdesc(page);+*pgt=ptdesc->_pt_s390_gaddr&~GMAP_SHADOW_FAKE_TABLE;*dat_protection=!!(*table&_SEGMENT_ENTRY_PROTECT);-*fake=!!(page->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);+*fake=!!(ptdesc->_pt_s390_gaddr&GMAP_SHADOW_FAKE_TABLE);rc=0;}else{rc=-EAGAIN;
@@ -2064,19 +2090,19 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,{unsignedlongraddr,origin;unsignedlong*table;-structpage*page;+structptdesc*ptdesc;phys_addr_ts_pgt;intrc;BUG_ON(!gmap_is_shadow(sg)||(pgt&_SEGMENT_ENTRY_LARGE));/* Allocate a shadow page table */-page=page_table_alloc_pgste(sg->mm);-if(!page)+ptdesc=page_ptdesc(page_table_alloc_pgste(sg->mm));+if(!ptdesc)return-ENOMEM;-page->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;+ptdesc->_pt_s390_gaddr=pgt&_SEGMENT_ENTRY_ORIGIN;if(fake)-page->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;-s_pgt=page_to_phys(page);+ptdesc->_pt_s390_gaddr|=GMAP_SHADOW_FAKE_TABLE;+s_pgt=page_to_phys(ptdesc_page(ptdesc));/* Install shadow page table */spin_lock(&sg->guest_table_lock);table=gmap_table_walk(sg,saddr,1);/* get segment pointer */
@@ -2094,7 +2120,7 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,/* mark as invalid as long as the parent table is not protected */*table=(unsignedlong)s_pgt|_SEGMENT_ENTRY|(pgt&_SEGMENT_ENTRY_PROTECT)|_SEGMENT_ENTRY_INVALID;-list_add(&page->lru,&sg->pt_list);+list_add(&ptdesc->pt_list,&sg->pt_list);if(fake){/* nothing to protect for fake tables */*table&=~_SEGMENT_ENTRY_INVALID;
@@ -2120,8 +2146,8 @@ int gmap_shadow_pgt(struct gmap *sg, unsigned long saddr, unsigned long pgt,returnrc;out_free:spin_unlock(&sg->guest_table_lock);-page->_pt_s390_gaddr=0;-page_table_free_pgste(page);+ptdesc->_pt_s390_gaddr=0;+page_table_free_pgste(ptdesc_page(ptdesc));returnrc;}
@@ -2863,10 +2889,10 @@ int s390_replace_asce(struct gmap *gmap)if((gmap->asce&_ASCE_TYPE_MASK)==_ASCE_TYPE_SEGMENT)return-EINVAL;-page=alloc_pages(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL_ACCOUNT,CRST_ALLOC_ORDER);+if(!ptdesc)return-ENOMEM;-table=page_to_virt(page);+table=ptdesc_to_virt(ptdesc);memcpy(table,gmap->table,1UL<<(CRST_ALLOC_ORDER+PAGE_SHIFT));/*
@@ -2875,7 +2901,7 @@ int s390_replace_asce(struct gmap *gmap)*itwillbefreedwhentheVMistorndown.*/spin_lock(&gmap->guest_table_lock);-list_add(&page->lru,&gmap->crst_list);+list_add(&ptdesc->pt_list,&gmap->crst_list);spin_unlock(&gmap->guest_table_lock);/* Set new table origin while preserving existing ASCE control bits */
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:47:27
On Mon, Jun 12, 2023 at 02:04:06PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
@@ -140,21 +140,21 @@ static inline unsigned int atomic_xor_bits(atomic_t *v, unsigned int bits)structpage*page_table_alloc_pgste(structmm_struct*mm){-structpage*page;+structptdesc*ptdesc;u64*table;-page=alloc_page(GFP_KERNEL);-if(page){-table=(u64*)page_to_virt(page);+ptdesc=pagetable_alloc(GFP_KERNEL,0);+if(ptdesc){+table=(u64*)ptdesc_to_virt(ptdesc);memset64(table,_PAGE_INVALID,PTRS_PER_PTE);memset64(table+PTRS_PER_PTE,0,PTRS_PER_PTE);}-returnpage;+returnptdesc_page(ptdesc);}voidpage_table_free_pgste(structpage*page){-__free_page(page);+pagetable_free(page_ptdesc(page));}#endif /* CONFIG_PGSTE */
@@ -230,7 +230,7 @@ void page_table_free_pgste(struct page *page)unsignedlong*page_table_alloc(structmm_struct*mm){unsignedlong*table;-structpage*page;+structptdesc*ptdesc;unsignedintmask,bit;/* Try to get a fragment of a 4K page as a 2K page table */
@@ -238,9 +238,9 @@ unsigned long *page_table_alloc(struct mm_struct *mm)table=NULL;spin_lock_bh(&mm->context.lock);if(!list_empty(&mm->context.pgtable_list)){-page=list_first_entry(&mm->context.pgtable_list,-structpage,lru);-mask=atomic_read(&page->pt_frag_refcount);+ptdesc=list_first_entry(&mm->context.pgtable_list,+structptdesc,pt_list);+mask=atomic_read(&ptdesc->pt_frag_refcount);/**Thependingremovalbitsmustalsobechecked.*Failuretodosomightleadtoanimpossible
@@ -253,13 +253,13 @@ unsigned long *page_table_alloc(struct mm_struct *mm)*/mask=(mask|(mask>>4))&0x03U;if(mask!=0x03U){-table=(unsignedlong*)page_to_virt(page);+table=(unsignedlong*)ptdesc_to_virt(ptdesc);bit=mask&1;/* =1 -> second 2K */if(bit)table+=PTRS_PER_PTE;-atomic_xor_bits(&page->pt_frag_refcount,+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x01U<<bit);-list_del(&page->lru);+list_del(&ptdesc->pt_list);}}spin_unlock_bh(&mm->context.lock);
@@ -267,27 +267,27 @@ unsigned long *page_table_alloc(struct mm_struct *mm)returntable;}/* Allocate a fresh page */-page=alloc_page(GFP_KERNEL);-if(!page)+ptdesc=pagetable_alloc(GFP_KERNEL,0);+if(!ptdesc)returnNULL;-if(!pgtable_pte_page_ctor(page)){-__free_page(page);+if(!pagetable_pte_ctor(ptdesc)){+pagetable_free(ptdesc);returnNULL;}-arch_set_page_dat(page,0);+arch_set_page_dat(ptdesc_page(ptdesc),0);/* Initialize page table */-table=(unsignedlong*)page_to_virt(page);+table=(unsignedlong*)ptdesc_to_virt(ptdesc);if(mm_alloc_pgste(mm)){/* Return 4K page table with PGSTEs */-atomic_xor_bits(&page->pt_frag_refcount,0x03U);+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x03U);memset64((u64*)table,_PAGE_INVALID,PTRS_PER_PTE);memset64((u64*)table+PTRS_PER_PTE,0,PTRS_PER_PTE);}else{/* Return the first 2K fragment of the page */-atomic_xor_bits(&page->pt_frag_refcount,0x01U);+atomic_xor_bits(&ptdesc->pt_frag_refcount,0x01U);memset64((u64*)table,_PAGE_INVALID,2*PTRS_PER_PTE);spin_lock_bh(&mm->context.lock);-list_add(&page->lru,&mm->context.pgtable_list);+list_add(&ptdesc->pt_list,&mm->context.pgtable_list);spin_unlock_bh(&mm->context.lock);}returntable;
@@ -309,9 +309,8 @@ static void page_table_release_check(struct page *page, void *table,voidpage_table_free(structmm_struct*mm,unsignedlong*table){unsignedintmask,bit,half;-structpage*page;+structptdesc*ptdesc=virt_to_ptdesc(table);-page=virt_to_page(table);if(!mm_alloc_pgste(mm)){/* Free 2K page table fragment of a 4K page */bit=((unsignedlong)table&~PAGE_MASK)/(PTRS_PER_PTE*sizeof(pte_t));
@@ -141,20 +141,6 @@ struct page {struct{/* Tail pages of compound page */unsignedlongcompound_head;/* Bit zero is set */};-struct{/* Page table pages */-unsignedlong_pt_pad_1;/* compound_head */-pgtable_tpmd_huge_pte;/* protected by page->ptl */-unsignedlong_pt_s390_gaddr;/* mapping */-union{-structmm_struct*pt_mm;/* x86 pgds only */-atomic_tpt_frag_refcount;/* powerpc */-};-#if ALLOC_SPLIT_PTLOCKS-spinlock_t*ptl;-#else-spinlock_tptl;-#endif-};struct{/* ZONE_DEVICE pages *//** @pgmap: Points to the hosting device page map. */structdev_pagemap*pgmap;
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 14:59:59
On Mon, Jun 12, 2023 at 02:04:08PM -0700, Vishal Moola (Oracle) wrote:
quoted hunk
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
---
include/asm-generic/pgalloc.h | 62 +++++++++++++++++++++--------------
1 file changed, 37 insertions(+), 25 deletions(-)
@@ -76,7 +80,7 @@ static inline pgtable_t __pte_alloc_one(struct mm_struct *mm, gfp_t gfp) * pte_alloc_one - allocate a page for PTE-level user page table * @mm: the mm_struct of the current context *- * Allocates a page and runs the pgtable_pte_page_ctor().+ * Allocates a ptdesc and runs the pagetable_pte_ctor().
Allocates memory for page table and ptdesc
*
* Return: `struct page` initialized as page table or %NULL on error
@@ -110,7 +116,7 @@ static inline void pte_free(struct mm_struct *mm, struct page *pte_page) * pmd_alloc_one - allocate a page for PMD-level page table * @mm: the mm_struct of the current context *- * Allocates a page and runs the pgtable_pmd_page_ctor().+ * Allocates a ptdesc and runs the pagetable_pmd_ctor().
Allocate memory for page table and ptdesc
quoted hunk
* Allocations use %GFP_PGTABLE_USER in user context and
* %GFP_PGTABLE_KERNEL in kernel context.
*
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:06:39
On Mon, Jun 12, 2023 at 02:04:09PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
late_alloc() also uses the __get_free_pages() helper function. Convert
this to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
One comment below.
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:07:34
On Mon, Jun 12, 2023 at 02:04:10PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:08:38
On Mon, Jun 12, 2023 at 02:04:11PM -0700, Vishal Moola (Oracle) wrote:
Part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Guo Ren <guoren@kernel.org>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:10:21
On Mon, Jun 12, 2023 at 02:04:13PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:13:31
On Mon, Jun 12, 2023 at 02:04:14PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
One comment below
@@ -201,7 +201,7 @@ int free_pointer_table(void *table, int type)list_del(dp);mmu_page_dtor((void*)page);if(type==TABLE_PTE)-pgtable_pte_page_dtor(virt_to_page((void*)page));+pagetable_pte_dtor(virt_to_ptdesc((void*)page));free_page(page);return1;}elseif(ptable_list[type].next!=dp){
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:17:02
On Mon, Jun 12, 2023 at 02:04:15PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:19:32
On Mon, Jun 12, 2023 at 02:04:18PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Some of the functions use the *get*page*() helper functions. Convert
these to use pagetable_alloc() and ptdesc_address() instead to help
standardize page tables further.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Acked-by: Palmer Dabbelt <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:20:05
On Mon, Jun 12, 2023 at 02:04:19PM -0700, Vishal Moola (Oracle) wrote:
Part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents. Also cleans up some spacing issues.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:20:47
On Mon, Jun 12, 2023 at 02:04:20PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:22:07
On Mon, Jun 12, 2023 at 02:04:22PM -0700, Vishal Moola (Oracle) wrote:
Part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents. Also cleans up some spacing issues.
Signed-off-by: Vishal Moola (Oracle) <redacted>
From: Mike Rapoport <rppt@kernel.org> Date: 2023-06-14 15:24:15
On Mon, Jun 12, 2023 at 02:04:23PM -0700, Vishal Moola (Oracle) wrote:
These functions are no longer necessary. Remove them and cleanup
Documentation referencing them.
Signed-off-by: Vishal Moola (Oracle) <redacted>
I've found one stale reference in riscv:
$ git grep -n pgtable_pmd_page_ctor
arch/riscv/mm/init.c:440: BUG_ON(!vaddr || !pgtable_pmd_page_ctor(virt_to_page(vaddr)));
Otherwise
Acked-by: Mike Rapoport (IBM) <rppt@kernel.org>
@@ -53,7 +53,7 @@ Support of split page table lock by an architecture =================================================== There's no need in special enabling of PTE split page table lock: everything-required is done by pgtable_pte_page_ctor() and pgtable_pte_page_dtor(), which+required is done by pagetable_pte_ctor() and pagetable_pte_dtor(), which must be called on PTE table allocation / freeing. Make sure the architecture doesn't use slab allocator for page table
@@ -63,8 +63,8 @@ This field shares storage with page->ptl. PMD split lock only makes sense if you have more than two page table levels.-PMD split lock enabling requires pgtable_pmd_page_ctor() call on PMD table-allocation and pgtable_pmd_page_dtor() on freeing.+PMD split lock enabling requires pagetable_pmd_ctor() call on PMD table+allocation and pagetable_pmd_dtor() on freeing. Allocation usually happens in pmd_alloc_one(), freeing in pmd_free() and pmd_free_tlb(), but make sure you cover all PMD table allocation / freeing
@@ -72,7 +72,7 @@ paths: i.e X86_PAE preallocate few PMDs on pgd_alloc(). With everything in place you can set CONFIG_ARCH_ENABLE_SPLIT_PMD_PTLOCK.-NOTE: pgtable_pte_page_ctor() and pgtable_pmd_page_ctor() can fail -- it must+NOTE: pagetable_pte_ctor() and pagetable_pmd_ctor() can fail -- it must be handled properly. page->ptl
@@ -92,7 +92,7 @@ trick: split lock with enabled DEBUG_SPINLOCK or DEBUG_LOCK_ALLOC, but costs one more cache line for indirect access;-The spinlock_t allocated in pgtable_pte_page_ctor() for PTE table and in-pgtable_pmd_page_ctor() for PMD table.+The spinlock_t allocated in pagetable_pte_ctor() for PTE table and in+pagetable_pmd_ctor() for PMD table. Please, never access page->ptl directly -- use appropriate helper.
On Mon, Jun 12, 2023 at 02:04:10PM -0700, Vishal Moola (Oracle) wrote:
As part of the conversions to replace pgtable constructor/destructors with
ptdesc equivalents, convert various page table functions to use ptdescs.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Currently, page table information is stored within struct page. As part
of simplifying struct page, create struct ptdesc for page table
information.
Signed-off-by: Vishal Moola (Oracle) <redacted>
Vishal, as I think you have already guessed, your ptdesc series and
my pte_free_defer() "mm: free retracted page table by RCU" series are
on a collision course.
Probably just trivial collisions in most architectures, which either
of us can easily adjust to the other; powerpc likely to be more awkward,
but fairly easily resolved; s390 quite a problem.
I've so far been unable to post a v2 of my series (and powerpc and s390
were stupidly wrong in the v1), because a good s390 patch is not yet
decided - Gerald Schaefer and I are currently working on that, on the
s390 list (I took off most Ccs until we are settled and I can post v2).
As you have no doubt found yourself, s390 has sophisticated handling of
free half-pages already, and I need to add rcu_head usage in there too:
it's tricky to squeeze it all in, and ptdesc does not appear to help us
in any way (though mostly it's just changing some field names, okay).
If ptdesc were actually allowing a flexible structure which architectures
could add into, that would (in some future) be nice; but of course at
present it's still fitting it all into one struct page, and mandating
new restrictions which just make an architecture's job harder.
Some notes on problematic fields below FYI.
I shall be needing struct rcu_head rcu_head (or pt_rcu_head or whatever,
if you prefer) in this union too. Sharing the lru or pt_list with rcu_head
is what's difficult to get right and efficient on s390 - and if ptdesc gave
us an independent rcu_head for each page table, that would be a blessing!
but sadly not, it still has to squeeze into a struct page.
+ struct {
+ unsigned long _pt_pad_1;
+ pgtable_t pmd_huge_pte;
+ };
+ };
+ unsigned long _pt_s390_gaddr;
+
+ union {
+ struct mm_struct *pt_mm;
+ atomic_t pt_frag_refcount;
Whether s390 will want pt_mm is not yet decided: I want to use it,
Gerald prefers to go without it; but if we do end up using it,
then pt_frag_refcount is a luxury we would have to give up.
s390 does very well already with its _refcount tricks, and I'd expect
powerpc's simpler but more wasteful implementation to work as well
with _refcount too - I know that a few years back, powerpc did misuse
_refcount (it did not allow for speculative accesses, thought it had
sole ownership of that field); but s390 copes well with that, and I
expect powerpc can do so too, without the luxury of pt_frag_refcount.
But I've no desire to undo powerpc's use of pt_frag_refcount:
just warning that we may want to undo any use of it in s390.
I thought I had more issues to mention, probably Gerald will
remind me of a whole new unexplored dimension! gmap perhaps.
Hugh
+ };
+
+#if ALLOC_SPLIT_PTLOCKS
+ spinlock_t *ptl;
+#else
+ spinlock_t ptl;
+#endif
+};
+
+#define TABLE_MATCH(pg, pt) \
+ static_assert(offsetof(struct page, pg) == offsetof(struct ptdesc, pt))
+TABLE_MATCH(flags, __page_flags);
+TABLE_MATCH(compound_head, pt_list);
+TABLE_MATCH(compound_head, _pt_pad_1);
+TABLE_MATCH(pmd_huge_pte, pmd_huge_pte);
+TABLE_MATCH(mapping, _pt_s390_gaddr);
+TABLE_MATCH(pt_mm, pt_mm);
+TABLE_MATCH(ptl, ptl);
+#undef TABLE_MATCH
+static_assert(sizeof(struct ptdesc) <= sizeof(struct page));
+
/*
* No-op macros that just return the current protection value. Defined here
* because these macros can be used even if CONFIG_MMU is not defined.
--
2.40.1