[PATCH 1/4] mm: Move ioremap page table mapping function to mm/
Christophe Leroy
christophe.leroy at c-s.fr
Tue Jun 11 15:24:17 AEST 2019
Le 10/06/2019 à 06:38, Nicholas Piggin a écrit :
> ioremap_page_range is a generic function to create a kernel virtual
> mapping, move it to mm/vmalloc.c and rename it vmap_range.
>
> For clarity with this move, also:
> - Rename vunmap_page_range (vmap_range's inverse) to vunmap_range.
> - Rename vmap_page_range (which takes a page array) to vmap_pages.
Maybe it would be easier to follow the change if the name change was
done in another patch than the move.
>
> Signed-off-by: Nicholas Piggin <npiggin at gmail.com>
> ---
>
> Fixed up the arm64 compile errors, fixed a few bugs, and tidied
> things up a bit more.
>
> Have tested powerpc and x86 but not arm64, would appreciate a review
> and test of the arm64 patch if possible.
>
> include/linux/vmalloc.h | 3 +
> lib/ioremap.c | 173 +++---------------------------
> mm/vmalloc.c | 228 ++++++++++++++++++++++++++++++++++++----
> 3 files changed, 229 insertions(+), 175 deletions(-)
>
> diff --git a/include/linux/vmalloc.h b/include/linux/vmalloc.h
> index 51e131245379..812bea5866d6 100644
> --- a/include/linux/vmalloc.h
> +++ b/include/linux/vmalloc.h
> @@ -147,6 +147,9 @@ extern struct vm_struct *find_vm_area(const void *addr);
> extern int map_vm_area(struct vm_struct *area, pgprot_t prot,
> struct page **pages);
> #ifdef CONFIG_MMU
> +extern int vmap_range(unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift);
Drop extern keyword here.
As checkpatch tells you, 'CHECK:AVOID_EXTERNS: extern prototypes should
be avoided in .h files'
Christophe
> extern int map_kernel_range_noflush(unsigned long start, unsigned long size,
> pgprot_t prot, struct page **pages);
> extern void unmap_kernel_range_noflush(unsigned long addr, unsigned long size);
> diff --git a/lib/ioremap.c b/lib/ioremap.c
> index 063213685563..e13946da8ec3 100644
> --- a/lib/ioremap.c
> +++ b/lib/ioremap.c
> @@ -58,165 +58,24 @@ static inline int ioremap_pud_enabled(void) { return 0; }
> static inline int ioremap_pmd_enabled(void) { return 0; }
> #endif /* CONFIG_HAVE_ARCH_HUGE_VMAP */
>
> -static int ioremap_pte_range(pmd_t *pmd, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> -{
> - pte_t *pte;
> - u64 pfn;
> -
> - pfn = phys_addr >> PAGE_SHIFT;
> - pte = pte_alloc_kernel(pmd, addr);
> - if (!pte)
> - return -ENOMEM;
> - do {
> - BUG_ON(!pte_none(*pte));
> - set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
> - pfn++;
> - } while (pte++, addr += PAGE_SIZE, addr != end);
> - return 0;
> -}
> -
> -static int ioremap_try_huge_pmd(pmd_t *pmd, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr,
> - pgprot_t prot)
> -{
> - if (!ioremap_pmd_enabled())
> - return 0;
> -
> - if ((end - addr) != PMD_SIZE)
> - return 0;
> -
> - if (!IS_ALIGNED(phys_addr, PMD_SIZE))
> - return 0;
> -
> - if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
> - return 0;
> -
> - return pmd_set_huge(pmd, phys_addr, prot);
> -}
> -
> -static inline int ioremap_pmd_range(pud_t *pud, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> -{
> - pmd_t *pmd;
> - unsigned long next;
> -
> - pmd = pmd_alloc(&init_mm, pud, addr);
> - if (!pmd)
> - return -ENOMEM;
> - do {
> - next = pmd_addr_end(addr, end);
> -
> - if (ioremap_try_huge_pmd(pmd, addr, next, phys_addr, prot))
> - continue;
> -
> - if (ioremap_pte_range(pmd, addr, next, phys_addr, prot))
> - return -ENOMEM;
> - } while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
> - return 0;
> -}
> -
> -static int ioremap_try_huge_pud(pud_t *pud, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr,
> - pgprot_t prot)
> -{
> - if (!ioremap_pud_enabled())
> - return 0;
> -
> - if ((end - addr) != PUD_SIZE)
> - return 0;
> -
> - if (!IS_ALIGNED(phys_addr, PUD_SIZE))
> - return 0;
> -
> - if (pud_present(*pud) && !pud_free_pmd_page(pud, addr))
> - return 0;
> -
> - return pud_set_huge(pud, phys_addr, prot);
> -}
> -
> -static inline int ioremap_pud_range(p4d_t *p4d, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> -{
> - pud_t *pud;
> - unsigned long next;
> -
> - pud = pud_alloc(&init_mm, p4d, addr);
> - if (!pud)
> - return -ENOMEM;
> - do {
> - next = pud_addr_end(addr, end);
> -
> - if (ioremap_try_huge_pud(pud, addr, next, phys_addr, prot))
> - continue;
> -
> - if (ioremap_pmd_range(pud, addr, next, phys_addr, prot))
> - return -ENOMEM;
> - } while (pud++, phys_addr += (next - addr), addr = next, addr != end);
> - return 0;
> -}
> -
> -static int ioremap_try_huge_p4d(p4d_t *p4d, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr,
> - pgprot_t prot)
> -{
> - if (!ioremap_p4d_enabled())
> - return 0;
> -
> - if ((end - addr) != P4D_SIZE)
> - return 0;
> -
> - if (!IS_ALIGNED(phys_addr, P4D_SIZE))
> - return 0;
> -
> - if (p4d_present(*p4d) && !p4d_free_pud_page(p4d, addr))
> - return 0;
> -
> - return p4d_set_huge(p4d, phys_addr, prot);
> -}
> -
> -static inline int ioremap_p4d_range(pgd_t *pgd, unsigned long addr,
> - unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> -{
> - p4d_t *p4d;
> - unsigned long next;
> -
> - p4d = p4d_alloc(&init_mm, pgd, addr);
> - if (!p4d)
> - return -ENOMEM;
> - do {
> - next = p4d_addr_end(addr, end);
> -
> - if (ioremap_try_huge_p4d(p4d, addr, next, phys_addr, prot))
> - continue;
> -
> - if (ioremap_pud_range(p4d, addr, next, phys_addr, prot))
> - return -ENOMEM;
> - } while (p4d++, phys_addr += (next - addr), addr = next, addr != end);
> - return 0;
> -}
> -
> int ioremap_page_range(unsigned long addr,
> unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> {
> - pgd_t *pgd;
> - unsigned long start;
> - unsigned long next;
> - int err;
> -
> - might_sleep();
> - BUG_ON(addr >= end);
> -
> - start = addr;
> - pgd = pgd_offset_k(addr);
> - do {
> - next = pgd_addr_end(addr, end);
> - err = ioremap_p4d_range(pgd, addr, next, phys_addr, prot);
> - if (err)
> - break;
> - } while (pgd++, phys_addr += (next - addr), addr = next, addr != end);
> -
> - flush_cache_vmap(start, end);
> + unsigned int max_page_shift = PAGE_SHIFT;
> +
> + /*
> + * Due to the max_page_shift parameter to vmap_range, platforms must
> + * enable all smaller sizes to take advantage of a given size,
> + * otherwise fall back to small pages.
> + */
> + if (ioremap_pmd_enabled()) {
> + max_page_shift = PMD_SHIFT;
> + if (ioremap_pud_enabled()) {
> + max_page_shift = PUD_SHIFT;
> + if (ioremap_p4d_enabled())
> + max_page_shift = P4D_SHIFT;
> + }
> + }
>
> - return err;
> + return vmap_range(addr, end, phys_addr, prot, max_page_shift);
> }
> diff --git a/mm/vmalloc.c b/mm/vmalloc.c
> index 233af6936c93..dd27cfb29b10 100644
> --- a/mm/vmalloc.c
> +++ b/mm/vmalloc.c
> @@ -119,7 +119,7 @@ static void vunmap_p4d_range(pgd_t *pgd, unsigned long addr, unsigned long end)
> } while (p4d++, addr = next, addr != end);
> }
>
> -static void vunmap_page_range(unsigned long addr, unsigned long end)
> +static void vunmap_range(unsigned long addr, unsigned long end)
> {
> pgd_t *pgd;
> unsigned long next;
> @@ -135,6 +135,198 @@ static void vunmap_page_range(unsigned long addr, unsigned long end)
> }
>
> static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot)
> +{
> + pte_t *pte;
> + u64 pfn;
> +
> + pfn = phys_addr >> PAGE_SHIFT;
> + pte = pte_alloc_kernel(pmd, addr);
> + if (!pte)
> + return -ENOMEM;
> + do {
> + BUG_ON(!pte_none(*pte));
> + set_pte_at(&init_mm, addr, pte, pfn_pte(pfn, prot));
> + pfn++;
> + } while (pte++, addr += PAGE_SIZE, addr != end);
> + return 0;
> +}
> +
> +static int vmap_try_huge_pmd(pmd_t *pmd, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
> + return 0;
> +
> + if (max_page_shift < PMD_SHIFT)
> + return 0;
> +
> + if ((end - addr) != PMD_SIZE)
> + return 0;
> +
> + if (!IS_ALIGNED(phys_addr, PMD_SIZE))
> + return 0;
> +
> + if (pmd_present(*pmd) && !pmd_free_pte_page(pmd, addr))
> + return 0;
> +
> + return pmd_set_huge(pmd, phys_addr, prot);
> +}
> +
> +static inline int vmap_pmd_range(pud_t *pud, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + pmd_t *pmd;
> + unsigned long next;
> +
> + pmd = pmd_alloc(&init_mm, pud, addr);
> + if (!pmd)
> + return -ENOMEM;
> + do {
> + next = pmd_addr_end(addr, end);
> +
> + if (vmap_try_huge_pmd(pmd, addr, next, phys_addr, prot,
> + max_page_shift))
> + continue;
> +
> + if (vmap_pte_range(pmd, addr, next, phys_addr, prot))
> + return -ENOMEM;
> + } while (pmd++, phys_addr += (next - addr), addr = next, addr != end);
> + return 0;
> +}
> +
> +static int vmap_try_huge_pud(pud_t *pud, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
> + return 0;
> +
> + if (max_page_shift < PUD_SHIFT)
> + return 0;
> +
> + if ((end - addr) != PUD_SIZE)
> + return 0;
> +
> + if (!IS_ALIGNED(phys_addr, PUD_SIZE))
> + return 0;
> +
> + if (pud_present(*pud) && !pud_free_pmd_page(pud, addr))
> + return 0;
> +
> + return pud_set_huge(pud, phys_addr, prot);
> +}
> +
> +static inline int vmap_pud_range(p4d_t *p4d, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + pud_t *pud;
> + unsigned long next;
> +
> + pud = pud_alloc(&init_mm, p4d, addr);
> + if (!pud)
> + return -ENOMEM;
> + do {
> + next = pud_addr_end(addr, end);
> +
> + if (vmap_try_huge_pud(pud, addr, next, phys_addr, prot,
> + max_page_shift))
> + continue;
> +
> + if (vmap_pmd_range(pud, addr, next, phys_addr, prot,
> + max_page_shift))
> + return -ENOMEM;
> + } while (pud++, phys_addr += (next - addr), addr = next, addr != end);
> + return 0;
> +}
> +
> +static int vmap_try_huge_p4d(p4d_t *p4d, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + if (!IS_ENABLED(CONFIG_HAVE_ARCH_HUGE_VMAP))
> + return 0;
> +
> + if (max_page_shift < P4D_SHIFT)
> + return 0;
> +
> + if ((end - addr) != P4D_SIZE)
> + return 0;
> +
> + if (!IS_ALIGNED(phys_addr, P4D_SIZE))
> + return 0;
> +
> + if (p4d_present(*p4d) && !p4d_free_pud_page(p4d, addr))
> + return 0;
> +
> + return p4d_set_huge(p4d, phys_addr, prot);
> +}
> +
> +static inline int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + p4d_t *p4d;
> + unsigned long next;
> +
> + p4d = p4d_alloc(&init_mm, pgd, addr);
> + if (!p4d)
> + return -ENOMEM;
> + do {
> + next = p4d_addr_end(addr, end);
> +
> + if (vmap_try_huge_p4d(p4d, addr, next, phys_addr, prot,
> + max_page_shift))
> + continue;
> +
> + if (vmap_pud_range(p4d, addr, next, phys_addr, prot,
> + max_page_shift))
> + return -ENOMEM;
> + } while (p4d++, phys_addr += (next - addr), addr = next, addr != end);
> + return 0;
> +}
> +
> +static int vmap_range_noflush(unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + pgd_t *pgd;
> + unsigned long start;
> + unsigned long next;
> + int err;
> +
> + might_sleep();
> + BUG_ON(addr >= end);
> +
> + start = addr;
> + pgd = pgd_offset_k(addr);
> + do {
> + next = pgd_addr_end(addr, end);
> + err = vmap_p4d_range(pgd, addr, next, phys_addr, prot,
> + max_page_shift);
> + if (err)
> + break;
> + } while (pgd++, phys_addr += (next - addr), addr = next, addr != end);
> +
> + return err;
> +}
> +
> +int vmap_range(unsigned long addr,
> + unsigned long end, phys_addr_t phys_addr, pgprot_t prot,
> + unsigned int max_page_shift)
> +{
> + int ret;
> +
> + ret = vmap_range_noflush(addr, end, phys_addr, prot, max_page_shift);
> + flush_cache_vmap(addr, end);
> +
> + return ret;
> +}
> +
> +static int vmap_pages_pte_range(pmd_t *pmd, unsigned long addr,
> unsigned long end, pgprot_t prot, struct page **pages, int *nr)
> {
> pte_t *pte;
> @@ -160,7 +352,7 @@ static int vmap_pte_range(pmd_t *pmd, unsigned long addr,
> return 0;
> }
>
> -static int vmap_pmd_range(pud_t *pud, unsigned long addr,
> +static int vmap_pages_pmd_range(pud_t *pud, unsigned long addr,
> unsigned long end, pgprot_t prot, struct page **pages, int *nr)
> {
> pmd_t *pmd;
> @@ -171,13 +363,13 @@ static int vmap_pmd_range(pud_t *pud, unsigned long addr,
> return -ENOMEM;
> do {
> next = pmd_addr_end(addr, end);
> - if (vmap_pte_range(pmd, addr, next, prot, pages, nr))
> + if (vmap_pages_pte_range(pmd, addr, next, prot, pages, nr))
> return -ENOMEM;
> } while (pmd++, addr = next, addr != end);
> return 0;
> }
>
> -static int vmap_pud_range(p4d_t *p4d, unsigned long addr,
> +static int vmap_pages_pud_range(p4d_t *p4d, unsigned long addr,
> unsigned long end, pgprot_t prot, struct page **pages, int *nr)
> {
> pud_t *pud;
> @@ -188,13 +380,13 @@ static int vmap_pud_range(p4d_t *p4d, unsigned long addr,
> return -ENOMEM;
> do {
> next = pud_addr_end(addr, end);
> - if (vmap_pmd_range(pud, addr, next, prot, pages, nr))
> + if (vmap_pages_pmd_range(pud, addr, next, prot, pages, nr))
> return -ENOMEM;
> } while (pud++, addr = next, addr != end);
> return 0;
> }
>
> -static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
> +static int vmap_pages_p4d_range(pgd_t *pgd, unsigned long addr,
> unsigned long end, pgprot_t prot, struct page **pages, int *nr)
> {
> p4d_t *p4d;
> @@ -205,7 +397,7 @@ static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
> return -ENOMEM;
> do {
> next = p4d_addr_end(addr, end);
> - if (vmap_pud_range(p4d, addr, next, prot, pages, nr))
> + if (vmap_pages_pud_range(p4d, addr, next, prot, pages, nr))
> return -ENOMEM;
> } while (p4d++, addr = next, addr != end);
> return 0;
> @@ -217,7 +409,7 @@ static int vmap_p4d_range(pgd_t *pgd, unsigned long addr,
> *
> * Ie. pte at addr+N*PAGE_SIZE shall point to pfn corresponding to pages[N]
> */
> -static int vmap_page_range_noflush(unsigned long start, unsigned long end,
> +static int vmap_pages_range_noflush(unsigned long start, unsigned long end,
> pgprot_t prot, struct page **pages)
> {
> pgd_t *pgd;
> @@ -230,7 +422,7 @@ static int vmap_page_range_noflush(unsigned long start, unsigned long end,
> pgd = pgd_offset_k(addr);
> do {
> next = pgd_addr_end(addr, end);
> - err = vmap_p4d_range(pgd, addr, next, prot, pages, &nr);
> + err = vmap_pages_p4d_range(pgd, addr, next, prot, pages, &nr);
> if (err)
> return err;
> } while (pgd++, addr = next, addr != end);
> @@ -238,12 +430,12 @@ static int vmap_page_range_noflush(unsigned long start, unsigned long end,
> return nr;
> }
>
> -static int vmap_page_range(unsigned long start, unsigned long end,
> +static int vmap_pages_range(unsigned long start, unsigned long end,
> pgprot_t prot, struct page **pages)
> {
> int ret;
>
> - ret = vmap_page_range_noflush(start, end, prot, pages);
> + ret = vmap_pages_range_noflush(start, end, prot, pages);
> flush_cache_vmap(start, end);
> return ret;
> }
> @@ -1148,7 +1340,7 @@ static void free_vmap_area(struct vmap_area *va)
> */
> static void unmap_vmap_area(struct vmap_area *va)
> {
> - vunmap_page_range(va->va_start, va->va_end);
> + vunmap_range(va->va_start, va->va_end);
> }
>
> /*
> @@ -1586,7 +1778,7 @@ static void vb_free(const void *addr, unsigned long size)
> rcu_read_unlock();
> BUG_ON(!vb);
>
> - vunmap_page_range((unsigned long)addr, (unsigned long)addr + size);
> + vunmap_range((unsigned long)addr, (unsigned long)addr + size);
>
> if (debug_pagealloc_enabled())
> flush_tlb_kernel_range((unsigned long)addr,
> @@ -1736,7 +1928,7 @@ void *vm_map_ram(struct page **pages, unsigned int count, int node, pgprot_t pro
> addr = va->va_start;
> mem = (void *)addr;
> }
> - if (vmap_page_range(addr, addr + size, prot, pages) < 0) {
> + if (vmap_pages_range(addr, addr + size, prot, pages) < 0) {
> vm_unmap_ram(mem, count);
> return NULL;
> }
> @@ -1903,7 +2095,7 @@ void __init vmalloc_init(void)
> int map_kernel_range_noflush(unsigned long addr, unsigned long size,
> pgprot_t prot, struct page **pages)
> {
> - return vmap_page_range_noflush(addr, addr + size, prot, pages);
> + return vmap_pages_range_noflush(addr, addr + size, prot, pages);
> }
>
> /**
> @@ -1922,7 +2114,7 @@ int map_kernel_range_noflush(unsigned long addr, unsigned long size,
> */
> void unmap_kernel_range_noflush(unsigned long addr, unsigned long size)
> {
> - vunmap_page_range(addr, addr + size);
> + vunmap_range(addr, addr + size);
> }
> EXPORT_SYMBOL_GPL(unmap_kernel_range_noflush);
>
> @@ -1939,7 +2131,7 @@ void unmap_kernel_range(unsigned long addr, unsigned long size)
> unsigned long end = addr + size;
>
> flush_cache_vunmap(addr, end);
> - vunmap_page_range(addr, end);
> + vunmap_range(addr, end);
> flush_tlb_kernel_range(addr, end);
> }
> EXPORT_SYMBOL_GPL(unmap_kernel_range);
> @@ -1950,7 +2142,7 @@ int map_vm_area(struct vm_struct *area, pgprot_t prot, struct page **pages)
> unsigned long end = addr + get_vm_area_size(area);
> int err;
>
> - err = vmap_page_range(addr, end, prot, pages);
> + err = vmap_pages_range(addr, end, prot, pages);
>
> return err > 0 ? 0 : err;
> }
>
More information about the Linuxppc-dev
mailing list