Skip to content

Commit 34e4c79

Browse files
hcahcaVasily Gorbik
authored andcommitted
s390/mm: use VM_FLUSH_RESET_PERMS in module_alloc()
Make use of the set_direct_map() calls for module allocations. In particular: - All changes to read-only permissions in kernel VA mappings are also applied to the direct mapping. Note that execute permissions are intentionally not applied to the direct mapping in order to make sure that all allocated pages within the direct mapping stay non-executable - module_alloc() passes the VM_FLUSH_RESET_PERMS to __vmalloc_node_range() to make sure that all implicit permission changes made to the direct mapping are reset when the allocated vm area is freed again Side effects: the direct mapping will be fragmented depending on how many vm areas with VM_FLUSH_RESET_PERMS and/or explicit page permission changes are allocated and freed again. For example, just after boot of a system the direct mapping statistics look like: $cat /proc/meminfo ... DirectMap4k: 111628 kB DirectMap1M: 16665600 kB DirectMap2G: 0 kB Acked-by: Alexander Gordeev <agordeev@linux.ibm.com> Signed-off-by: Heiko Carstens <hca@linux.ibm.com> Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
1 parent 7608f70 commit 34e4c79

2 files changed

Lines changed: 54 additions & 8 deletions

File tree

arch/s390/kernel/module.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,10 @@ void *module_alloc(unsigned long size)
6262
if (PAGE_ALIGN(size) > MODULES_LEN)
6363
return NULL;
6464
p = __vmalloc_node_range(size, MODULE_ALIGN,
65-
MODULES_VADDR + get_module_load_offset(), MODULES_END,
66-
gfp_mask, PAGE_KERNEL, VM_DEFER_KMEMLEAK, NUMA_NO_NODE,
67-
__builtin_return_address(0));
65+
MODULES_VADDR + get_module_load_offset(),
66+
MODULES_END, gfp_mask, PAGE_KERNEL,
67+
VM_FLUSH_RESET_PERMS | VM_DEFER_KMEMLEAK,
68+
NUMA_NO_NODE, __builtin_return_address(0));
6869
if (p && (kasan_alloc_module_shadow(p, size, gfp_mask) < 0)) {
6970
vfree(p);
7071
return NULL;

arch/s390/mm/pageattr.c

Lines changed: 50 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -323,9 +323,6 @@ static int change_page_attr(unsigned long addr, unsigned long end,
323323
int rc = -EINVAL;
324324
pgd_t *pgdp;
325325

326-
if (addr == end)
327-
return 0;
328-
mutex_lock(&cpa_mutex);
329326
pgdp = pgd_offset_k(addr);
330327
do {
331328
if (pgd_none(*pgdp))
@@ -336,18 +333,66 @@ static int change_page_attr(unsigned long addr, unsigned long end,
336333
break;
337334
cond_resched();
338335
} while (pgdp++, addr = next, addr < end && !rc);
339-
mutex_unlock(&cpa_mutex);
336+
return rc;
337+
}
338+
339+
static int change_page_attr_alias(unsigned long addr, unsigned long end,
340+
unsigned long flags)
341+
{
342+
unsigned long alias, offset, va_start, va_end;
343+
struct vm_struct *area;
344+
int rc = 0;
345+
346+
/*
347+
* Changes to read-only permissions on kernel VA mappings are also
348+
* applied to the kernel direct mapping. Execute permissions are
349+
* intentionally not transferred to keep all allocated pages within
350+
* the direct mapping non-executable.
351+
*/
352+
flags &= SET_MEMORY_RO | SET_MEMORY_RW;
353+
if (!flags)
354+
return 0;
355+
area = NULL;
356+
while (addr < end) {
357+
if (!area)
358+
area = find_vm_area((void *)addr);
359+
if (!area || !(area->flags & VM_ALLOC))
360+
return 0;
361+
va_start = (unsigned long)area->addr;
362+
va_end = va_start + area->nr_pages * PAGE_SIZE;
363+
offset = (addr - va_start) >> PAGE_SHIFT;
364+
alias = (unsigned long)page_address(area->pages[offset]);
365+
rc = change_page_attr(alias, alias + PAGE_SIZE, flags);
366+
if (rc)
367+
break;
368+
addr += PAGE_SIZE;
369+
if (addr >= va_end)
370+
area = NULL;
371+
}
340372
return rc;
341373
}
342374

343375
int __set_memory(unsigned long addr, int numpages, unsigned long flags)
344376
{
377+
unsigned long end;
378+
int rc;
379+
345380
if (!MACHINE_HAS_NX)
346381
flags &= ~(SET_MEMORY_NX | SET_MEMORY_X);
347382
if (!flags)
348383
return 0;
384+
if (!numpages)
385+
return 0;
349386
addr &= PAGE_MASK;
350-
return change_page_attr(addr, addr + numpages * PAGE_SIZE, flags);
387+
end = addr + numpages * PAGE_SIZE;
388+
mutex_lock(&cpa_mutex);
389+
rc = change_page_attr(addr, end, flags);
390+
if (rc)
391+
goto out;
392+
rc = change_page_attr_alias(addr, end, flags);
393+
out:
394+
mutex_unlock(&cpa_mutex);
395+
return rc;
351396
}
352397

353398
int set_direct_map_invalid_noflush(struct page *page)

0 commit comments

Comments
 (0)