forked from Minki/linux
89154dd531
Convert the last few remaining mmap_sem rwsem calls to use the new mmap locking API. These were missed by coccinelle for some reason (I think coccinelle does not support some of the preprocessor constructs in these files ?) [akpm@linux-foundation.org: convert linux-next leftovers] [akpm@linux-foundation.org: more linux-next leftovers] [akpm@linux-foundation.org: more linux-next leftovers] Signed-off-by: Michel Lespinasse <walken@google.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Reviewed-by: Daniel Jordan <daniel.m.jordan@oracle.com> Reviewed-by: Laurent Dufour <ldufour@linux.ibm.com> Reviewed-by: Vlastimil Babka <vbabka@suse.cz> Cc: Davidlohr Bueso <dbueso@suse.de> Cc: David Rientjes <rientjes@google.com> Cc: Hugh Dickins <hughd@google.com> Cc: Jason Gunthorpe <jgg@ziepe.ca> Cc: Jerome Glisse <jglisse@redhat.com> Cc: John Hubbard <jhubbard@nvidia.com> Cc: Liam Howlett <Liam.Howlett@oracle.com> Cc: Matthew Wilcox <willy@infradead.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Ying Han <yinghan@google.com> Link: http://lkml.kernel.org/r/20200520052908.204642-6-walken@google.com Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
188 lines
4.2 KiB
C
188 lines
4.2 KiB
C
// SPDX-License-Identifier: GPL-2.0-only
|
|
/*
|
|
* Copyright (C) 2019 SiFive
|
|
*/
|
|
|
|
#include <linux/pagewalk.h>
|
|
#include <linux/pgtable.h>
|
|
#include <asm/tlbflush.h>
|
|
#include <asm/bitops.h>
|
|
|
|
struct pageattr_masks {
|
|
pgprot_t set_mask;
|
|
pgprot_t clear_mask;
|
|
};
|
|
|
|
static unsigned long set_pageattr_masks(unsigned long val, struct mm_walk *walk)
|
|
{
|
|
struct pageattr_masks *masks = walk->private;
|
|
unsigned long new_val = val;
|
|
|
|
new_val &= ~(pgprot_val(masks->clear_mask));
|
|
new_val |= (pgprot_val(masks->set_mask));
|
|
|
|
return new_val;
|
|
}
|
|
|
|
static int pageattr_pgd_entry(pgd_t *pgd, unsigned long addr,
|
|
unsigned long next, struct mm_walk *walk)
|
|
{
|
|
pgd_t val = READ_ONCE(*pgd);
|
|
|
|
if (pgd_leaf(val)) {
|
|
val = __pgd(set_pageattr_masks(pgd_val(val), walk));
|
|
set_pgd(pgd, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pageattr_p4d_entry(p4d_t *p4d, unsigned long addr,
|
|
unsigned long next, struct mm_walk *walk)
|
|
{
|
|
p4d_t val = READ_ONCE(*p4d);
|
|
|
|
if (p4d_leaf(val)) {
|
|
val = __p4d(set_pageattr_masks(p4d_val(val), walk));
|
|
set_p4d(p4d, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pageattr_pud_entry(pud_t *pud, unsigned long addr,
|
|
unsigned long next, struct mm_walk *walk)
|
|
{
|
|
pud_t val = READ_ONCE(*pud);
|
|
|
|
if (pud_leaf(val)) {
|
|
val = __pud(set_pageattr_masks(pud_val(val), walk));
|
|
set_pud(pud, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pageattr_pmd_entry(pmd_t *pmd, unsigned long addr,
|
|
unsigned long next, struct mm_walk *walk)
|
|
{
|
|
pmd_t val = READ_ONCE(*pmd);
|
|
|
|
if (pmd_leaf(val)) {
|
|
val = __pmd(set_pageattr_masks(pmd_val(val), walk));
|
|
set_pmd(pmd, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pageattr_pte_entry(pte_t *pte, unsigned long addr,
|
|
unsigned long next, struct mm_walk *walk)
|
|
{
|
|
pte_t val = READ_ONCE(*pte);
|
|
|
|
val = __pte(set_pageattr_masks(pte_val(val), walk));
|
|
set_pte(pte, val);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int pageattr_pte_hole(unsigned long addr, unsigned long next,
|
|
int depth, struct mm_walk *walk)
|
|
{
|
|
/* Nothing to do here */
|
|
return 0;
|
|
}
|
|
|
|
const static struct mm_walk_ops pageattr_ops = {
|
|
.pgd_entry = pageattr_pgd_entry,
|
|
.p4d_entry = pageattr_p4d_entry,
|
|
.pud_entry = pageattr_pud_entry,
|
|
.pmd_entry = pageattr_pmd_entry,
|
|
.pte_entry = pageattr_pte_entry,
|
|
.pte_hole = pageattr_pte_hole,
|
|
};
|
|
|
|
static int __set_memory(unsigned long addr, int numpages, pgprot_t set_mask,
|
|
pgprot_t clear_mask)
|
|
{
|
|
int ret;
|
|
unsigned long start = addr;
|
|
unsigned long end = start + PAGE_SIZE * numpages;
|
|
struct pageattr_masks masks = {
|
|
.set_mask = set_mask,
|
|
.clear_mask = clear_mask
|
|
};
|
|
|
|
if (!numpages)
|
|
return 0;
|
|
|
|
mmap_read_lock(&init_mm);
|
|
ret = walk_page_range_novma(&init_mm, start, end, &pageattr_ops, NULL,
|
|
&masks);
|
|
mmap_read_unlock(&init_mm);
|
|
|
|
flush_tlb_kernel_range(start, end);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int set_memory_ro(unsigned long addr, int numpages)
|
|
{
|
|
return __set_memory(addr, numpages, __pgprot(_PAGE_READ),
|
|
__pgprot(_PAGE_WRITE));
|
|
}
|
|
|
|
int set_memory_rw(unsigned long addr, int numpages)
|
|
{
|
|
return __set_memory(addr, numpages, __pgprot(_PAGE_READ | _PAGE_WRITE),
|
|
__pgprot(0));
|
|
}
|
|
|
|
int set_memory_x(unsigned long addr, int numpages)
|
|
{
|
|
return __set_memory(addr, numpages, __pgprot(_PAGE_EXEC), __pgprot(0));
|
|
}
|
|
|
|
int set_memory_nx(unsigned long addr, int numpages)
|
|
{
|
|
return __set_memory(addr, numpages, __pgprot(0), __pgprot(_PAGE_EXEC));
|
|
}
|
|
|
|
int set_direct_map_invalid_noflush(struct page *page)
|
|
{
|
|
unsigned long start = (unsigned long)page_address(page);
|
|
unsigned long end = start + PAGE_SIZE;
|
|
struct pageattr_masks masks = {
|
|
.set_mask = __pgprot(0),
|
|
.clear_mask = __pgprot(_PAGE_PRESENT)
|
|
};
|
|
|
|
return walk_page_range(&init_mm, start, end, &pageattr_ops, &masks);
|
|
}
|
|
|
|
int set_direct_map_default_noflush(struct page *page)
|
|
{
|
|
unsigned long start = (unsigned long)page_address(page);
|
|
unsigned long end = start + PAGE_SIZE;
|
|
struct pageattr_masks masks = {
|
|
.set_mask = PAGE_KERNEL,
|
|
.clear_mask = __pgprot(0)
|
|
};
|
|
|
|
return walk_page_range(&init_mm, start, end, &pageattr_ops, &masks);
|
|
}
|
|
|
|
void __kernel_map_pages(struct page *page, int numpages, int enable)
|
|
{
|
|
if (!debug_pagealloc_enabled())
|
|
return;
|
|
|
|
if (enable)
|
|
__set_memory((unsigned long)page_address(page), numpages,
|
|
__pgprot(_PAGE_PRESENT), __pgprot(0));
|
|
else
|
|
__set_memory((unsigned long)page_address(page), numpages,
|
|
__pgprot(0), __pgprot(_PAGE_PRESENT));
|
|
}
|