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/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)
|
||||
|
|
Loading…
Add table
Reference in a new issue