arm64: allow vmalloc regions to be set with set_memory_*
The range of set_memory_* is currently restricted to the module address range because of difficulties in breaking down larger block sizes. vmalloc maps PAGE_SIZE pages so it is safe to use as well. Update the function ranges and add a comment explaining why the range is restricted the way it is. Suggested-by: Laura Abbott <labbott@fedoraproject.org> Acked-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Signed-off-by: Will Deacon <will.deacon@arm.com> (cherry picked from commit 95f5c80050ad723163aa80dc8bffd48ef4afc6d5) Signed-off-by: Alex Shi <alex.shi@linaro.org>
This commit is contained in:
parent
f00cf2ba83
commit
a0e40450cf
1 changed files with 19 additions and 4 deletions
|
@ -14,6 +14,7 @@
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/sched.h>
|
#include <linux/sched.h>
|
||||||
|
#include <linux/vmalloc.h>
|
||||||
|
|
||||||
#include <asm/pgtable.h>
|
#include <asm/pgtable.h>
|
||||||
#include <asm/tlbflush.h>
|
#include <asm/tlbflush.h>
|
||||||
|
@ -44,6 +45,7 @@ static int change_memory_common(unsigned long addr, int numpages,
|
||||||
unsigned long end = start + size;
|
unsigned long end = start + size;
|
||||||
int ret;
|
int ret;
|
||||||
struct page_change_data data;
|
struct page_change_data data;
|
||||||
|
struct vm_struct *area;
|
||||||
|
|
||||||
if (!PAGE_ALIGNED(addr)) {
|
if (!PAGE_ALIGNED(addr)) {
|
||||||
start &= PAGE_MASK;
|
start &= PAGE_MASK;
|
||||||
|
@ -51,10 +53,23 @@ static int change_memory_common(unsigned long addr, int numpages,
|
||||||
WARN_ON_ONCE(1);
|
WARN_ON_ONCE(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (start < MODULES_VADDR || start >= MODULES_END)
|
/*
|
||||||
return -EINVAL;
|
* Kernel VA mappings are always live, and splitting live section
|
||||||
|
* mappings into page mappings may cause TLB conflicts. This means
|
||||||
if (end < MODULES_VADDR || end >= MODULES_END)
|
* 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;
|
return -EINVAL;
|
||||||
|
|
||||||
if (!numpages)
|
if (!numpages)
|
||||||
|
|
Loading…
Add table
Reference in a new issue