diff options
author | Ingo Molnar <mingo@kernel.org> | 2016-03-04 14:12:08 +0300 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-03-04 14:12:08 +0300 |
commit | bc94b99636dc7bcccce439a9fb9c00065e2e2627 (patch) | |
tree | bddbd29a5fd7b2d270d039efc1d6858791a2c98f /arch/arm64/mm/pageattr.c | |
parent | 4650bac1fc45d64aef62ab99aa4db93d41dedbd9 (diff) | |
parent | fc77dbd34c5c99bce46d40a2491937c3bcbd10af (diff) | |
download | linux-bc94b99636dc7bcccce439a9fb9c00065e2e2627.tar.xz |
Merge tag 'v4.5-rc6' into core/resources, to resolve conflict
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch/arm64/mm/pageattr.c')
-rw-r--r-- | arch/arm64/mm/pageattr.c | 23 |
1 files changed, 19 insertions, 4 deletions
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c index cf6240741134..0795c3a36d8f 100644 --- a/arch/arm64/mm/pageattr.c +++ b/arch/arm64/mm/pageattr.c @@ -14,6 +14,7 @@ #include <linux/mm.h> #include <linux/module.h> #include <linux/sched.h> +#include <linux/vmalloc.h> #include <asm/pgtable.h> #include <asm/tlbflush.h> @@ -44,6 +45,7 @@ static int change_memory_common(unsigned long addr, int numpages, unsigned long end = start + size; int ret; struct page_change_data data; + struct vm_struct *area; if (!PAGE_ALIGNED(addr)) { start &= PAGE_MASK; @@ -51,10 +53,23 @@ static int change_memory_common(unsigned long addr, int numpages, WARN_ON_ONCE(1); } - if (start < MODULES_VADDR || start >= MODULES_END) - return -EINVAL; - - if (end < MODULES_VADDR || end >= MODULES_END) + /* + * Kernel VA mappings are always live, and splitting live section + * mappings into page mappings may cause TLB conflicts. This means + * we have to ensure that changing the permission bits of the range + * we are operating on does not result in such splitting. + * + * Let's restrict ourselves to mappings created by vmalloc (or vmap). + * Those are guaranteed to consist entirely of page mappings, and + * splitting is never needed. + * + * So check whether the [addr, addr + size) interval is entirely + * covered by precisely one VM area that has the VM_ALLOC flag set. + */ + area = find_vm_area((void *)addr); + if (!area || + end > (unsigned long)area->addr + area->size || + !(area->flags & VM_ALLOC)) return -EINVAL; if (!numpages) |