Skip to content

Commit a916d13

Browse files
Ard BiesheuvelAlex Shi
authored andcommitted
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>
1 parent 762f201 commit a916d13

1 file changed

Lines changed: 19 additions & 4 deletions

File tree

arch/arm64/mm/pageattr.c

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <linux/mm.h>
1515
#include <linux/module.h>
1616
#include <linux/sched.h>
17+
#include <linux/vmalloc.h>
1718

1819
#include <asm/pgtable.h>
1920
#include <asm/tlbflush.h>
@@ -44,17 +45,31 @@ static int change_memory_common(unsigned long addr, int numpages,
4445
unsigned long end = start + size;
4546
int ret;
4647
struct page_change_data data;
48+
struct vm_struct *area;
4749

4850
if (!PAGE_ALIGNED(addr)) {
4951
start &= PAGE_MASK;
5052
end = start + size;
5153
WARN_ON_ONCE(1);
5254
}
5355

54-
if (start < MODULES_VADDR || start >= MODULES_END)
55-
return -EINVAL;
56-
57-
if (end < MODULES_VADDR || end >= MODULES_END)
56+
/*
57+
* Kernel VA mappings are always live, and splitting live section
58+
* mappings into page mappings may cause TLB conflicts. This means
59+
* we have to ensure that changing the permission bits of the range
60+
* we are operating on does not result in such splitting.
61+
*
62+
* Let's restrict ourselves to mappings created by vmalloc (or vmap).
63+
* Those are guaranteed to consist entirely of page mappings, and
64+
* splitting is never needed.
65+
*
66+
* So check whether the [addr, addr + size) interval is entirely
67+
* covered by precisely one VM area that has the VM_ALLOC flag set.
68+
*/
69+
area = find_vm_area((void *)addr);
70+
if (!area ||
71+
end > (unsigned long)area->addr + area->size ||
72+
!(area->flags & VM_ALLOC))
5873
return -EINVAL;
5974

6075
if (!numpages)

0 commit comments

Comments
 (0)