[PATCHv2 2/3] arm64: Add support for ARCH_SUPPORTS_DEBUG_PAGEALLOC

Ard Biesheuvel ard.biesheuvel at linaro.org
Tue Feb 2 00:57:15 PST 2016


On 1 February 2016 at 22:24, Laura Abbott <labbott at redhat.com> wrote:
> On 02/01/2016 04:29 AM, Mark Rutland wrote:
>>
>> Hi,
>>
>> On Fri, Jan 29, 2016 at 03:46:57PM -0800, Laura Abbott wrote:
>>>
>>>
>>> ARCH_SUPPORTS_DEBUG_PAGEALLOC provides a hook to map and unmap
>>> pages for debugging purposes. This requires memory be mapped
>>> with PAGE_SIZE mappings since breaking down larger mappings
>>> at runtime will lead to TLB conflicts. Check if debug_pagealloc
>>> is enabled at runtime and if so, map everyting with PAGE_SIZE
>>> pages. Implement the functions to actually map/unmap the
>>> pages at runtime.
>>>
>>>
>>> Signed-off-by: Laura Abbott <labbott at fedoraproject.org>
>>
>>
>> I tried to apply atop of the arm64 for-next/pgtable branch, but git
>> wasn't very happy about that -- which branch/patches is this based on?
>>
>> I'm not sure if I'm missing something, have something I shouldn't, or if
>> my MTA is corrupting patches again...
>>
>
> Hmmm, I based it off of your arm64-pagetable-rework-20160125 tag and
> Ard's patch for vmalloc and set_memory_* . The patches seem to apply
> on the for-next/pgtable branch as well so I'm guessing you are missing
> Ard's patch.
>
>
>
>>>
>>> ---
>>>   arch/arm64/Kconfig       |  3 +++
>>>   arch/arm64/mm/mmu.c      | 10 +++++++---
>>>   arch/arm64/mm/pageattr.c | 40 +++++++++++++++++++++++++++++++++-------
>>>   3 files changed, 43 insertions(+), 10 deletions(-)
>>>
>>> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
>>> index 8cc6228..0f33218 100644
>>> --- a/arch/arm64/Kconfig
>>> +++ b/arch/arm64/Kconfig
>>> @@ -537,6 +537,9 @@ config HOTPLUG_CPU
>>>   source kernel/Kconfig.preempt
>>>   source kernel/Kconfig.hz
>>>
>>> +config ARCH_SUPPORTS_DEBUG_PAGEALLOC
>>> +       def_bool y
>>> +
>>>   config ARCH_HAS_HOLES_MEMORYMODEL
>>>         def_bool y if SPARSEMEM
>>>
>>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>>> index 103ebc0..5abbd30 100644
>>> --- a/arch/arm64/mm/mmu.c
>>> +++ b/arch/arm64/mm/mmu.c
>>> @@ -181,7 +181,8 @@ static void alloc_init_pmd(pud_t *pud, unsigned long
>>> addr, unsigned long end,
>>>         do {
>>>                 next = pmd_addr_end(addr, end);
>>>                 /* try section mapping first */
>>> -               if (((addr | next | phys) & ~SECTION_MASK) == 0) {
>>> +               if (((addr | next | phys) & ~SECTION_MASK) == 0 &&
>>> +                     (!debug_pagealloc_enabled() || !pgtable_alloc)) {
>>>                         pmd_t old_pmd =*pmd;
>>>                         set_pmd(pmd, __pmd(phys |
>>>
>>> pgprot_val(mk_sect_prot(prot))));
>>> @@ -208,8 +209,11 @@ static void alloc_init_pmd(pud_t *pud, unsigned long
>>> addr, unsigned long end,
>>>   }
>>>
>>>   static inline bool use_1G_block(unsigned long addr, unsigned long next,
>>> -                       unsigned long phys)
>>> +                       unsigned long phys, phys_addr_t
>>> (*pgtable_alloc)(void))
>>>   {
>>> +       if (pgtable_alloc && debug_pagealloc_enabled())
>>> +               return false;
>>> +
>>>         if (PAGE_SHIFT != 12)
>>>                 return false;
>>>
>>> @@ -241,7 +245,7 @@ static void alloc_init_pud(pgd_t *pgd, unsigned long
>>> addr, unsigned long end,
>>>                 /*
>>>                  * For 4K granule only, attempt to put down a 1GB block
>>>                  */
>>> -               if (use_1G_block(addr, next, phys)) {
>>> +               if (use_1G_block(addr, next, phys, pgtable_alloc)) {
>>>                         pud_t old_pud = *pud;
>>>                         set_pud(pud, __pud(phys |
>>>
>>> pgprot_val(mk_sect_prot(prot))));
>>
>>
>> The checks for pgtable_alloc is to allow create_mapping_noalloc to use
>> sections regardless, right?
>>
>> I got a little confused by that initially, but that seems to make sense.
>>
>
> Yeah, that was what I was going for. I went for the implication with
> pgtable_alloc
> over adding a bool variable to create_mapping. I'll see if I can put a
> comment
> in somewhere to clarify the intentions.
>

Yes, the logic becomes slightly fuzzy, so it would be good to document
this one way or the other.

-- 
Ard.

>
>>>
>>> diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
>>> index 1360a02..69a8a7d 100644
>>> --- a/arch/arm64/mm/pageattr.c
>>> +++ b/arch/arm64/mm/pageattr.c
>>> @@ -38,7 +38,8 @@ static int change_page_range(pte_t *ptep, pgtable_t
>>> token, unsigned long addr,
>>>   }
>>>
>>>   static int change_memory_common(unsigned long addr, int numpages,
>>> -                               pgprot_t set_mask, pgprot_t clear_mask)
>>> +                               pgprot_t set_mask, pgprot_t clear_mask,
>>> +                               bool ignore_vma_check)
>>>   {
>>>         unsigned long start = addr;
>>>         unsigned long size = PAGE_SIZE*numpages;
>>> @@ -65,11 +66,14 @@ static int change_memory_common(unsigned long addr,
>>> int numpages,
>>>          *
>>>          * So check whether the [addr, addr + size) interval is entirely
>>>          * covered by precisely one VM area that has the VM_ALLOC flag
>>> set.
>>> +        *
>>> +        * The one exception to this is is we're forcing everything to be
>>> +        * page mapped with DEBUG_PAGEALLOC
>>>          */
>>>         area = find_vm_area((void *)addr);
>>> -       if (!area ||
>>> +       if (!ignore_vma_check && (!area ||
>>>             end > (unsigned long)area->addr + area->size ||
>>> -           !(area->flags & VM_ALLOC))
>>> +           !(area->flags & VM_ALLOC)))
>>>                 return -EINVAL;
>>
>>
>> Perhaps we could pull out everything but the VMA checks into a static
>> __change_memory_common. Then we can call that directly in
>> __kernel_map_pages, and don't need to pass a confusing boolean
>> parameter.
>
>
> Sounds fine.
>
>>
>> Otherwise, this looks good to me.
>>  Mark.
>>
>
> Thanks,
> Laura
>
>
>>>
>>>
>>>         data.set_mask = set_mask;
>>> @@ -86,21 +90,24 @@ int set_memory_ro(unsigned long addr, int numpages)
>>>   {
>>>         return change_memory_common(addr, numpages,
>>>                                         __pgprot(PTE_RDONLY),
>>> -                                       __pgprot(PTE_WRITE));
>>> +                                       __pgprot(PTE_WRITE),
>>> +                                       false);
>>>   }
>>>
>>>   int set_memory_rw(unsigned long addr, int numpages)
>>>   {
>>>         return change_memory_common(addr, numpages,
>>>                                         __pgprot(PTE_WRITE),
>>> -                                       __pgprot(PTE_RDONLY));
>>> +                                       __pgprot(PTE_RDONLY),
>>> +                                       false);
>>>   }
>>>
>>>   int set_memory_nx(unsigned long addr, int numpages)
>>>   {
>>>         return change_memory_common(addr, numpages,
>>>                                         __pgprot(PTE_PXN),
>>> -                                       __pgprot(0));
>>> +                                       __pgprot(0),
>>> +                                       false);
>>>   }
>>>   EXPORT_SYMBOL_GPL(set_memory_nx);
>>>
>>> @@ -108,6 +115,25 @@ int set_memory_x(unsigned long addr, int numpages)
>>>   {
>>>         return change_memory_common(addr, numpages,
>>>                                         __pgprot(0),
>>> -                                       __pgprot(PTE_PXN));
>>> +                                       __pgprot(PTE_PXN),
>>> +                                       false);
>>>   }
>>>   EXPORT_SYMBOL_GPL(set_memory_x);
>>> +
>>> +#ifdef CONFIG_DEBUG_PAGEALLOC
>>> +void __kernel_map_pages(struct page *page, int numpages, int enable)
>>> +{
>>> +       unsigned long addr = (unsigned long) page_address(page);
>>> +
>>> +       if (enable)
>>> +               change_memory_common(addr, numpages,
>>> +                                       __pgprot(PTE_VALID),
>>> +                                       __pgprot(0),
>>> +                                       true);
>>> +       else
>>> +               change_memory_common(addr, numpages,
>>> +                                       __pgprot(0),
>>> +                                       __pgprot(PTE_VALID),
>>> +                                       true);
>>> +}
>>> +#endif
>>> --
>>> 2.5.0
>>>
>



More information about the linux-arm-kernel mailing list