Merge branch 'akpm' (patches from Andrew)
Merge second patch-bomb from Andrew Morton: - more MM stuff: - Kirill's page-flags rework - Kirill's now-allegedly-fixed THP rework - MADV_FREE implementation - DAX feature work (msync/fsync). This isn't quite complete but DAX is new and it's good enough and the guys have a handle on what needs to be done - I expect this to be wrapped in the next week or two. - some vsprintf maintenance work - various other misc bits * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (145 commits) printk: change recursion_bug type to bool lib/vsprintf: factor out %pN[F] handler as netdev_bits() lib/vsprintf: refactor duplicate code to special_hex_number() printk-formats.txt: remove unimplemented %pT printk: help pr_debug and pr_devel to optimize out arguments lib/test_printf.c: test dentry printing lib/test_printf.c: add test for large bitmaps lib/test_printf.c: account for kvasprintf tests lib/test_printf.c: add a few number() tests lib/test_printf.c: test precision quirks lib/test_printf.c: check for out-of-bound writes lib/test_printf.c: don't BUG lib/kasprintf.c: add sanity check to kvasprintf lib/vsprintf.c: warn about too large precisions and field widths lib/vsprintf.c: help gcc make number() smaller lib/vsprintf.c: expand field_width to 24 bits lib/vsprintf.c: eliminate potential race in string() lib/vsprintf.c: move string() below widen_string() lib/vsprintf.c: pull out padding code from dentry_name() printk: do cond_resched() between lines while outputting to consoles ...
This commit is contained in:
commit
0cbeafb245
|
@ -1,40 +0,0 @@
|
|||
#
|
||||
# Feature name: pmdp_splitting_flush
|
||||
# Kconfig: __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
# description: arch supports the pmdp_splitting_flush() VM API
|
||||
#
|
||||
-----------------------
|
||||
| arch |status|
|
||||
-----------------------
|
||||
| alpha: | TODO |
|
||||
| arc: | TODO |
|
||||
| arm: | ok |
|
||||
| arm64: | ok |
|
||||
| avr32: | TODO |
|
||||
| blackfin: | TODO |
|
||||
| c6x: | TODO |
|
||||
| cris: | TODO |
|
||||
| frv: | TODO |
|
||||
| h8300: | TODO |
|
||||
| hexagon: | TODO |
|
||||
| ia64: | TODO |
|
||||
| m32r: | TODO |
|
||||
| m68k: | TODO |
|
||||
| metag: | TODO |
|
||||
| microblaze: | TODO |
|
||||
| mips: | ok |
|
||||
| mn10300: | TODO |
|
||||
| nios2: | TODO |
|
||||
| openrisc: | TODO |
|
||||
| parisc: | TODO |
|
||||
| powerpc: | ok |
|
||||
| s390: | ok |
|
||||
| score: | TODO |
|
||||
| sh: | TODO |
|
||||
| sparc: | TODO |
|
||||
| tile: | TODO |
|
||||
| um: | TODO |
|
||||
| unicore32: | TODO |
|
||||
| x86: | ok |
|
||||
| xtensa: | TODO |
|
||||
-----------------------
|
|
@ -306,15 +306,6 @@ Network device features:
|
|||
|
||||
Passed by reference.
|
||||
|
||||
Command from struct task_struct
|
||||
|
||||
%pT ls
|
||||
|
||||
For printing executable name excluding path from struct
|
||||
task_struct.
|
||||
|
||||
Passed by reference.
|
||||
|
||||
If you add other %p extensions, please extend lib/test_printf.c with
|
||||
one or more test cases, if at all feasible.
|
||||
|
||||
|
|
|
@ -35,10 +35,10 @@ miss is going to run faster.
|
|||
|
||||
== Design ==
|
||||
|
||||
- "graceful fallback": mm components which don't have transparent
|
||||
hugepage knowledge fall back to breaking a transparent hugepage and
|
||||
working on the regular pages and their respective regular pmd/pte
|
||||
mappings
|
||||
- "graceful fallback": mm components which don't have transparent hugepage
|
||||
knowledge fall back to breaking huge pmd mapping into table of ptes and,
|
||||
if necessary, split a transparent hugepage. Therefore these components
|
||||
can continue working on the regular pages or regular pte mappings.
|
||||
|
||||
- if a hugepage allocation fails because of memory fragmentation,
|
||||
regular pages should be gracefully allocated instead and mixed in
|
||||
|
@ -221,9 +221,18 @@ thp_collapse_alloc_failed is incremented if khugepaged found a range
|
|||
of pages that should be collapsed into one huge page but failed
|
||||
the allocation.
|
||||
|
||||
thp_split is incremented every time a huge page is split into base
|
||||
thp_split_page is incremented every time a huge page is split into base
|
||||
pages. This can happen for a variety of reasons but a common
|
||||
reason is that a huge page is old and is being reclaimed.
|
||||
This action implies splitting all PMD the page mapped with.
|
||||
|
||||
thp_split_page_failed is is incremented if kernel fails to split huge
|
||||
page. This can happen if the page was pinned by somebody.
|
||||
|
||||
thp_split_pmd is incremented every time a PMD split into table of PTEs.
|
||||
This can happen, for instance, when application calls mprotect() or
|
||||
munmap() on part of huge page. It doesn't split huge page, only
|
||||
page table entry.
|
||||
|
||||
thp_zero_page_alloc is incremented every time a huge zero page is
|
||||
successfully allocated. It includes allocations which where
|
||||
|
@ -274,10 +283,8 @@ is complete, so they won't ever notice the fact the page is huge. But
|
|||
if any driver is going to mangle over the page structure of the tail
|
||||
page (like for checking page->mapping or other bits that are relevant
|
||||
for the head page and not the tail page), it should be updated to jump
|
||||
to check head page instead (while serializing properly against
|
||||
split_huge_page() to avoid the head and tail pages to disappear from
|
||||
under it, see the futex code to see an example of that, hugetlbfs also
|
||||
needed special handling in futex code for similar reasons).
|
||||
to check head page instead. Taking reference on any head/tail page would
|
||||
prevent page from being split by anyone.
|
||||
|
||||
NOTE: these aren't new constraints to the GUP API, and they match the
|
||||
same constrains that applies to hugetlbfs too, so any driver capable
|
||||
|
@ -312,9 +319,9 @@ unaffected. libhugetlbfs will also work fine as usual.
|
|||
== Graceful fallback ==
|
||||
|
||||
Code walking pagetables but unware about huge pmds can simply call
|
||||
split_huge_page_pmd(vma, addr, pmd) where the pmd is the one returned by
|
||||
split_huge_pmd(vma, pmd, addr) where the pmd is the one returned by
|
||||
pmd_offset. It's trivial to make the code transparent hugepage aware
|
||||
by just grepping for "pmd_offset" and adding split_huge_page_pmd where
|
||||
by just grepping for "pmd_offset" and adding split_huge_pmd where
|
||||
missing after pmd_offset returns the pmd. Thanks to the graceful
|
||||
fallback design, with a one liner change, you can avoid to write
|
||||
hundred if not thousand of lines of complex code to make your code
|
||||
|
@ -323,7 +330,8 @@ hugepage aware.
|
|||
If you're not walking pagetables but you run into a physical hugepage
|
||||
but you can't handle it natively in your code, you can split it by
|
||||
calling split_huge_page(page). This is what the Linux VM does before
|
||||
it tries to swapout the hugepage for example.
|
||||
it tries to swapout the hugepage for example. split_huge_page() can fail
|
||||
if the page is pinned and you must handle this correctly.
|
||||
|
||||
Example to make mremap.c transparent hugepage aware with a one liner
|
||||
change:
|
||||
|
@ -335,14 +343,14 @@ diff --git a/mm/mremap.c b/mm/mremap.c
|
|||
return NULL;
|
||||
|
||||
pmd = pmd_offset(pud, addr);
|
||||
+ split_huge_page_pmd(vma, addr, pmd);
|
||||
+ split_huge_pmd(vma, pmd, addr);
|
||||
if (pmd_none_or_clear_bad(pmd))
|
||||
return NULL;
|
||||
|
||||
== Locking in hugepage aware code ==
|
||||
|
||||
We want as much code as possible hugepage aware, as calling
|
||||
split_huge_page() or split_huge_page_pmd() has a cost.
|
||||
split_huge_page() or split_huge_pmd() has a cost.
|
||||
|
||||
To make pagetable walks huge pmd aware, all you need to do is to call
|
||||
pmd_trans_huge() on the pmd returned by pmd_offset. You must hold the
|
||||
|
@ -351,47 +359,80 @@ created from under you by khugepaged (khugepaged collapse_huge_page
|
|||
takes the mmap_sem in write mode in addition to the anon_vma lock). If
|
||||
pmd_trans_huge returns false, you just fallback in the old code
|
||||
paths. If instead pmd_trans_huge returns true, you have to take the
|
||||
mm->page_table_lock and re-run pmd_trans_huge. Taking the
|
||||
page_table_lock will prevent the huge pmd to be converted into a
|
||||
regular pmd from under you (split_huge_page can run in parallel to the
|
||||
page table lock (pmd_lock()) and re-run pmd_trans_huge. Taking the
|
||||
page table lock will prevent the huge pmd to be converted into a
|
||||
regular pmd from under you (split_huge_pmd can run in parallel to the
|
||||
pagetable walk). If the second pmd_trans_huge returns false, you
|
||||
should just drop the page_table_lock and fallback to the old code as
|
||||
before. Otherwise you should run pmd_trans_splitting on the pmd. In
|
||||
case pmd_trans_splitting returns true, it means split_huge_page is
|
||||
already in the middle of splitting the page. So if pmd_trans_splitting
|
||||
returns true it's enough to drop the page_table_lock and call
|
||||
wait_split_huge_page and then fallback the old code paths. You are
|
||||
guaranteed by the time wait_split_huge_page returns, the pmd isn't
|
||||
huge anymore. If pmd_trans_splitting returns false, you can proceed to
|
||||
process the huge pmd and the hugepage natively. Once finished you can
|
||||
drop the page_table_lock.
|
||||
should just drop the page table lock and fallback to the old code as
|
||||
before. Otherwise you can proceed to process the huge pmd and the
|
||||
hugepage natively. Once finished you can drop the page table lock.
|
||||
|
||||
== compound_lock, get_user_pages and put_page ==
|
||||
== Refcounts and transparent huge pages ==
|
||||
|
||||
Refcounting on THP is mostly consistent with refcounting on other compound
|
||||
pages:
|
||||
|
||||
- get_page()/put_page() and GUP operate in head page's ->_count.
|
||||
|
||||
- ->_count in tail pages is always zero: get_page_unless_zero() never
|
||||
succeed on tail pages.
|
||||
|
||||
- map/unmap of the pages with PTE entry increment/decrement ->_mapcount
|
||||
on relevant sub-page of the compound page.
|
||||
|
||||
- map/unmap of the whole compound page accounted in compound_mapcount
|
||||
(stored in first tail page).
|
||||
|
||||
PageDoubleMap() indicates that ->_mapcount in all subpages is offset up by one.
|
||||
This additional reference is required to get race-free detection of unmap of
|
||||
subpages when we have them mapped with both PMDs and PTEs.
|
||||
|
||||
This is optimization required to lower overhead of per-subpage mapcount
|
||||
tracking. The alternative is alter ->_mapcount in all subpages on each
|
||||
map/unmap of the whole compound page.
|
||||
|
||||
We set PG_double_map when a PMD of the page got split for the first time,
|
||||
but still have PMD mapping. The addtional references go away with last
|
||||
compound_mapcount.
|
||||
|
||||
split_huge_page internally has to distribute the refcounts in the head
|
||||
page to the tail pages before clearing all PG_head/tail bits from the
|
||||
page structures. It can do that easily for refcounts taken by huge pmd
|
||||
mappings. But the GUI API as created by hugetlbfs (that returns head
|
||||
and tail pages if running get_user_pages on an address backed by any
|
||||
hugepage), requires the refcount to be accounted on the tail pages and
|
||||
not only in the head pages, if we want to be able to run
|
||||
split_huge_page while there are gup pins established on any tail
|
||||
page. Failure to be able to run split_huge_page if there's any gup pin
|
||||
on any tail page, would mean having to split all hugepages upfront in
|
||||
get_user_pages which is unacceptable as too many gup users are
|
||||
performance critical and they must work natively on hugepages like
|
||||
they work natively on hugetlbfs already (hugetlbfs is simpler because
|
||||
hugetlbfs pages cannot be split so there wouldn't be requirement of
|
||||
accounting the pins on the tail pages for hugetlbfs). If we wouldn't
|
||||
account the gup refcounts on the tail pages during gup, we won't know
|
||||
anymore which tail page is pinned by gup and which is not while we run
|
||||
split_huge_page. But we still have to add the gup pin to the head page
|
||||
too, to know when we can free the compound page in case it's never
|
||||
split during its lifetime. That requires changing not just
|
||||
get_page, but put_page as well so that when put_page runs on a tail
|
||||
page (and only on a tail page) it will find its respective head page,
|
||||
and then it will decrease the head page refcount in addition to the
|
||||
tail page refcount. To obtain a head page reliably and to decrease its
|
||||
refcount without race conditions, put_page has to serialize against
|
||||
__split_huge_page_refcount using a special per-page lock called
|
||||
compound_lock.
|
||||
page to the tail pages before clearing all PG_head/tail bits from the page
|
||||
structures. It can be done easily for refcounts taken by page table
|
||||
entries. But we don't have enough information on how to distribute any
|
||||
additional pins (i.e. from get_user_pages). split_huge_page() fails any
|
||||
requests to split pinned huge page: it expects page count to be equal to
|
||||
sum of mapcount of all sub-pages plus one (split_huge_page caller must
|
||||
have reference for head page).
|
||||
|
||||
split_huge_page uses migration entries to stabilize page->_count and
|
||||
page->_mapcount.
|
||||
|
||||
We safe against physical memory scanners too: the only legitimate way
|
||||
scanner can get reference to a page is get_page_unless_zero().
|
||||
|
||||
All tail pages has zero ->_count until atomic_add(). It prevent scanner
|
||||
from geting reference to tail page up to the point. After the atomic_add()
|
||||
we don't care about ->_count value. We already known how many references
|
||||
with should uncharge from head page.
|
||||
|
||||
For head page get_page_unless_zero() will succeed and we don't mind. It's
|
||||
clear where reference should go after split: it will stay on head page.
|
||||
|
||||
Note that split_huge_pmd() doesn't have any limitation on refcounting:
|
||||
pmd can be split at any point and never fails.
|
||||
|
||||
== Partial unmap and deferred_split_huge_page() ==
|
||||
|
||||
Unmapping part of THP (with munmap() or other way) is not going to free
|
||||
memory immediately. Instead, we detect that a subpage of THP is not in use
|
||||
in page_remove_rmap() and queue the THP for splitting if memory pressure
|
||||
comes. Splitting will free up unused subpages.
|
||||
|
||||
Splitting the page right away is not an option due to locking context in
|
||||
the place where we can detect partial unmap. It's also might be
|
||||
counterproductive since in many cases partial unmap unmap happens during
|
||||
exit(2) if an THP crosses VMA boundary.
|
||||
|
||||
Function deferred_split_huge_page() is used to queue page for splitting.
|
||||
The splitting itself will happen when we get memory pressure via shrinker
|
||||
interface.
|
||||
|
|
|
@ -47,8 +47,10 @@
|
|||
#define MADV_WILLNEED 3 /* will need these pages */
|
||||
#define MADV_SPACEAVAIL 5 /* ensure resources are available */
|
||||
#define MADV_DONTNEED 6 /* don't need these pages */
|
||||
#define MADV_FREE 7 /* free pages only if memory pressure */
|
||||
|
||||
/* common/generic parameters */
|
||||
#define MADV_FREE 8 /* free pages only if memory pressure */
|
||||
#define MADV_REMOVE 9 /* remove these pages & resources */
|
||||
#define MADV_DONTFORK 10 /* don't inherit across fork */
|
||||
#define MADV_DOFORK 11 /* do inherit across fork */
|
||||
|
|
|
@ -73,9 +73,6 @@ config STACKTRACE_SUPPORT
|
|||
def_bool y
|
||||
select STACKTRACE
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_ARCH_TRANSPARENT_HUGEPAGE
|
||||
def_bool y
|
||||
depends on ARC_MMU_V4
|
||||
|
|
|
@ -617,7 +617,7 @@ void flush_dcache_page(struct page *page)
|
|||
*/
|
||||
if (!mapping_mapped(mapping)) {
|
||||
clear_bit(PG_dc_clean, &page->flags);
|
||||
} else if (page_mapped(page)) {
|
||||
} else if (page_mapcount(page)) {
|
||||
|
||||
/* kernel reading from page with U-mapping */
|
||||
phys_addr_t paddr = (unsigned long)page_address(page);
|
||||
|
@ -857,7 +857,7 @@ void copy_user_highpage(struct page *to, struct page *from,
|
|||
* For !VIPT cache, all of this gets compiled out as
|
||||
* addr_not_cache_congruent() is 0
|
||||
*/
|
||||
if (page_mapped(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
|
||||
if (page_mapcount(from) && addr_not_cache_congruent(kfrom, u_vaddr)) {
|
||||
__flush_dcache_page((unsigned long)kfrom, u_vaddr);
|
||||
clean_src_k_mappings = 1;
|
||||
}
|
||||
|
|
|
@ -168,11 +168,6 @@ config STACKTRACE_SUPPORT
|
|||
bool
|
||||
default y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
bool
|
||||
depends on !SMP
|
||||
default y
|
||||
|
||||
config LOCKDEP_SUPPORT
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -182,7 +182,8 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
|
|||
return (vcpu->arch.cp15[c1_SCTLR] & 0b101) == 0b101;
|
||||
}
|
||||
|
||||
static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
|
||||
static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
|
||||
kvm_pfn_t pfn,
|
||||
unsigned long size,
|
||||
bool ipa_uncached)
|
||||
{
|
||||
|
@ -246,7 +247,7 @@ static inline void __kvm_flush_dcache_pte(pte_t pte)
|
|||
static inline void __kvm_flush_dcache_pmd(pmd_t pmd)
|
||||
{
|
||||
unsigned long size = PMD_SIZE;
|
||||
pfn_t pfn = pmd_pfn(pmd);
|
||||
kvm_pfn_t pfn = pmd_pfn(pmd);
|
||||
|
||||
while (size) {
|
||||
void *va = kmap_atomic_pfn(pfn);
|
||||
|
|
|
@ -88,7 +88,6 @@
|
|||
|
||||
#define L_PMD_SECT_VALID (_AT(pmdval_t, 1) << 0)
|
||||
#define L_PMD_SECT_DIRTY (_AT(pmdval_t, 1) << 55)
|
||||
#define L_PMD_SECT_SPLITTING (_AT(pmdval_t, 1) << 56)
|
||||
#define L_PMD_SECT_NONE (_AT(pmdval_t, 1) << 57)
|
||||
#define L_PMD_SECT_RDONLY (_AT(pteval_t, 1) << 58)
|
||||
|
||||
|
@ -232,13 +231,6 @@ static inline pte_t pte_mkspecial(pte_t pte)
|
|||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !pmd_table(pmd))
|
||||
#define pmd_trans_splitting(pmd) (pmd_isset((pmd), L_PMD_SECT_SPLITTING))
|
||||
|
||||
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
|
||||
pmd_t *pmdp);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define PMD_BIT_FUNC(fn,op) \
|
||||
|
@ -246,9 +238,9 @@ static inline pmd_t pmd_##fn(pmd_t pmd) { pmd_val(pmd) op; return pmd; }
|
|||
|
||||
PMD_BIT_FUNC(wrprotect, |= L_PMD_SECT_RDONLY);
|
||||
PMD_BIT_FUNC(mkold, &= ~PMD_SECT_AF);
|
||||
PMD_BIT_FUNC(mksplitting, |= L_PMD_SECT_SPLITTING);
|
||||
PMD_BIT_FUNC(mkwrite, &= ~L_PMD_SECT_RDONLY);
|
||||
PMD_BIT_FUNC(mkdirty, |= L_PMD_SECT_DIRTY);
|
||||
PMD_BIT_FUNC(mkclean, &= ~L_PMD_SECT_DIRTY);
|
||||
PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
|
||||
|
||||
#define pmd_mkhuge(pmd) (__pmd(pmd_val(pmd) & ~PMD_TABLE_BIT))
|
||||
|
|
|
@ -992,9 +992,9 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool transparent_hugepage_adjust(pfn_t *pfnp, phys_addr_t *ipap)
|
||||
static bool transparent_hugepage_adjust(kvm_pfn_t *pfnp, phys_addr_t *ipap)
|
||||
{
|
||||
pfn_t pfn = *pfnp;
|
||||
kvm_pfn_t pfn = *pfnp;
|
||||
gfn_t gfn = *ipap >> PAGE_SHIFT;
|
||||
|
||||
if (PageTransCompound(pfn_to_page(pfn))) {
|
||||
|
@ -1201,7 +1201,7 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
|
|||
kvm_mmu_write_protect_pt_masked(kvm, slot, gfn_offset, mask);
|
||||
}
|
||||
|
||||
static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
|
||||
static void coherent_cache_guest_page(struct kvm_vcpu *vcpu, kvm_pfn_t pfn,
|
||||
unsigned long size, bool uncached)
|
||||
{
|
||||
__coherent_cache_guest_page(vcpu, pfn, size, uncached);
|
||||
|
@ -1218,7 +1218,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
|
|||
struct kvm *kvm = vcpu->kvm;
|
||||
struct kvm_mmu_memory_cache *memcache = &vcpu->arch.mmu_page_cache;
|
||||
struct vm_area_struct *vma;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
pgprot_t mem_type = PAGE_S2;
|
||||
bool fault_ipa_uncached;
|
||||
bool logging_active = memslot_is_logging(memslot);
|
||||
|
@ -1346,7 +1346,7 @@ static void handle_access_fault(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa)
|
|||
{
|
||||
pmd_t *pmd;
|
||||
pte_t *pte;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
bool pfn_valid = false;
|
||||
|
||||
trace_kvm_access_fault(fault_ipa);
|
||||
|
|
|
@ -52,14 +52,13 @@ pin_page_for_write(const void __user *_addr, pte_t **ptep, spinlock_t **ptlp)
|
|||
*
|
||||
* Lock the page table for the destination and check
|
||||
* to see that it's still huge and whether or not we will
|
||||
* need to fault on write, or if we have a splitting THP.
|
||||
* need to fault on write.
|
||||
*/
|
||||
if (unlikely(pmd_thp_or_huge(*pmd))) {
|
||||
ptl = ¤t->mm->page_table_lock;
|
||||
spin_lock(ptl);
|
||||
if (unlikely(!pmd_thp_or_huge(*pmd)
|
||||
|| pmd_hugewillfault(*pmd)
|
||||
|| pmd_trans_splitting(*pmd))) {
|
||||
|| pmd_hugewillfault(*pmd))) {
|
||||
spin_unlock(ptl);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -330,7 +330,7 @@ void flush_dcache_page(struct page *page)
|
|||
mapping = page_mapping(page);
|
||||
|
||||
if (!cache_ops_need_broadcast() &&
|
||||
mapping && !page_mapped(page))
|
||||
mapping && !page_mapcount(page))
|
||||
clear_bit(PG_dcache_clean, &page->flags);
|
||||
else {
|
||||
__flush_dcache_page(mapping, page);
|
||||
|
@ -415,18 +415,3 @@ void __flush_anon_page(struct vm_area_struct *vma, struct page *page, unsigned l
|
|||
*/
|
||||
__cpuc_flush_dcache_area(page_address(page), PAGE_SIZE);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
|
||||
pmd_t *pmdp)
|
||||
{
|
||||
pmd_t pmd = pmd_mksplitting(*pmdp);
|
||||
VM_BUG_ON(address & ~PMD_MASK);
|
||||
set_pmd_at(vma->vm_mm, address, pmdp, pmd);
|
||||
|
||||
/* dummy IPI to serialise against fast_gup */
|
||||
kick_all_cpus_sync();
|
||||
}
|
||||
#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
|
|
@ -230,7 +230,8 @@ static inline bool vcpu_has_cache_enabled(struct kvm_vcpu *vcpu)
|
|||
return (vcpu_sys_reg(vcpu, SCTLR_EL1) & 0b101) == 0b101;
|
||||
}
|
||||
|
||||
static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu, pfn_t pfn,
|
||||
static inline void __coherent_cache_guest_page(struct kvm_vcpu *vcpu,
|
||||
kvm_pfn_t pfn,
|
||||
unsigned long size,
|
||||
bool ipa_uncached)
|
||||
{
|
||||
|
|
|
@ -353,21 +353,14 @@ static inline pgprot_t mk_sect_prot(pgprot_t prot)
|
|||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#define pmd_trans_huge(pmd) (pmd_val(pmd) && !(pmd_val(pmd) & PMD_TABLE_BIT))
|
||||
#define pmd_trans_splitting(pmd) pte_special(pmd_pte(pmd))
|
||||
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
struct vm_area_struct;
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
|
||||
pmd_t *pmdp);
|
||||
#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
||||
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
|
||||
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
|
||||
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
|
||||
#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))
|
||||
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
|
||||
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
|
||||
#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
|
||||
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
|
||||
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
|
||||
#define pmd_mknotpresent(pmd) (__pmd(pmd_val(pmd) & ~PMD_TYPE_MASK))
|
||||
|
|
|
@ -102,19 +102,3 @@ EXPORT_SYMBOL(flush_dcache_page);
|
|||
* Additional functions defined in assembly.
|
||||
*/
|
||||
EXPORT_SYMBOL(flush_icache_range);
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
|
||||
pmd_t *pmdp)
|
||||
{
|
||||
pmd_t pmd = pmd_mksplitting(*pmdp);
|
||||
|
||||
VM_BUG_ON(address & ~PMD_MASK);
|
||||
set_pmd_at(vma->vm_mm, address, pmdp, pmd);
|
||||
|
||||
/* dummy IPI to serialise against fast_gup */
|
||||
kick_all_cpus_sync();
|
||||
}
|
||||
#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
|
|
@ -83,11 +83,9 @@ static inline int get_order(unsigned long size)
|
|||
|
||||
#ifndef CONFIG_NEED_MULTIPLE_NODES
|
||||
|
||||
#define PHYS_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT)
|
||||
#define ARCH_PFN_OFFSET (CONFIG_PHYS_OFFSET >> PAGE_SHIFT)
|
||||
|
||||
#define pfn_to_page(pfn) (mem_map + ((pfn) - PHYS_PFN_OFFSET))
|
||||
#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + PHYS_PFN_OFFSET)
|
||||
#define pfn_valid(pfn) ((pfn) >= PHYS_PFN_OFFSET && (pfn) < (PHYS_PFN_OFFSET + max_mapnr))
|
||||
#define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && (pfn) < (ARCH_PFN_OFFSET + max_mapnr))
|
||||
#endif /* CONFIG_NEED_MULTIPLE_NODES */
|
||||
|
||||
#define virt_to_page(kaddr) pfn_to_page(__pa(kaddr) >> PAGE_SHIFT)
|
||||
|
@ -101,4 +99,6 @@ static inline int get_order(unsigned long size)
|
|||
*/
|
||||
#define HIGHMEM_START 0x20000000UL
|
||||
|
||||
#include <asm-generic/memory_model.h>
|
||||
|
||||
#endif /* __ASM_AVR32_PAGE_H */
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef struct page *pgtable_t;
|
|||
#define pgprot_val(x) ((x).pgprot)
|
||||
|
||||
#define __pte(x) ((pte_t) { (x) } )
|
||||
#define __pmd(x) ((pmd_t) { (x) } )
|
||||
#define __pmd(x) ((pmd_t) { { (x) } } )
|
||||
#define __pud(x) ((pud_t) { (x) } )
|
||||
#define __pgd(x) ((pgd_t) { (x) } )
|
||||
#define __pgprot(x) ((pgprot_t) { (x) } )
|
||||
|
|
|
@ -105,6 +105,7 @@ extern struct page *vmem_map;
|
|||
#ifdef CONFIG_DISCONTIGMEM
|
||||
# define page_to_pfn(page) ((unsigned long) (page - vmem_map))
|
||||
# define pfn_to_page(pfn) (vmem_map + (pfn))
|
||||
# define __pfn_to_phys(pfn) PFN_PHYS(pfn)
|
||||
#else
|
||||
# include <asm-generic/memory_model.h>
|
||||
#endif
|
||||
|
|
|
@ -36,9 +36,6 @@ config STACKTRACE_SUPPORT
|
|||
config LOCKDEP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
def_bool y
|
||||
|
||||
|
|
|
@ -67,9 +67,6 @@ config STACKTRACE_SUPPORT
|
|||
config LOCKDEP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
source "init/Kconfig"
|
||||
|
||||
source "kernel/Kconfig.freezer"
|
||||
|
|
|
@ -101,9 +101,9 @@
|
|||
#define CAUSEF_DC (_ULCAST_(1) << 27)
|
||||
|
||||
extern atomic_t kvm_mips_instance;
|
||||
extern pfn_t(*kvm_mips_gfn_to_pfn) (struct kvm *kvm, gfn_t gfn);
|
||||
extern void (*kvm_mips_release_pfn_clean) (pfn_t pfn);
|
||||
extern bool(*kvm_mips_is_error_pfn) (pfn_t pfn);
|
||||
extern kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
|
||||
extern void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
|
||||
extern bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
|
||||
|
||||
struct kvm_vm_stat {
|
||||
u32 remote_tlb_flush;
|
||||
|
|
|
@ -131,14 +131,12 @@
|
|||
/* Huge TLB page */
|
||||
#define _PAGE_HUGE_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
|
||||
#define _PAGE_HUGE (1 << _PAGE_HUGE_SHIFT)
|
||||
#define _PAGE_SPLITTING_SHIFT (_PAGE_HUGE_SHIFT + 1)
|
||||
#define _PAGE_SPLITTING (1 << _PAGE_SPLITTING_SHIFT)
|
||||
#endif /* CONFIG_64BIT && CONFIG_MIPS_HUGE_TLB_SUPPORT */
|
||||
|
||||
#if defined(CONFIG_CPU_MIPSR2) || defined(CONFIG_CPU_MIPSR6)
|
||||
/* XI - page cannot be executed */
|
||||
#ifdef _PAGE_SPLITTING_SHIFT
|
||||
#define _PAGE_NO_EXEC_SHIFT (_PAGE_SPLITTING_SHIFT + 1)
|
||||
#ifdef _PAGE_HUGE_SHIFT
|
||||
#define _PAGE_NO_EXEC_SHIFT (_PAGE_HUGE_SHIFT + 1)
|
||||
#else
|
||||
#define _PAGE_NO_EXEC_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
|
||||
#endif
|
||||
|
@ -153,8 +151,8 @@
|
|||
|
||||
#if defined(_PAGE_NO_READ_SHIFT)
|
||||
#define _PAGE_GLOBAL_SHIFT (_PAGE_NO_READ_SHIFT + 1)
|
||||
#elif defined(_PAGE_SPLITTING_SHIFT)
|
||||
#define _PAGE_GLOBAL_SHIFT (_PAGE_SPLITTING_SHIFT + 1)
|
||||
#elif defined(_PAGE_HUGE_SHIFT)
|
||||
#define _PAGE_GLOBAL_SHIFT (_PAGE_HUGE_SHIFT + 1)
|
||||
#else
|
||||
#define _PAGE_GLOBAL_SHIFT (_PAGE_MODIFIED_SHIFT + 1)
|
||||
#endif
|
||||
|
|
|
@ -482,27 +482,9 @@ static inline pmd_t pmd_mkhuge(pmd_t pmd)
|
|||
return pmd;
|
||||
}
|
||||
|
||||
static inline int pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
return !!(pmd_val(pmd) & _PAGE_SPLITTING);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mksplitting(pmd_t pmd)
|
||||
{
|
||||
pmd_val(pmd) |= _PAGE_SPLITTING;
|
||||
|
||||
return pmd;
|
||||
}
|
||||
|
||||
extern void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||||
pmd_t *pmdp, pmd_t pmd);
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
/* Extern to avoid header file madness */
|
||||
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long address,
|
||||
pmd_t *pmdp);
|
||||
|
||||
#define __HAVE_ARCH_PMD_WRITE
|
||||
static inline int pmd_write(pmd_t pmd)
|
||||
{
|
||||
|
|
|
@ -73,8 +73,10 @@
|
|||
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
|
||||
#define MADV_WILLNEED 3 /* will need these pages */
|
||||
#define MADV_DONTNEED 4 /* don't need these pages */
|
||||
#define MADV_FREE 5 /* free pages only if memory pressure */
|
||||
|
||||
/* common parameters: try to keep these consistent across architectures */
|
||||
#define MADV_FREE 8 /* free pages only if memory pressure */
|
||||
#define MADV_REMOVE 9 /* remove these pages & resources */
|
||||
#define MADV_DONTFORK 10 /* don't inherit across fork */
|
||||
#define MADV_DOFORK 11 /* do inherit across fork */
|
||||
|
|
|
@ -1525,7 +1525,7 @@ int kvm_mips_sync_icache(unsigned long va, struct kvm_vcpu *vcpu)
|
|||
struct kvm *kvm = vcpu->kvm;
|
||||
unsigned long pa;
|
||||
gfn_t gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
gfn = va >> PAGE_SHIFT;
|
||||
|
||||
|
|
|
@ -38,13 +38,13 @@ atomic_t kvm_mips_instance;
|
|||
EXPORT_SYMBOL(kvm_mips_instance);
|
||||
|
||||
/* These function pointers are initialized once the KVM module is loaded */
|
||||
pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
|
||||
kvm_pfn_t (*kvm_mips_gfn_to_pfn)(struct kvm *kvm, gfn_t gfn);
|
||||
EXPORT_SYMBOL(kvm_mips_gfn_to_pfn);
|
||||
|
||||
void (*kvm_mips_release_pfn_clean)(pfn_t pfn);
|
||||
void (*kvm_mips_release_pfn_clean)(kvm_pfn_t pfn);
|
||||
EXPORT_SYMBOL(kvm_mips_release_pfn_clean);
|
||||
|
||||
bool (*kvm_mips_is_error_pfn)(pfn_t pfn);
|
||||
bool (*kvm_mips_is_error_pfn)(kvm_pfn_t pfn);
|
||||
EXPORT_SYMBOL(kvm_mips_is_error_pfn);
|
||||
|
||||
uint32_t kvm_mips_get_kernel_asid(struct kvm_vcpu *vcpu)
|
||||
|
@ -144,7 +144,7 @@ EXPORT_SYMBOL(kvm_mips_dump_guest_tlbs);
|
|||
static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
|
||||
{
|
||||
int srcu_idx, err = 0;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
if (kvm->arch.guest_pmap[gfn] != KVM_INVALID_PAGE)
|
||||
return 0;
|
||||
|
@ -262,7 +262,7 @@ int kvm_mips_handle_kseg0_tlb_fault(unsigned long badvaddr,
|
|||
struct kvm_vcpu *vcpu)
|
||||
{
|
||||
gfn_t gfn;
|
||||
pfn_t pfn0, pfn1;
|
||||
kvm_pfn_t pfn0, pfn1;
|
||||
unsigned long vaddr = 0;
|
||||
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
|
||||
int even;
|
||||
|
@ -313,7 +313,7 @@ EXPORT_SYMBOL(kvm_mips_handle_kseg0_tlb_fault);
|
|||
int kvm_mips_handle_commpage_tlb_fault(unsigned long badvaddr,
|
||||
struct kvm_vcpu *vcpu)
|
||||
{
|
||||
pfn_t pfn0, pfn1;
|
||||
kvm_pfn_t pfn0, pfn1;
|
||||
unsigned long flags, old_entryhi = 0, vaddr = 0;
|
||||
unsigned long entrylo0 = 0, entrylo1 = 0;
|
||||
|
||||
|
@ -360,7 +360,7 @@ int kvm_mips_handle_mapped_seg_tlb_fault(struct kvm_vcpu *vcpu,
|
|||
{
|
||||
unsigned long entryhi = 0, entrylo0 = 0, entrylo1 = 0;
|
||||
struct kvm *kvm = vcpu->kvm;
|
||||
pfn_t pfn0, pfn1;
|
||||
kvm_pfn_t pfn0, pfn1;
|
||||
|
||||
if ((tlb->tlb_hi & VPN2_MASK) == 0) {
|
||||
pfn0 = 0;
|
||||
|
|
|
@ -587,7 +587,8 @@ static inline void local_r4k_flush_cache_page(void *args)
|
|||
* another ASID than the current one.
|
||||
*/
|
||||
map_coherent = (cpu_has_dc_aliases &&
|
||||
page_mapped(page) && !Page_dcache_dirty(page));
|
||||
page_mapcount(page) &&
|
||||
!Page_dcache_dirty(page));
|
||||
if (map_coherent)
|
||||
vaddr = kmap_coherent(page, addr);
|
||||
else
|
||||
|
|
|
@ -106,7 +106,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
|
|||
unsigned long addr = (unsigned long) page_address(page);
|
||||
|
||||
if (pages_do_alias(addr, vmaddr)) {
|
||||
if (page_mapped(page) && !Page_dcache_dirty(page)) {
|
||||
if (page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||
void *kaddr;
|
||||
|
||||
kaddr = kmap_coherent(page, vmaddr);
|
||||
|
|
|
@ -87,8 +87,6 @@ static int gup_huge_pmd(pmd_t pmd, unsigned long addr, unsigned long end,
|
|||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
(*nr)++;
|
||||
page++;
|
||||
refs++;
|
||||
|
@ -109,18 +107,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
|
|||
pmd_t pmd = *pmdp;
|
||||
|
||||
next = pmd_addr_end(addr, end);
|
||||
/*
|
||||
* The pmd_trans_splitting() check below explains why
|
||||
* pmdp_splitting_flush has to flush the tlb, to stop
|
||||
* this gup-fast code from running while we set the
|
||||
* splitting bit in the pmd. Returning zero will take
|
||||
* the slow path that will call wait_split_huge_page()
|
||||
* if the pmd is still in splitting state. gup-fast
|
||||
* can't because it has irq disabled and
|
||||
* wait_split_huge_page() would never return as the
|
||||
* tlb flush IPI wouldn't run.
|
||||
*/
|
||||
if (pmd_none(pmd) || pmd_trans_splitting(pmd))
|
||||
if (pmd_none(pmd))
|
||||
return 0;
|
||||
if (unlikely(pmd_huge(pmd))) {
|
||||
if (!gup_huge_pmd(pmd, addr, next, write, pages,nr))
|
||||
|
@ -153,8 +140,6 @@ static int gup_huge_pud(pud_t pud, unsigned long addr, unsigned long end,
|
|||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
(*nr)++;
|
||||
page++;
|
||||
refs++;
|
||||
|
|
|
@ -165,7 +165,7 @@ void copy_user_highpage(struct page *to, struct page *from,
|
|||
|
||||
vto = kmap_atomic(to);
|
||||
if (cpu_has_dc_aliases &&
|
||||
page_mapped(from) && !Page_dcache_dirty(from)) {
|
||||
page_mapcount(from) && !Page_dcache_dirty(from)) {
|
||||
vfrom = kmap_coherent(from, vaddr);
|
||||
copy_page(vto, vfrom);
|
||||
kunmap_coherent();
|
||||
|
@ -187,7 +187,7 @@ void copy_to_user_page(struct vm_area_struct *vma,
|
|||
unsigned long len)
|
||||
{
|
||||
if (cpu_has_dc_aliases &&
|
||||
page_mapped(page) && !Page_dcache_dirty(page)) {
|
||||
page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||
memcpy(vto, src, len);
|
||||
kunmap_coherent();
|
||||
|
@ -205,7 +205,7 @@ void copy_from_user_page(struct vm_area_struct *vma,
|
|||
unsigned long len)
|
||||
{
|
||||
if (cpu_has_dc_aliases &&
|
||||
page_mapped(page) && !Page_dcache_dirty(page)) {
|
||||
page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||
memcpy(dst, vfrom, len);
|
||||
kunmap_coherent();
|
||||
|
|
|
@ -62,20 +62,6 @@ void pmd_init(unsigned long addr, unsigned long pagetable)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long address,
|
||||
pmd_t *pmdp)
|
||||
{
|
||||
if (!pmd_trans_splitting(*pmdp)) {
|
||||
pmd_t pmd = pmd_mksplitting(*pmdp);
|
||||
set_pmd_at(vma->vm_mm, address, pmdp, pmd);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
pmd_t mk_pmd(struct page *page, pgprot_t prot)
|
||||
{
|
||||
pmd_t pmd;
|
||||
|
|
|
@ -240,7 +240,6 @@ static void output_pgtable_bits_defines(void)
|
|||
pr_define("_PAGE_MODIFIED_SHIFT %d\n", _PAGE_MODIFIED_SHIFT);
|
||||
#ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
|
||||
pr_define("_PAGE_HUGE_SHIFT %d\n", _PAGE_HUGE_SHIFT);
|
||||
pr_define("_PAGE_SPLITTING_SHIFT %d\n", _PAGE_SPLITTING_SHIFT);
|
||||
#endif
|
||||
#ifdef CONFIG_CPU_MIPSR2
|
||||
if (cpu_has_rixi) {
|
||||
|
|
|
@ -107,6 +107,7 @@ static inline int get_order(unsigned long size)
|
|||
#define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
|
||||
#define pfn_to_page(pfn) (mem_map + ((pfn) - __pfn_disp))
|
||||
#define page_to_pfn(page) ((unsigned long)((page) - mem_map) + __pfn_disp)
|
||||
#define __pfn_to_phys(pfn) PFN_PHYS(pfn)
|
||||
|
||||
#define pfn_valid(pfn) \
|
||||
({ \
|
||||
|
|
|
@ -79,9 +79,6 @@ config TIME_LOW_RES
|
|||
depends on SMP
|
||||
default y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
# unless you want to implement ACPI on PA-RISC ... ;-)
|
||||
config PM
|
||||
bool
|
||||
|
|
|
@ -43,8 +43,10 @@
|
|||
#define MADV_SPACEAVAIL 5 /* insure that resources are reserved */
|
||||
#define MADV_VPS_PURGE 6 /* Purge pages from VM page cache */
|
||||
#define MADV_VPS_INHERIT 7 /* Inherit parents page size */
|
||||
#define MADV_FREE 8 /* free pages only if memory pressure */
|
||||
|
||||
/* common/generic parameters */
|
||||
#define MADV_FREE 8 /* free pages only if memory pressure */
|
||||
#define MADV_REMOVE 9 /* remove these pages & resources */
|
||||
#define MADV_DONTFORK 10 /* don't inherit across fork */
|
||||
#define MADV_DOFORK 11 /* do inherit across fork */
|
||||
|
|
|
@ -47,9 +47,6 @@ config STACKTRACE_SUPPORT
|
|||
bool
|
||||
default y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config TRACE_IRQFLAGS_SUPPORT
|
||||
bool
|
||||
default y
|
||||
|
|
|
@ -256,13 +256,6 @@ static inline int pmd_trans_huge(pmd_t pmd)
|
|||
(_PAGE_PTE | _PAGE_THP_HUGE));
|
||||
}
|
||||
|
||||
static inline int pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
if (pmd_trans_huge(pmd))
|
||||
return pmd_val(pmd) & _PAGE_SPLITTING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int pmd_large(pmd_t pmd)
|
||||
{
|
||||
return !!(pmd_val(pmd) & _PAGE_PTE);
|
||||
|
@ -273,11 +266,6 @@ static inline pmd_t pmd_mknotpresent(pmd_t pmd)
|
|||
return __pmd(pmd_val(pmd) & ~_PAGE_PRESENT);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mksplitting(pmd_t pmd)
|
||||
{
|
||||
return __pmd(pmd_val(pmd) | _PAGE_SPLITTING);
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMD_SAME
|
||||
static inline int pmd_same(pmd_t pmd_a, pmd_t pmd_b)
|
||||
{
|
||||
|
|
|
@ -40,11 +40,6 @@
|
|||
#define _PAGE_SOFT_DIRTY 0x00000
|
||||
#endif
|
||||
|
||||
/*
|
||||
* THP pages can't be special. So use the _PAGE_SPECIAL
|
||||
*/
|
||||
#define _PAGE_SPLITTING _PAGE_SPECIAL
|
||||
|
||||
/*
|
||||
* We need to differentiate between explicit huge page and THP huge
|
||||
* page, since THP huge page also need to track real subpage details
|
||||
|
@ -54,9 +49,8 @@
|
|||
/*
|
||||
* set of bits not changed in pmd_modify.
|
||||
*/
|
||||
#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | \
|
||||
_PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_SPLITTING | \
|
||||
_PAGE_THP_HUGE | _PAGE_PTE | _PAGE_SOFT_DIRTY)
|
||||
#define _HPAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
|
||||
_PAGE_ACCESSED | _PAGE_THP_HUGE)
|
||||
|
||||
#ifdef CONFIG_PPC_64K_PAGES
|
||||
#include <asm/book3s/64/hash-64k.h>
|
||||
|
|
|
@ -223,9 +223,11 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)
|
|||
#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
|
||||
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
|
||||
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
|
||||
#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
|
||||
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
|
||||
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
|
||||
#define pmd_mkdirty(pmd) pte_pmd(pte_mkdirty(pmd_pte(pmd)))
|
||||
#define pmd_mkclean(pmd) pte_pmd(pte_mkclean(pmd_pte(pmd)))
|
||||
#define pmd_mkyoung(pmd) pte_pmd(pte_mkyoung(pmd_pte(pmd)))
|
||||
#define pmd_mkwrite(pmd) pte_pmd(pte_mkwrite(pmd_pte(pmd)))
|
||||
|
||||
|
@ -266,10 +268,6 @@ extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
|||
extern pmd_t pmdp_huge_get_and_clear(struct mm_struct *mm,
|
||||
unsigned long addr, pmd_t *pmdp);
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp);
|
||||
|
||||
extern pmd_t pmdp_collapse_flush(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp);
|
||||
#define pmdp_collapse_flush pmdp_collapse_flush
|
||||
|
|
|
@ -154,8 +154,8 @@ extern void kvmppc_set_bat(struct kvm_vcpu *vcpu, struct kvmppc_bat *bat,
|
|||
bool upper, u32 val);
|
||||
extern void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr);
|
||||
extern int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu);
|
||||
extern pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
|
||||
bool *writable);
|
||||
extern kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa,
|
||||
bool writing, bool *writable);
|
||||
extern void kvmppc_add_revmap_chain(struct kvm *kvm, struct revmap_entry *rev,
|
||||
unsigned long *rmap, long pte_index, int realmode);
|
||||
extern void kvmppc_update_rmap_change(unsigned long *rmap, unsigned long psize);
|
||||
|
|
|
@ -515,7 +515,7 @@ void kvmppc_claim_lpid(long lpid);
|
|||
void kvmppc_free_lpid(long lpid);
|
||||
void kvmppc_init_lpid(unsigned long nr_lpids);
|
||||
|
||||
static inline void kvmppc_mmu_flush_icache(pfn_t pfn)
|
||||
static inline void kvmppc_mmu_flush_icache(kvm_pfn_t pfn)
|
||||
{
|
||||
struct page *page;
|
||||
/*
|
||||
|
|
|
@ -366,7 +366,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(kvmppc_core_prepare_to_enter);
|
||||
|
||||
pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
|
||||
kvm_pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
|
||||
bool *writable)
|
||||
{
|
||||
ulong mp_pa = vcpu->arch.magic_page_pa & KVM_PAM;
|
||||
|
@ -379,9 +379,9 @@ pfn_t kvmppc_gpa_to_pfn(struct kvm_vcpu *vcpu, gpa_t gpa, bool writing,
|
|||
gpa &= ~0xFFFULL;
|
||||
if (unlikely(mp_pa) && unlikely((gpa & KVM_PAM) == mp_pa)) {
|
||||
ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
pfn = (pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
|
||||
pfn = (kvm_pfn_t)virt_to_phys((void*)shared_page) >> PAGE_SHIFT;
|
||||
get_page(pfn_to_page(pfn));
|
||||
if (writable)
|
||||
*writable = true;
|
||||
|
|
|
@ -142,7 +142,7 @@ extern char etext[];
|
|||
int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
|
||||
bool iswrite)
|
||||
{
|
||||
pfn_t hpaddr;
|
||||
kvm_pfn_t hpaddr;
|
||||
u64 vpn;
|
||||
u64 vsid;
|
||||
struct kvmppc_sid_map *map;
|
||||
|
|
|
@ -83,7 +83,7 @@ int kvmppc_mmu_map_page(struct kvm_vcpu *vcpu, struct kvmppc_pte *orig_pte,
|
|||
bool iswrite)
|
||||
{
|
||||
unsigned long vpn;
|
||||
pfn_t hpaddr;
|
||||
kvm_pfn_t hpaddr;
|
||||
ulong hash, hpteg;
|
||||
u64 vsid;
|
||||
int ret;
|
||||
|
|
|
@ -41,7 +41,7 @@ enum vcpu_ftr {
|
|||
#define E500_TLB_MAS2_ATTR (0x7f)
|
||||
|
||||
struct tlbe_ref {
|
||||
pfn_t pfn; /* valid only for TLB0, except briefly */
|
||||
kvm_pfn_t pfn; /* valid only for TLB0, except briefly */
|
||||
unsigned int flags; /* E500_TLB_* */
|
||||
};
|
||||
|
||||
|
|
|
@ -163,9 +163,9 @@ void kvmppc_map_magic(struct kvm_vcpu *vcpu)
|
|||
struct kvm_book3e_206_tlb_entry magic;
|
||||
ulong shared_page = ((ulong)vcpu->arch.shared) & PAGE_MASK;
|
||||
unsigned int stid;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
pfn = (pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
|
||||
pfn = (kvm_pfn_t)virt_to_phys((void *)shared_page) >> PAGE_SHIFT;
|
||||
get_page(pfn_to_page(pfn));
|
||||
|
||||
preempt_disable();
|
||||
|
@ -246,7 +246,7 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
|
|||
|
||||
static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
|
||||
struct kvm_book3e_206_tlb_entry *gtlbe,
|
||||
pfn_t pfn, unsigned int wimg)
|
||||
kvm_pfn_t pfn, unsigned int wimg)
|
||||
{
|
||||
ref->pfn = pfn;
|
||||
ref->flags = E500_TLB_VALID;
|
||||
|
@ -309,7 +309,7 @@ static void kvmppc_e500_setup_stlbe(
|
|||
int tsize, struct tlbe_ref *ref, u64 gvaddr,
|
||||
struct kvm_book3e_206_tlb_entry *stlbe)
|
||||
{
|
||||
pfn_t pfn = ref->pfn;
|
||||
kvm_pfn_t pfn = ref->pfn;
|
||||
u32 pr = vcpu->arch.shared->msr & MSR_PR;
|
||||
|
||||
BUG_ON(!(ref->flags & E500_TLB_VALID));
|
||||
|
|
|
@ -30,7 +30,7 @@ TRACE_EVENT(kvm_book3s_reenter,
|
|||
#ifdef CONFIG_PPC_BOOK3S_64
|
||||
|
||||
TRACE_EVENT(kvm_book3s_64_mmu_map,
|
||||
TP_PROTO(int rflags, ulong hpteg, ulong va, pfn_t hpaddr,
|
||||
TP_PROTO(int rflags, ulong hpteg, ulong va, kvm_pfn_t hpaddr,
|
||||
struct kvmppc_pte *orig_pte),
|
||||
TP_ARGS(rflags, hpteg, va, hpaddr, orig_pte),
|
||||
|
||||
|
|
|
@ -39,9 +39,6 @@ int __hash_page_thp(unsigned long ea, unsigned long access, unsigned long vsid,
|
|||
/* If PMD busy, retry the access */
|
||||
if (unlikely(old_pmd & _PAGE_BUSY))
|
||||
return 0;
|
||||
/* If PMD is trans splitting retry the access */
|
||||
if (unlikely(old_pmd & _PAGE_SPLITTING))
|
||||
return 0;
|
||||
/* If PMD permissions don't match, take page fault */
|
||||
if (unlikely(access & ~old_pmd))
|
||||
return 1;
|
||||
|
|
|
@ -958,10 +958,6 @@ pte_t *__find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
|
|||
/*
|
||||
* A hugepage collapse is captured by pmd_none, because
|
||||
* it mark the pmd none and do a hpte invalidate.
|
||||
*
|
||||
* We don't worry about pmd_trans_splitting here, The
|
||||
* caller if it needs to handle the splitting case
|
||||
* should check for that.
|
||||
*/
|
||||
if (pmd_none(pmd))
|
||||
return NULL;
|
||||
|
@ -999,7 +995,7 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
|
|||
{
|
||||
unsigned long mask;
|
||||
unsigned long pte_end;
|
||||
struct page *head, *page, *tail;
|
||||
struct page *head, *page;
|
||||
pte_t pte;
|
||||
int refs;
|
||||
|
||||
|
@ -1022,7 +1018,6 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
|
|||
head = pte_page(pte);
|
||||
|
||||
page = head + ((addr & (sz-1)) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
|
@ -1044,15 +1039,5 @@ int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
|
|
@ -603,55 +603,6 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
|||
return __pmdp_test_and_clear_young(vma->vm_mm, address, pmdp);
|
||||
}
|
||||
|
||||
/*
|
||||
* We mark the pmd splitting and invalidate all the hpte
|
||||
* entries for this hugepage.
|
||||
*/
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp)
|
||||
{
|
||||
unsigned long old, tmp;
|
||||
|
||||
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
||||
|
||||
#ifdef CONFIG_DEBUG_VM
|
||||
WARN_ON(!pmd_trans_huge(*pmdp));
|
||||
assert_spin_locked(&vma->vm_mm->page_table_lock);
|
||||
#endif
|
||||
|
||||
#ifdef PTE_ATOMIC_UPDATES
|
||||
|
||||
__asm__ __volatile__(
|
||||
"1: ldarx %0,0,%3\n\
|
||||
andi. %1,%0,%6\n\
|
||||
bne- 1b \n\
|
||||
oris %1,%0,%4@h \n\
|
||||
stdcx. %1,0,%3 \n\
|
||||
bne- 1b"
|
||||
: "=&r" (old), "=&r" (tmp), "=m" (*pmdp)
|
||||
: "r" (pmdp), "i" (_PAGE_SPLITTING), "m" (*pmdp), "i" (_PAGE_BUSY)
|
||||
: "cc" );
|
||||
#else
|
||||
old = pmd_val(*pmdp);
|
||||
*pmdp = __pmd(old | _PAGE_SPLITTING);
|
||||
#endif
|
||||
/*
|
||||
* If we didn't had the splitting flag set, go and flush the
|
||||
* HPTE entries.
|
||||
*/
|
||||
trace_hugepage_splitting(address, old);
|
||||
if (!(old & _PAGE_SPLITTING)) {
|
||||
/* We need to flush the hpte */
|
||||
if (old & _PAGE_HASHPTE)
|
||||
hpte_do_hugepage_flush(vma->vm_mm, address, pmdp, old);
|
||||
}
|
||||
/*
|
||||
* This ensures that generic code that rely on IRQ disabling
|
||||
* to prevent a parallel THP split work as expected.
|
||||
*/
|
||||
kick_all_cpus_sync();
|
||||
}
|
||||
|
||||
/*
|
||||
* We want to put the pgtable in pmd and use pgtable for tracking
|
||||
* the base page size hptes
|
||||
|
|
|
@ -135,7 +135,7 @@ static int subpage_walk_pmd_entry(pmd_t *pmd, unsigned long addr,
|
|||
unsigned long end, struct mm_walk *walk)
|
||||
{
|
||||
struct vm_area_struct *vma = walk->vma;
|
||||
split_huge_page_pmd(vma, addr, pmd);
|
||||
split_huge_pmd(vma, pmd, addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/of_device.h>
|
||||
#include <linux/of_platform.h>
|
||||
#include <linux/pfn_t.h>
|
||||
|
||||
#include <asm/page.h>
|
||||
#include <asm/prom.h>
|
||||
|
@ -142,15 +143,13 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
|
|||
*/
|
||||
static long
|
||||
axon_ram_direct_access(struct block_device *device, sector_t sector,
|
||||
void __pmem **kaddr, unsigned long *pfn)
|
||||
void __pmem **kaddr, pfn_t *pfn)
|
||||
{
|
||||
struct axon_ram_bank *bank = device->bd_disk->private_data;
|
||||
loff_t offset = (loff_t)sector << AXON_RAM_SECTOR_SHIFT;
|
||||
void *addr = (void *)(bank->ph_addr + offset);
|
||||
|
||||
*kaddr = (void __pmem *)addr;
|
||||
*pfn = virt_to_phys(addr) >> PAGE_SHIFT;
|
||||
|
||||
*kaddr = (void __pmem __force *) bank->io_addr + offset;
|
||||
*pfn = phys_to_pfn_t(bank->ph_addr + offset, PFN_DEV);
|
||||
return bank->size - offset;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,6 @@ config LOCKDEP_SUPPORT
|
|||
config STACKTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config RWSEM_GENERIC_SPINLOCK
|
||||
bool
|
||||
|
||||
|
|
|
@ -286,7 +286,6 @@ static inline int is_module_addr(void *addr)
|
|||
|
||||
#define _SEGMENT_ENTRY_DIRTY 0x2000 /* SW segment dirty bit */
|
||||
#define _SEGMENT_ENTRY_YOUNG 0x1000 /* SW segment young bit */
|
||||
#define _SEGMENT_ENTRY_SPLIT 0x0800 /* THP splitting bit */
|
||||
#define _SEGMENT_ENTRY_LARGE 0x0400 /* STE-format control, large page */
|
||||
#define _SEGMENT_ENTRY_READ 0x0002 /* SW segment read bit */
|
||||
#define _SEGMENT_ENTRY_WRITE 0x0001 /* SW segment write bit */
|
||||
|
@ -318,8 +317,6 @@ static inline int is_module_addr(void *addr)
|
|||
* SW-bits: y young, d dirty, r read, w write
|
||||
*/
|
||||
|
||||
#define _SEGMENT_ENTRY_SPLIT_BIT 11 /* THP splitting bit number */
|
||||
|
||||
/* Page status table bits for virtualization */
|
||||
#define PGSTE_ACC_BITS 0xf000000000000000UL
|
||||
#define PGSTE_FP_BIT 0x0800000000000000UL
|
||||
|
@ -523,10 +520,6 @@ static inline int pmd_bad(pmd_t pmd)
|
|||
return (pmd_val(pmd) & ~_SEGMENT_ENTRY_BITS) != 0;
|
||||
}
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long addr, pmd_t *pmdp);
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SET_ACCESS_FLAGS
|
||||
extern int pmdp_set_access_flags(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp,
|
||||
|
@ -1424,8 +1417,7 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
|
|||
if (pmd_large(pmd)) {
|
||||
pmd_val(pmd) &= _SEGMENT_ENTRY_ORIGIN_LARGE |
|
||||
_SEGMENT_ENTRY_DIRTY | _SEGMENT_ENTRY_YOUNG |
|
||||
_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_SPLIT |
|
||||
_SEGMENT_ENTRY_SOFT_DIRTY;
|
||||
_SEGMENT_ENTRY_LARGE | _SEGMENT_ENTRY_SOFT_DIRTY;
|
||||
pmd_val(pmd) |= massage_pgprot_pmd(newprot);
|
||||
if (!(pmd_val(pmd) & _SEGMENT_ENTRY_DIRTY))
|
||||
pmd_val(pmd) |= _SEGMENT_ENTRY_PROTECT;
|
||||
|
@ -1533,12 +1525,6 @@ extern void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
|
|||
#define __HAVE_ARCH_PGTABLE_WITHDRAW
|
||||
extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
|
||||
|
||||
static inline int pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
return (pmd_val(pmd) & _SEGMENT_ENTRY_LARGE) &&
|
||||
(pmd_val(pmd) & _SEGMENT_ENTRY_SPLIT);
|
||||
}
|
||||
|
||||
static inline void set_pmd_at(struct mm_struct *mm, unsigned long addr,
|
||||
pmd_t *pmdp, pmd_t entry)
|
||||
{
|
||||
|
|
|
@ -55,7 +55,7 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
unsigned long mask, result;
|
||||
struct page *head, *page, *tail;
|
||||
struct page *head, *page;
|
||||
int refs;
|
||||
|
||||
result = write ? 0 : _SEGMENT_ENTRY_PROTECT;
|
||||
|
@ -67,7 +67,6 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
refs = 0;
|
||||
head = pmd_page(pmd);
|
||||
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
|
@ -88,16 +87,6 @@ static inline int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -116,16 +105,7 @@ static inline int gup_pmd_range(pud_t *pudp, pud_t pud, unsigned long addr,
|
|||
pmd = *pmdp;
|
||||
barrier();
|
||||
next = pmd_addr_end(addr, end);
|
||||
/*
|
||||
* The pmd_trans_splitting() check below explains why
|
||||
* pmdp_splitting_flush() has to serialize with
|
||||
* smp_call_function() against our disabled IRQs, to stop
|
||||
* this gup-fast code from running while we set the
|
||||
* splitting bit in the pmd. Returning zero will take
|
||||
* the slow path that will call wait_split_huge_page()
|
||||
* if the pmd is still in splitting state.
|
||||
*/
|
||||
if (pmd_none(pmd) || pmd_trans_splitting(pmd))
|
||||
if (pmd_none(pmd))
|
||||
return 0;
|
||||
if (unlikely(pmd_large(pmd))) {
|
||||
/*
|
||||
|
|
|
@ -578,17 +578,29 @@ int gmap_fault(struct gmap *gmap, unsigned long gaddr,
|
|||
{
|
||||
unsigned long vmaddr;
|
||||
int rc;
|
||||
bool unlocked;
|
||||
|
||||
down_read(&gmap->mm->mmap_sem);
|
||||
|
||||
retry:
|
||||
unlocked = false;
|
||||
vmaddr = __gmap_translate(gmap, gaddr);
|
||||
if (IS_ERR_VALUE(vmaddr)) {
|
||||
rc = vmaddr;
|
||||
goto out_up;
|
||||
}
|
||||
if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags)) {
|
||||
if (fixup_user_fault(current, gmap->mm, vmaddr, fault_flags,
|
||||
&unlocked)) {
|
||||
rc = -EFAULT;
|
||||
goto out_up;
|
||||
}
|
||||
/*
|
||||
* In the case that fixup_user_fault unlocked the mmap_sem during
|
||||
* faultin redo __gmap_translate to not race with a map/unmap_segment.
|
||||
*/
|
||||
if (unlocked)
|
||||
goto retry;
|
||||
|
||||
rc = __gmap_link(gmap, gaddr, vmaddr);
|
||||
out_up:
|
||||
up_read(&gmap->mm->mmap_sem);
|
||||
|
@ -714,12 +726,14 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len)
|
|||
spinlock_t *ptl;
|
||||
pte_t *ptep, entry;
|
||||
pgste_t pgste;
|
||||
bool unlocked;
|
||||
int rc = 0;
|
||||
|
||||
if ((gaddr & ~PAGE_MASK) || (len & ~PAGE_MASK))
|
||||
return -EINVAL;
|
||||
down_read(&gmap->mm->mmap_sem);
|
||||
while (len) {
|
||||
unlocked = false;
|
||||
/* Convert gmap address and connect the page tables */
|
||||
addr = __gmap_translate(gmap, gaddr);
|
||||
if (IS_ERR_VALUE(addr)) {
|
||||
|
@ -727,10 +741,14 @@ int gmap_ipte_notify(struct gmap *gmap, unsigned long gaddr, unsigned long len)
|
|||
break;
|
||||
}
|
||||
/* Get the page mapped */
|
||||
if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE)) {
|
||||
if (fixup_user_fault(current, gmap->mm, addr, FAULT_FLAG_WRITE,
|
||||
&unlocked)) {
|
||||
rc = -EFAULT;
|
||||
break;
|
||||
}
|
||||
/* While trying to map mmap_sem got unlocked. Let us retry */
|
||||
if (unlocked)
|
||||
continue;
|
||||
rc = __gmap_link(gmap, gaddr, addr);
|
||||
if (rc)
|
||||
break;
|
||||
|
@ -791,9 +809,11 @@ int set_guest_storage_key(struct mm_struct *mm, unsigned long addr,
|
|||
spinlock_t *ptl;
|
||||
pgste_t old, new;
|
||||
pte_t *ptep;
|
||||
bool unlocked;
|
||||
|
||||
down_read(&mm->mmap_sem);
|
||||
retry:
|
||||
unlocked = false;
|
||||
ptep = get_locked_pte(mm, addr, &ptl);
|
||||
if (unlikely(!ptep)) {
|
||||
up_read(&mm->mmap_sem);
|
||||
|
@ -802,7 +822,12 @@ retry:
|
|||
if (!(pte_val(*ptep) & _PAGE_INVALID) &&
|
||||
(pte_val(*ptep) & _PAGE_PROTECT)) {
|
||||
pte_unmap_unlock(ptep, ptl);
|
||||
if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE)) {
|
||||
/*
|
||||
* We do not really care about unlocked. We will retry either
|
||||
* way. But this allows fixup_user_fault to enable userfaultfd.
|
||||
*/
|
||||
if (fixup_user_fault(current, mm, addr, FAULT_FLAG_WRITE,
|
||||
&unlocked)) {
|
||||
up_read(&mm->mmap_sem);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
@ -1305,22 +1330,6 @@ int pmdp_set_access_flags(struct vm_area_struct *vma,
|
|||
return 1;
|
||||
}
|
||||
|
||||
static void pmdp_splitting_flush_sync(void *arg)
|
||||
{
|
||||
/* Simply deliver the interrupt */
|
||||
}
|
||||
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
|
||||
pmd_t *pmdp)
|
||||
{
|
||||
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
||||
if (!test_and_set_bit(_SEGMENT_ENTRY_SPLIT_BIT,
|
||||
(unsigned long *) pmdp)) {
|
||||
/* need to serialize against gup-fast (IRQ disabled) */
|
||||
smp_call_function(pmdp_splitting_flush_sync, NULL, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void pgtable_trans_huge_deposit(struct mm_struct *mm, pmd_t *pmdp,
|
||||
pgtable_t pgtable)
|
||||
{
|
||||
|
|
|
@ -130,9 +130,6 @@ config STACKTRACE_SUPPORT
|
|||
config LOCKDEP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config ARCH_HAS_ILOG2_U32
|
||||
def_bool n
|
||||
|
||||
|
|
|
@ -241,7 +241,7 @@ static void sh4_flush_cache_page(void *args)
|
|||
*/
|
||||
map_coherent = (current_cpu_data.dcache.n_aliases &&
|
||||
test_bit(PG_dcache_clean, &page->flags) &&
|
||||
page_mapped(page));
|
||||
page_mapcount(page));
|
||||
if (map_coherent)
|
||||
vaddr = kmap_coherent(page, address);
|
||||
else
|
||||
|
|
|
@ -59,7 +59,7 @@ void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
|
|||
unsigned long vaddr, void *dst, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
|
||||
test_bit(PG_dcache_clean, &page->flags)) {
|
||||
void *vto = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||
memcpy(vto, src, len);
|
||||
|
@ -78,7 +78,7 @@ void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
|
|||
unsigned long vaddr, void *dst, const void *src,
|
||||
unsigned long len)
|
||||
{
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
|
||||
test_bit(PG_dcache_clean, &page->flags)) {
|
||||
void *vfrom = kmap_coherent(page, vaddr) + (vaddr & ~PAGE_MASK);
|
||||
memcpy(dst, vfrom, len);
|
||||
|
@ -97,7 +97,7 @@ void copy_user_highpage(struct page *to, struct page *from,
|
|||
|
||||
vto = kmap_atomic(to);
|
||||
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapped(from) &&
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapcount(from) &&
|
||||
test_bit(PG_dcache_clean, &from->flags)) {
|
||||
vfrom = kmap_coherent(from, vaddr);
|
||||
copy_page(vto, vfrom);
|
||||
|
@ -153,7 +153,7 @@ void __flush_anon_page(struct page *page, unsigned long vmaddr)
|
|||
unsigned long addr = (unsigned long) page_address(page);
|
||||
|
||||
if (pages_do_alias(addr, vmaddr)) {
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapped(page) &&
|
||||
if (boot_cpu_data.dcache.n_aliases && page_mapcount(page) &&
|
||||
test_bit(PG_dcache_clean, &page->flags)) {
|
||||
void *kaddr;
|
||||
|
||||
|
|
|
@ -101,10 +101,6 @@ config LOCKDEP_SUPPORT
|
|||
bool
|
||||
default y if SPARC64
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
bool
|
||||
default y if SPARC64
|
||||
|
||||
config ARCH_HIBERNATION_POSSIBLE
|
||||
def_bool y if SPARC64
|
||||
|
||||
|
|
|
@ -681,13 +681,6 @@ static inline unsigned long pmd_trans_huge(pmd_t pmd)
|
|||
return pte_val(pte) & _PAGE_PMD_HUGE;
|
||||
}
|
||||
|
||||
static inline unsigned long pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
pte_t pte = __pte(pmd_val(pmd));
|
||||
|
||||
return pmd_trans_huge(pmd) && pte_special(pte);
|
||||
}
|
||||
|
||||
#define has_transparent_hugepage() 1
|
||||
|
||||
static inline pmd_t pmd_mkold(pmd_t pmd)
|
||||
|
@ -717,6 +710,15 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
|
|||
return __pmd(pte_val(pte));
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkclean(pmd_t pmd)
|
||||
{
|
||||
pte_t pte = __pte(pmd_val(pmd));
|
||||
|
||||
pte = pte_mkclean(pte);
|
||||
|
||||
return __pmd(pte_val(pte));
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkyoung(pmd_t pmd)
|
||||
{
|
||||
pte_t pte = __pte(pmd_val(pmd));
|
||||
|
@ -735,15 +737,6 @@ static inline pmd_t pmd_mkwrite(pmd_t pmd)
|
|||
return __pmd(pte_val(pte));
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mksplitting(pmd_t pmd)
|
||||
{
|
||||
pte_t pte = __pte(pmd_val(pmd));
|
||||
|
||||
pte = pte_mkspecial(pte);
|
||||
|
||||
return __pmd(pte_val(pte));
|
||||
}
|
||||
|
||||
static inline pgprot_t pmd_pgprot(pmd_t entry)
|
||||
{
|
||||
unsigned long val = pmd_val(entry);
|
||||
|
|
|
@ -113,9 +113,6 @@ static unsigned int get_user_insn(unsigned long tpc)
|
|||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
if (pmd_trans_huge(*pmdp)) {
|
||||
if (pmd_trans_splitting(*pmdp))
|
||||
goto out_irq_enable;
|
||||
|
||||
pa = pmd_pfn(*pmdp) << PAGE_SHIFT;
|
||||
pa += tpc & ~HPAGE_MASK;
|
||||
|
||||
|
|
|
@ -56,8 +56,6 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
|||
put_page(head);
|
||||
return 0;
|
||||
}
|
||||
if (head != page)
|
||||
get_huge_page_tail(page);
|
||||
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
@ -70,7 +68,7 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
unsigned long end, int write, struct page **pages,
|
||||
int *nr)
|
||||
{
|
||||
struct page *head, *page, *tail;
|
||||
struct page *head, *page;
|
||||
int refs;
|
||||
|
||||
if (!(pmd_val(pmd) & _PAGE_VALID))
|
||||
|
@ -82,7 +80,6 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
refs = 0;
|
||||
head = pmd_page(pmd);
|
||||
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
|
||||
tail = page;
|
||||
do {
|
||||
VM_BUG_ON(compound_head(page) != head);
|
||||
pages[*nr] = page;
|
||||
|
@ -103,15 +100,6 @@ static int gup_huge_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Any tail page need their mapcount reference taken before we
|
||||
* return.
|
||||
*/
|
||||
while (refs--) {
|
||||
if (PageTail(tail))
|
||||
get_huge_page_tail(tail);
|
||||
tail++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -126,7 +114,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
|
|||
pmd_t pmd = *pmdp;
|
||||
|
||||
next = pmd_addr_end(addr, end);
|
||||
if (pmd_none(pmd) || pmd_trans_splitting(pmd))
|
||||
if (pmd_none(pmd))
|
||||
return 0;
|
||||
if (unlikely(pmd_large(pmd))) {
|
||||
if (!gup_huge_pmd(pmdp, pmd, addr, next,
|
||||
|
|
|
@ -489,16 +489,6 @@ static inline pmd_t pmd_modify(pmd_t pmd, pgprot_t newprot)
|
|||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
#define has_transparent_hugepage() 1
|
||||
#define pmd_trans_huge pmd_huge_page
|
||||
|
||||
static inline pmd_t pmd_mksplitting(pmd_t pmd)
|
||||
{
|
||||
return pte_pmd(hv_pte_set_client2(pmd_pte(pmd)));
|
||||
}
|
||||
|
||||
static inline int pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
return hv_pte_get_client2(pmd_pte(pmd));
|
||||
}
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
||||
/*
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
struct page;
|
||||
|
||||
#include <linux/pfn.h>
|
||||
#include <linux/types.h>
|
||||
#include <asm/vm-flags.h>
|
||||
|
||||
|
@ -52,7 +53,6 @@ typedef struct { unsigned long pgd; } pgd_t;
|
|||
#define pmd_val(x) ((x).pmd)
|
||||
#define __pmd(x) ((pmd_t) { (x) } )
|
||||
|
||||
typedef unsigned long long pfn_t;
|
||||
typedef unsigned long long phys_t;
|
||||
|
||||
#else
|
||||
|
@ -76,7 +76,6 @@ typedef struct { unsigned long pmd; } pmd_t;
|
|||
#define pte_is_zero(p) (!((p).pte & ~_PAGE_NEWPAGE))
|
||||
#define pte_set_val(p, phys, prot) (p).pte = (phys | pgprot_val(prot))
|
||||
|
||||
typedef unsigned long pfn_t;
|
||||
typedef unsigned long phys_t;
|
||||
|
||||
#endif
|
||||
|
@ -109,8 +108,8 @@ extern unsigned long uml_physmem;
|
|||
#define __pa(virt) to_phys((void *) (unsigned long) (virt))
|
||||
#define __va(phys) to_virt((unsigned long) (phys))
|
||||
|
||||
#define phys_to_pfn(p) ((pfn_t) ((p) >> PAGE_SHIFT))
|
||||
#define pfn_to_phys(pfn) ((phys_t) ((pfn) << PAGE_SHIFT))
|
||||
#define phys_to_pfn(p) ((p) >> PAGE_SHIFT)
|
||||
#define pfn_to_phys(pfn) PFN_PHYS(pfn)
|
||||
|
||||
#define pfn_valid(pfn) ((pfn) < max_mapnr)
|
||||
#define virt_addr_valid(v) pfn_valid(phys_to_pfn(__pa(v)))
|
||||
|
|
|
@ -98,7 +98,7 @@ static inline unsigned long pte_pfn(pte_t pte)
|
|||
return phys_to_pfn(pte_val(pte));
|
||||
}
|
||||
|
||||
static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
|
||||
static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot)
|
||||
{
|
||||
pte_t pte;
|
||||
phys_t phys = pfn_to_phys(page_nr);
|
||||
|
@ -107,7 +107,7 @@ static inline pte_t pfn_pte(pfn_t page_nr, pgprot_t pgprot)
|
|||
return pte;
|
||||
}
|
||||
|
||||
static inline pmd_t pfn_pmd(pfn_t page_nr, pgprot_t pgprot)
|
||||
static inline pmd_t pfn_pmd(unsigned long page_nr, pgprot_t pgprot)
|
||||
{
|
||||
return __pmd((page_nr << PAGE_SHIFT) | pgprot_val(pgprot));
|
||||
}
|
||||
|
|
|
@ -271,7 +271,7 @@ static inline int pte_same(pte_t pte_a, pte_t pte_b)
|
|||
|
||||
#define phys_to_page(phys) pfn_to_page(phys_to_pfn(phys))
|
||||
#define __virt_to_page(virt) phys_to_page(__pa(virt))
|
||||
#define page_to_phys(page) pfn_to_phys((pfn_t) page_to_pfn(page))
|
||||
#define page_to_phys(page) pfn_to_phys(page_to_pfn(page))
|
||||
#define virt_to_page(addr) __virt_to_page((const unsigned long) addr)
|
||||
|
||||
#define mk_pte(page, pgprot) \
|
||||
|
|
|
@ -34,9 +34,6 @@ config NO_IOPORT_MAP
|
|||
config STACKTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config LOCKDEP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
|
|
|
@ -180,9 +180,6 @@ config LOCKDEP_SUPPORT
|
|||
config STACKTRACE_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config HAVE_LATENCYTOP_SUPPORT
|
||||
def_bool y
|
||||
|
||||
config MMU
|
||||
def_bool y
|
||||
|
||||
|
|
|
@ -162,20 +162,22 @@ static inline int pmd_large(pmd_t pte)
|
|||
}
|
||||
|
||||
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
|
||||
static inline int pmd_trans_splitting(pmd_t pmd)
|
||||
{
|
||||
return pmd_val(pmd) & _PAGE_SPLITTING;
|
||||
}
|
||||
|
||||
static inline int pmd_trans_huge(pmd_t pmd)
|
||||
{
|
||||
return pmd_val(pmd) & _PAGE_PSE;
|
||||
return (pmd_val(pmd) & (_PAGE_PSE|_PAGE_DEVMAP)) == _PAGE_PSE;
|
||||
}
|
||||
|
||||
static inline int has_transparent_hugepage(void)
|
||||
{
|
||||
return cpu_has_pse;
|
||||
}
|
||||
|
||||
#ifdef __HAVE_ARCH_PTE_DEVMAP
|
||||
static inline int pmd_devmap(pmd_t pmd)
|
||||
{
|
||||
return !!(pmd_val(pmd) & _PAGE_DEVMAP);
|
||||
}
|
||||
#endif
|
||||
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
|
||||
|
||||
static inline pte_t pte_set_flags(pte_t pte, pteval_t set)
|
||||
|
@ -252,6 +254,11 @@ static inline pte_t pte_mkspecial(pte_t pte)
|
|||
return pte_set_flags(pte, _PAGE_SPECIAL);
|
||||
}
|
||||
|
||||
static inline pte_t pte_mkdevmap(pte_t pte)
|
||||
{
|
||||
return pte_set_flags(pte, _PAGE_SPECIAL|_PAGE_DEVMAP);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_set_flags(pmd_t pmd, pmdval_t set)
|
||||
{
|
||||
pmdval_t v = native_pmd_val(pmd);
|
||||
|
@ -271,6 +278,11 @@ static inline pmd_t pmd_mkold(pmd_t pmd)
|
|||
return pmd_clear_flags(pmd, _PAGE_ACCESSED);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkclean(pmd_t pmd)
|
||||
{
|
||||
return pmd_clear_flags(pmd, _PAGE_DIRTY);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_wrprotect(pmd_t pmd)
|
||||
{
|
||||
return pmd_clear_flags(pmd, _PAGE_RW);
|
||||
|
@ -281,6 +293,11 @@ static inline pmd_t pmd_mkdirty(pmd_t pmd)
|
|||
return pmd_set_flags(pmd, _PAGE_DIRTY | _PAGE_SOFT_DIRTY);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkdevmap(pmd_t pmd)
|
||||
{
|
||||
return pmd_set_flags(pmd, _PAGE_DEVMAP);
|
||||
}
|
||||
|
||||
static inline pmd_t pmd_mkhuge(pmd_t pmd)
|
||||
{
|
||||
return pmd_set_flags(pmd, _PAGE_PSE);
|
||||
|
@ -462,6 +479,13 @@ static inline int pte_present(pte_t a)
|
|||
return pte_flags(a) & (_PAGE_PRESENT | _PAGE_PROTNONE);
|
||||
}
|
||||
|
||||
#ifdef __HAVE_ARCH_PTE_DEVMAP
|
||||
static inline int pte_devmap(pte_t a)
|
||||
{
|
||||
return (pte_flags(a) & _PAGE_DEVMAP) == _PAGE_DEVMAP;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define pte_accessible pte_accessible
|
||||
static inline bool pte_accessible(struct mm_struct *mm, pte_t a)
|
||||
{
|
||||
|
@ -808,10 +832,6 @@ extern int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
|||
unsigned long address, pmd_t *pmdp);
|
||||
|
||||
|
||||
#define __HAVE_ARCH_PMDP_SPLITTING_FLUSH
|
||||
extern void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long addr, pmd_t *pmdp);
|
||||
|
||||
#define __HAVE_ARCH_PMD_WRITE
|
||||
static inline int pmd_write(pmd_t pmd)
|
||||
{
|
||||
|
|
|
@ -22,10 +22,11 @@
|
|||
#define _PAGE_BIT_PAT_LARGE 12 /* On 2MB or 1GB pages */
|
||||
#define _PAGE_BIT_SPECIAL _PAGE_BIT_SOFTW1
|
||||
#define _PAGE_BIT_CPA_TEST _PAGE_BIT_SOFTW1
|
||||
#define _PAGE_BIT_SPLITTING _PAGE_BIT_SOFTW2 /* only valid on a PSE pmd */
|
||||
#define _PAGE_BIT_HIDDEN _PAGE_BIT_SOFTW3 /* hidden by kmemcheck */
|
||||
#define _PAGE_BIT_SOFT_DIRTY _PAGE_BIT_SOFTW3 /* software dirty tracking */
|
||||
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
|
||||
#define _PAGE_BIT_SOFTW4 58 /* available for programmer */
|
||||
#define _PAGE_BIT_DEVMAP _PAGE_BIT_SOFTW4
|
||||
#define _PAGE_BIT_NX 63 /* No execute: only valid after cpuid check */
|
||||
|
||||
/* If _PAGE_BIT_PRESENT is clear, we use these: */
|
||||
/* - if the user mapped it with PROT_NONE; pte_present gives true */
|
||||
|
@ -46,7 +47,6 @@
|
|||
#define _PAGE_PAT_LARGE (_AT(pteval_t, 1) << _PAGE_BIT_PAT_LARGE)
|
||||
#define _PAGE_SPECIAL (_AT(pteval_t, 1) << _PAGE_BIT_SPECIAL)
|
||||
#define _PAGE_CPA_TEST (_AT(pteval_t, 1) << _PAGE_BIT_CPA_TEST)
|
||||
#define _PAGE_SPLITTING (_AT(pteval_t, 1) << _PAGE_BIT_SPLITTING)
|
||||
#define __HAVE_ARCH_PTE_SPECIAL
|
||||
|
||||
#ifdef CONFIG_KMEMCHECK
|
||||
|
@ -85,8 +85,11 @@
|
|||
|
||||
#if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE)
|
||||
#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX)
|
||||
#define _PAGE_DEVMAP (_AT(u64, 1) << _PAGE_BIT_DEVMAP)
|
||||
#define __HAVE_ARCH_PTE_DEVMAP
|
||||
#else
|
||||
#define _PAGE_NX (_AT(pteval_t, 0))
|
||||
#define _PAGE_DEVMAP (_AT(pteval_t, 0))
|
||||
#endif
|
||||
|
||||
#define _PAGE_PROTNONE (_AT(pteval_t, 1) << _PAGE_BIT_PROTNONE)
|
||||
|
|
|
@ -132,12 +132,7 @@ static inline void arch_clear_pmem(void __pmem *addr, size_t size)
|
|||
{
|
||||
void *vaddr = (void __force *)addr;
|
||||
|
||||
/* TODO: implement the zeroing via non-temporal writes */
|
||||
if (size == PAGE_SIZE && ((unsigned long)vaddr & ~PAGE_MASK) == 0)
|
||||
clear_page(vaddr);
|
||||
else
|
||||
memset(vaddr, 0, size);
|
||||
|
||||
memset(vaddr, 0, size);
|
||||
__arch_wb_cache_pmem(vaddr, size);
|
||||
}
|
||||
|
||||
|
|
|
@ -175,7 +175,11 @@ static void mark_screen_rdonly(struct mm_struct *mm)
|
|||
if (pud_none_or_clear_bad(pud))
|
||||
goto out;
|
||||
pmd = pmd_offset(pud, 0xA0000);
|
||||
split_huge_page_pmd_mm(mm, 0xA0000, pmd);
|
||||
|
||||
if (pmd_trans_huge(*pmd)) {
|
||||
struct vm_area_struct *vma = find_vma(mm, 0xA0000);
|
||||
split_huge_pmd(vma, pmd, 0xA0000);
|
||||
}
|
||||
if (pmd_none_or_clear_bad(pmd))
|
||||
goto out;
|
||||
pte = pte_offset_map_lock(mm, pmd, 0xA0000, &ptl);
|
||||
|
|
|
@ -43,11 +43,11 @@ static int kvm_iommu_unmap_memslots(struct kvm *kvm);
|
|||
static void kvm_iommu_put_pages(struct kvm *kvm,
|
||||
gfn_t base_gfn, unsigned long npages);
|
||||
|
||||
static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
|
||||
static kvm_pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
|
||||
unsigned long npages)
|
||||
{
|
||||
gfn_t end_gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
pfn = gfn_to_pfn_memslot(slot, gfn);
|
||||
end_gfn = gfn + npages;
|
||||
|
@ -62,7 +62,8 @@ static pfn_t kvm_pin_pages(struct kvm_memory_slot *slot, gfn_t gfn,
|
|||
return pfn;
|
||||
}
|
||||
|
||||
static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
|
||||
static void kvm_unpin_pages(struct kvm *kvm, kvm_pfn_t pfn,
|
||||
unsigned long npages)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
|
@ -73,7 +74,7 @@ static void kvm_unpin_pages(struct kvm *kvm, pfn_t pfn, unsigned long npages)
|
|||
int kvm_iommu_map_pages(struct kvm *kvm, struct kvm_memory_slot *slot)
|
||||
{
|
||||
gfn_t gfn, end_gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
int r = 0;
|
||||
struct iommu_domain *domain = kvm->arch.iommu_domain;
|
||||
int flags;
|
||||
|
@ -275,7 +276,7 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
|
|||
{
|
||||
struct iommu_domain *domain;
|
||||
gfn_t end_gfn, gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
u64 phys;
|
||||
|
||||
domain = kvm->arch.iommu_domain;
|
||||
|
|
|
@ -259,7 +259,7 @@ static unsigned get_mmio_spte_access(u64 spte)
|
|||
}
|
||||
|
||||
static bool set_mmio_spte(struct kvm_vcpu *vcpu, u64 *sptep, gfn_t gfn,
|
||||
pfn_t pfn, unsigned access)
|
||||
kvm_pfn_t pfn, unsigned access)
|
||||
{
|
||||
if (unlikely(is_noslot_pfn(pfn))) {
|
||||
mark_mmio_spte(vcpu, sptep, gfn, access);
|
||||
|
@ -320,7 +320,7 @@ static int is_last_spte(u64 pte, int level)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static pfn_t spte_to_pfn(u64 pte)
|
||||
static kvm_pfn_t spte_to_pfn(u64 pte)
|
||||
{
|
||||
return (pte & PT64_BASE_ADDR_MASK) >> PAGE_SHIFT;
|
||||
}
|
||||
|
@ -582,7 +582,7 @@ static bool mmu_spte_update(u64 *sptep, u64 new_spte)
|
|||
*/
|
||||
static int mmu_spte_clear_track_bits(u64 *sptep)
|
||||
{
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
u64 old_spte = *sptep;
|
||||
|
||||
if (!spte_has_volatile_bits(old_spte))
|
||||
|
@ -1372,7 +1372,7 @@ static int kvm_set_pte_rmapp(struct kvm *kvm, struct kvm_rmap_head *rmap_head,
|
|||
int need_flush = 0;
|
||||
u64 new_spte;
|
||||
pte_t *ptep = (pte_t *)data;
|
||||
pfn_t new_pfn;
|
||||
kvm_pfn_t new_pfn;
|
||||
|
||||
WARN_ON(pte_huge(*ptep));
|
||||
new_pfn = pte_pfn(*ptep);
|
||||
|
@ -2450,7 +2450,7 @@ static int mmu_need_write_protect(struct kvm_vcpu *vcpu, gfn_t gfn,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool kvm_is_mmio_pfn(pfn_t pfn)
|
||||
static bool kvm_is_mmio_pfn(kvm_pfn_t pfn)
|
||||
{
|
||||
if (pfn_valid(pfn))
|
||||
return !is_zero_pfn(pfn) && PageReserved(pfn_to_page(pfn));
|
||||
|
@ -2460,7 +2460,7 @@ static bool kvm_is_mmio_pfn(pfn_t pfn)
|
|||
|
||||
static int set_spte(struct kvm_vcpu *vcpu, u64 *sptep,
|
||||
unsigned pte_access, int level,
|
||||
gfn_t gfn, pfn_t pfn, bool speculative,
|
||||
gfn_t gfn, kvm_pfn_t pfn, bool speculative,
|
||||
bool can_unsync, bool host_writable)
|
||||
{
|
||||
u64 spte;
|
||||
|
@ -2539,7 +2539,7 @@ done:
|
|||
}
|
||||
|
||||
static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
|
||||
int write_fault, int level, gfn_t gfn, pfn_t pfn,
|
||||
int write_fault, int level, gfn_t gfn, kvm_pfn_t pfn,
|
||||
bool speculative, bool host_writable)
|
||||
{
|
||||
int was_rmapped = 0;
|
||||
|
@ -2602,7 +2602,7 @@ static bool mmu_set_spte(struct kvm_vcpu *vcpu, u64 *sptep, unsigned pte_access,
|
|||
return emulate;
|
||||
}
|
||||
|
||||
static pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
|
||||
static kvm_pfn_t pte_prefetch_gfn_to_pfn(struct kvm_vcpu *vcpu, gfn_t gfn,
|
||||
bool no_dirty_log)
|
||||
{
|
||||
struct kvm_memory_slot *slot;
|
||||
|
@ -2684,7 +2684,7 @@ static void direct_pte_prefetch(struct kvm_vcpu *vcpu, u64 *sptep)
|
|||
}
|
||||
|
||||
static int __direct_map(struct kvm_vcpu *vcpu, int write, int map_writable,
|
||||
int level, gfn_t gfn, pfn_t pfn, bool prefault)
|
||||
int level, gfn_t gfn, kvm_pfn_t pfn, bool prefault)
|
||||
{
|
||||
struct kvm_shadow_walk_iterator iterator;
|
||||
struct kvm_mmu_page *sp;
|
||||
|
@ -2732,7 +2732,7 @@ static void kvm_send_hwpoison_signal(unsigned long address, struct task_struct *
|
|||
send_sig_info(SIGBUS, &info, tsk);
|
||||
}
|
||||
|
||||
static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
|
||||
static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, kvm_pfn_t pfn)
|
||||
{
|
||||
/*
|
||||
* Do not cache the mmio info caused by writing the readonly gfn
|
||||
|
@ -2752,9 +2752,10 @@ static int kvm_handle_bad_page(struct kvm_vcpu *vcpu, gfn_t gfn, pfn_t pfn)
|
|||
}
|
||||
|
||||
static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
|
||||
gfn_t *gfnp, pfn_t *pfnp, int *levelp)
|
||||
gfn_t *gfnp, kvm_pfn_t *pfnp,
|
||||
int *levelp)
|
||||
{
|
||||
pfn_t pfn = *pfnp;
|
||||
kvm_pfn_t pfn = *pfnp;
|
||||
gfn_t gfn = *gfnp;
|
||||
int level = *levelp;
|
||||
|
||||
|
@ -2793,7 +2794,7 @@ static void transparent_hugepage_adjust(struct kvm_vcpu *vcpu,
|
|||
}
|
||||
|
||||
static bool handle_abnormal_pfn(struct kvm_vcpu *vcpu, gva_t gva, gfn_t gfn,
|
||||
pfn_t pfn, unsigned access, int *ret_val)
|
||||
kvm_pfn_t pfn, unsigned access, int *ret_val)
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
|
@ -2947,7 +2948,7 @@ exit:
|
|||
}
|
||||
|
||||
static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
|
||||
gva_t gva, pfn_t *pfn, bool write, bool *writable);
|
||||
gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable);
|
||||
static void make_mmu_pages_available(struct kvm_vcpu *vcpu);
|
||||
|
||||
static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
|
||||
|
@ -2956,7 +2957,7 @@ static int nonpaging_map(struct kvm_vcpu *vcpu, gva_t v, u32 error_code,
|
|||
int r;
|
||||
int level;
|
||||
bool force_pt_level = false;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
unsigned long mmu_seq;
|
||||
bool map_writable, write = error_code & PFERR_WRITE_MASK;
|
||||
|
||||
|
@ -3410,7 +3411,7 @@ static bool can_do_async_pf(struct kvm_vcpu *vcpu)
|
|||
}
|
||||
|
||||
static bool try_async_pf(struct kvm_vcpu *vcpu, bool prefault, gfn_t gfn,
|
||||
gva_t gva, pfn_t *pfn, bool write, bool *writable)
|
||||
gva_t gva, kvm_pfn_t *pfn, bool write, bool *writable)
|
||||
{
|
||||
struct kvm_memory_slot *slot;
|
||||
bool async;
|
||||
|
@ -3448,7 +3449,7 @@ check_hugepage_cache_consistency(struct kvm_vcpu *vcpu, gfn_t gfn, int level)
|
|||
static int tdp_page_fault(struct kvm_vcpu *vcpu, gva_t gpa, u32 error_code,
|
||||
bool prefault)
|
||||
{
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
int r;
|
||||
int level;
|
||||
bool force_pt_level;
|
||||
|
@ -4601,7 +4602,7 @@ static bool kvm_mmu_zap_collapsible_spte(struct kvm *kvm,
|
|||
u64 *sptep;
|
||||
struct rmap_iterator iter;
|
||||
int need_tlb_flush = 0;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
struct kvm_mmu_page *sp;
|
||||
|
||||
restart:
|
||||
|
|
|
@ -97,7 +97,7 @@ static void audit_mappings(struct kvm_vcpu *vcpu, u64 *sptep, int level)
|
|||
{
|
||||
struct kvm_mmu_page *sp;
|
||||
gfn_t gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
hpa_t hpa;
|
||||
|
||||
sp = page_header(__pa(sptep));
|
||||
|
|
|
@ -456,7 +456,7 @@ FNAME(prefetch_gpte)(struct kvm_vcpu *vcpu, struct kvm_mmu_page *sp,
|
|||
{
|
||||
unsigned pte_access;
|
||||
gfn_t gfn;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
if (FNAME(prefetch_invalid_gpte)(vcpu, sp, spte, gpte))
|
||||
return false;
|
||||
|
@ -551,7 +551,7 @@ static void FNAME(pte_prefetch)(struct kvm_vcpu *vcpu, struct guest_walker *gw,
|
|||
static int FNAME(fetch)(struct kvm_vcpu *vcpu, gva_t addr,
|
||||
struct guest_walker *gw,
|
||||
int write_fault, int hlevel,
|
||||
pfn_t pfn, bool map_writable, bool prefault)
|
||||
kvm_pfn_t pfn, bool map_writable, bool prefault)
|
||||
{
|
||||
struct kvm_mmu_page *sp = NULL;
|
||||
struct kvm_shadow_walk_iterator it;
|
||||
|
@ -694,7 +694,7 @@ static int FNAME(page_fault)(struct kvm_vcpu *vcpu, gva_t addr, u32 error_code,
|
|||
int user_fault = error_code & PFERR_USER_MASK;
|
||||
struct guest_walker walker;
|
||||
int r;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
int level = PT_PAGE_TABLE_LEVEL;
|
||||
bool force_pt_level = false;
|
||||
unsigned long mmu_seq;
|
||||
|
|
|
@ -4251,7 +4251,7 @@ out:
|
|||
static int init_rmode_identity_map(struct kvm *kvm)
|
||||
{
|
||||
int i, idx, r = 0;
|
||||
pfn_t identity_map_pfn;
|
||||
kvm_pfn_t identity_map_pfn;
|
||||
u32 tmp;
|
||||
|
||||
if (!enable_ept)
|
||||
|
|
|
@ -5148,7 +5148,7 @@ static bool reexecute_instruction(struct kvm_vcpu *vcpu, gva_t cr2,
|
|||
int emulation_type)
|
||||
{
|
||||
gpa_t gpa = cr2;
|
||||
pfn_t pfn;
|
||||
kvm_pfn_t pfn;
|
||||
|
||||
if (emulation_type & EMULTYPE_NO_REEXECUTE)
|
||||
return false;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <linux/vmstat.h>
|
||||
#include <linux/highmem.h>
|
||||
#include <linux/swap.h>
|
||||
#include <linux/memremap.h>
|
||||
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
|
@ -63,6 +64,16 @@ retry:
|
|||
#endif
|
||||
}
|
||||
|
||||
static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages)
|
||||
{
|
||||
while ((*nr) - nr_start) {
|
||||
struct page *page = pages[--(*nr)];
|
||||
|
||||
ClearPageReferenced(page);
|
||||
put_page(page);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The performance critical leaf functions are made noinline otherwise gcc
|
||||
* inlines everything into a single function which results in too much
|
||||
|
@ -71,7 +82,9 @@ retry:
|
|||
static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
struct dev_pagemap *pgmap = NULL;
|
||||
unsigned long mask;
|
||||
int nr_start = *nr;
|
||||
pte_t *ptep;
|
||||
|
||||
mask = _PAGE_PRESENT|_PAGE_USER;
|
||||
|
@ -89,13 +102,21 @@ static noinline int gup_pte_range(pmd_t pmd, unsigned long addr,
|
|||
return 0;
|
||||
}
|
||||
|
||||
if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
|
||||
page = pte_page(pte);
|
||||
if (pte_devmap(pte)) {
|
||||
pgmap = get_dev_pagemap(pte_pfn(pte), pgmap);
|
||||
if (unlikely(!pgmap)) {
|
||||
undo_dev_pagemap(nr, nr_start, pages);
|
||||
pte_unmap(ptep);
|
||||
return 0;
|
||||
}
|
||||
} else if ((pte_flags(pte) & (mask | _PAGE_SPECIAL)) != mask) {
|
||||
pte_unmap(ptep);
|
||||
return 0;
|
||||
}
|
||||
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
|
||||
page = pte_page(pte);
|
||||
get_page(page);
|
||||
put_dev_pagemap(pgmap);
|
||||
SetPageReferenced(page);
|
||||
pages[*nr] = page;
|
||||
(*nr)++;
|
||||
|
@ -114,6 +135,32 @@ static inline void get_head_page_multiple(struct page *page, int nr)
|
|||
SetPageReferenced(page);
|
||||
}
|
||||
|
||||
static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, struct page **pages, int *nr)
|
||||
{
|
||||
int nr_start = *nr;
|
||||
unsigned long pfn = pmd_pfn(pmd);
|
||||
struct dev_pagemap *pgmap = NULL;
|
||||
|
||||
pfn += (addr & ~PMD_MASK) >> PAGE_SHIFT;
|
||||
do {
|
||||
struct page *page = pfn_to_page(pfn);
|
||||
|
||||
pgmap = get_dev_pagemap(pfn, pgmap);
|
||||
if (unlikely(!pgmap)) {
|
||||
undo_dev_pagemap(nr, nr_start, pages);
|
||||
return 0;
|
||||
}
|
||||
SetPageReferenced(page);
|
||||
pages[*nr] = page;
|
||||
get_page(page);
|
||||
put_dev_pagemap(pgmap);
|
||||
(*nr)++;
|
||||
pfn++;
|
||||
} while (addr += PAGE_SIZE, addr != end);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
||||
unsigned long end, int write, struct page **pages, int *nr)
|
||||
{
|
||||
|
@ -126,9 +173,13 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
|||
mask |= _PAGE_RW;
|
||||
if ((pmd_flags(pmd) & mask) != mask)
|
||||
return 0;
|
||||
|
||||
VM_BUG_ON(!pfn_valid(pmd_pfn(pmd)));
|
||||
if (pmd_devmap(pmd))
|
||||
return __gup_device_huge_pmd(pmd, addr, end, pages, nr);
|
||||
|
||||
/* hugepages are never "special" */
|
||||
VM_BUG_ON(pmd_flags(pmd) & _PAGE_SPECIAL);
|
||||
VM_BUG_ON(!pfn_valid(pmd_pfn(pmd)));
|
||||
|
||||
refs = 0;
|
||||
head = pmd_page(pmd);
|
||||
|
@ -136,8 +187,6 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
|||
do {
|
||||
VM_BUG_ON_PAGE(compound_head(page) != head, page);
|
||||
pages[*nr] = page;
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
(*nr)++;
|
||||
page++;
|
||||
refs++;
|
||||
|
@ -158,18 +207,7 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
|
|||
pmd_t pmd = *pmdp;
|
||||
|
||||
next = pmd_addr_end(addr, end);
|
||||
/*
|
||||
* The pmd_trans_splitting() check below explains why
|
||||
* pmdp_splitting_flush has to flush the tlb, to stop
|
||||
* this gup-fast code from running while we set the
|
||||
* splitting bit in the pmd. Returning zero will take
|
||||
* the slow path that will call wait_split_huge_page()
|
||||
* if the pmd is still in splitting state. gup-fast
|
||||
* can't because it has irq disabled and
|
||||
* wait_split_huge_page() would never return as the
|
||||
* tlb flush IPI wouldn't run.
|
||||
*/
|
||||
if (pmd_none(pmd) || pmd_trans_splitting(pmd))
|
||||
if (pmd_none(pmd))
|
||||
return 0;
|
||||
if (unlikely(pmd_large(pmd) || !pmd_present(pmd))) {
|
||||
/*
|
||||
|
@ -212,8 +250,6 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
|
|||
do {
|
||||
VM_BUG_ON_PAGE(compound_head(page) != head, page);
|
||||
pages[*nr] = page;
|
||||
if (PageTail(page))
|
||||
get_huge_page_tail(page);
|
||||
(*nr)++;
|
||||
page++;
|
||||
refs++;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/module.h>
|
||||
#include <linux/memory.h>
|
||||
#include <linux/memory_hotplug.h>
|
||||
#include <linux/memremap.h>
|
||||
#include <linux/nmi.h>
|
||||
#include <linux/gfp.h>
|
||||
#include <linux/kcore.h>
|
||||
|
@ -714,6 +715,12 @@ static void __meminit free_pagetable(struct page *page, int order)
|
|||
{
|
||||
unsigned long magic;
|
||||
unsigned int nr_pages = 1 << order;
|
||||
struct vmem_altmap *altmap = to_vmem_altmap((unsigned long) page);
|
||||
|
||||
if (altmap) {
|
||||
vmem_altmap_free(altmap, nr_pages);
|
||||
return;
|
||||
}
|
||||
|
||||
/* bootmem page has reserved flag */
|
||||
if (PageReserved(page)) {
|
||||
|
@ -1017,13 +1024,19 @@ int __ref arch_remove_memory(u64 start, u64 size)
|
|||
{
|
||||
unsigned long start_pfn = start >> PAGE_SHIFT;
|
||||
unsigned long nr_pages = size >> PAGE_SHIFT;
|
||||
struct page *page = pfn_to_page(start_pfn);
|
||||
struct vmem_altmap *altmap;
|
||||
struct zone *zone;
|
||||
int ret;
|
||||
|
||||
zone = page_zone(pfn_to_page(start_pfn));
|
||||
kernel_physical_mapping_remove(start, start + size);
|
||||
/* With altmap the first mapped page is offset from @start */
|
||||
altmap = to_vmem_altmap((unsigned long) page);
|
||||
if (altmap)
|
||||
page += vmem_altmap_offset(altmap);
|
||||
zone = page_zone(page);
|
||||
ret = __remove_pages(zone, start_pfn, nr_pages);
|
||||
WARN_ON_ONCE(ret);
|
||||
kernel_physical_mapping_remove(start, start + size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -1235,7 +1248,7 @@ static void __meminitdata *p_start, *p_end;
|
|||
static int __meminitdata node_start;
|
||||
|
||||
static int __meminit vmemmap_populate_hugepages(unsigned long start,
|
||||
unsigned long end, int node)
|
||||
unsigned long end, int node, struct vmem_altmap *altmap)
|
||||
{
|
||||
unsigned long addr;
|
||||
unsigned long next;
|
||||
|
@ -1258,7 +1271,7 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
|
|||
if (pmd_none(*pmd)) {
|
||||
void *p;
|
||||
|
||||
p = vmemmap_alloc_block_buf(PMD_SIZE, node);
|
||||
p = __vmemmap_alloc_block_buf(PMD_SIZE, node, altmap);
|
||||
if (p) {
|
||||
pte_t entry;
|
||||
|
||||
|
@ -1279,7 +1292,8 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
|
|||
addr_end = addr + PMD_SIZE;
|
||||
p_end = p + PMD_SIZE;
|
||||
continue;
|
||||
}
|
||||
} else if (altmap)
|
||||
return -ENOMEM; /* no fallback */
|
||||
} else if (pmd_large(*pmd)) {
|
||||
vmemmap_verify((pte_t *)pmd, node, addr, next);
|
||||
continue;
|
||||
|
@ -1293,11 +1307,16 @@ static int __meminit vmemmap_populate_hugepages(unsigned long start,
|
|||
|
||||
int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node)
|
||||
{
|
||||
struct vmem_altmap *altmap = to_vmem_altmap(start);
|
||||
int err;
|
||||
|
||||
if (cpu_has_pse)
|
||||
err = vmemmap_populate_hugepages(start, end, node);
|
||||
else
|
||||
err = vmemmap_populate_hugepages(start, end, node, altmap);
|
||||
else if (altmap) {
|
||||
pr_err_once("%s: no cpu support for altmap allocations\n",
|
||||
__func__);
|
||||
err = -ENOMEM;
|
||||
} else
|
||||
err = vmemmap_populate_basepages(start, end, node);
|
||||
if (!err)
|
||||
sync_global_pgds(start, end - 1, 0);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include <linux/debugfs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/fs.h>
|
||||
|
@ -949,7 +950,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
|
|||
}
|
||||
|
||||
int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
|
||||
unsigned long pfn)
|
||||
pfn_t pfn)
|
||||
{
|
||||
enum page_cache_mode pcm;
|
||||
|
||||
|
@ -957,7 +958,7 @@ int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
|
|||
return 0;
|
||||
|
||||
/* Set prot based on lookup */
|
||||
pcm = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT);
|
||||
pcm = lookup_memtype(pfn_t_to_phys(pfn));
|
||||
*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
|
||||
cachemode2protval(pcm));
|
||||
|
||||
|
|
|
@ -505,19 +505,6 @@ int pmdp_clear_flush_young(struct vm_area_struct *vma,
|
|||
|
||||
return young;
|
||||
}
|
||||
|
||||
void pmdp_splitting_flush(struct vm_area_struct *vma,
|
||||
unsigned long address, pmd_t *pmdp)
|
||||
{
|
||||
int set;
|
||||
VM_BUG_ON(address & ~HPAGE_PMD_MASK);
|
||||
set = !test_and_set_bit(_PAGE_BIT_SPLITTING,
|
||||
(unsigned long *)pmdp);
|
||||
if (set) {
|
||||
/* need tlb flush only to serialize against gup-fast */
|
||||
flush_tlb_range(vma, address, address + HPAGE_PMD_SIZE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
|
|
|
@ -86,8 +86,10 @@
|
|||
#define MADV_SEQUENTIAL 2 /* expect sequential page references */
|
||||
#define MADV_WILLNEED 3 /* will need these pages */
|
||||
#define MADV_DONTNEED 4 /* don't need these pages */
|
||||
#define MADV_FREE 5 /* free pages only if memory pressure */
|
||||
|
||||
/* common parameters: try to keep these consistent across architectures */
|
||||
#define MADV_FREE 8 /* free pages only if memory pressure */
|
||||
#define MADV_REMOVE 9 /* remove these pages & resources */
|
||||
#define MADV_DONTFORK 10 /* don't inherit across fork */
|
||||
#define MADV_DOFORK 11 /* do inherit across fork */
|
||||
|
|
|
@ -245,7 +245,7 @@ static int check_tlb_entry(unsigned w, unsigned e, bool dtlb)
|
|||
page_mapcount(p));
|
||||
if (!page_count(p))
|
||||
rc |= TLB_INSANE;
|
||||
else if (page_mapped(p))
|
||||
else if (page_mapcount(p))
|
||||
rc |= TLB_SUSPICIOUS;
|
||||
} else {
|
||||
rc |= TLB_INSANE;
|
||||
|
|
|
@ -647,6 +647,13 @@ static int add_memory_block(int base_section_nr)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool is_zone_device_section(struct mem_section *ms)
|
||||
{
|
||||
struct page *page;
|
||||
|
||||
page = sparse_decode_mem_map(ms->section_mem_map, __section_nr(ms));
|
||||
return is_zone_device_page(page);
|
||||
}
|
||||
|
||||
/*
|
||||
* need an interface for the VM to add new memory regions,
|
||||
|
@ -657,6 +664,9 @@ int register_new_memory(int nid, struct mem_section *section)
|
|||
int ret = 0;
|
||||
struct memory_block *mem;
|
||||
|
||||
if (is_zone_device_section(section))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mem_sysfs_mutex);
|
||||
|
||||
mem = find_memory_block(section);
|
||||
|
@ -693,6 +703,9 @@ static int remove_memory_section(unsigned long node_id,
|
|||
{
|
||||
struct memory_block *mem;
|
||||
|
||||
if (is_zone_device_section(section))
|
||||
return 0;
|
||||
|
||||
mutex_lock(&mem_sysfs_mutex);
|
||||
mem = find_memory_block(section);
|
||||
unregister_mem_sect_under_nodes(mem, __section_nr(section));
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
#include <linux/radix-tree.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/slab.h>
|
||||
#ifdef CONFIG_BLK_DEV_RAM_DAX
|
||||
#include <linux/pfn_t.h>
|
||||
#endif
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
@ -378,7 +381,7 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
|
|||
|
||||
#ifdef CONFIG_BLK_DEV_RAM_DAX
|
||||
static long brd_direct_access(struct block_device *bdev, sector_t sector,
|
||||
void __pmem **kaddr, unsigned long *pfn)
|
||||
void __pmem **kaddr, pfn_t *pfn)
|
||||
{
|
||||
struct brd_device *brd = bdev->bd_disk->private_data;
|
||||
struct page *page;
|
||||
|
@ -389,7 +392,7 @@ static long brd_direct_access(struct block_device *bdev, sector_t sector,
|
|||
if (!page)
|
||||
return -ENOSPC;
|
||||
*kaddr = (void __pmem *)page_address(page);
|
||||
*pfn = page_to_pfn(page);
|
||||
*pfn = page_to_pfn_t(page);
|
||||
|
||||
return PAGE_SIZE;
|
||||
}
|
||||
|
|
|
@ -1325,7 +1325,6 @@ static int zram_remove(struct zram *zram)
|
|||
|
||||
pr_info("Removed device: %s\n", zram->disk->disk_name);
|
||||
|
||||
idr_remove(&zram_index_idr, zram->disk->first_minor);
|
||||
blk_cleanup_queue(zram->disk->queue);
|
||||
del_gendisk(zram->disk);
|
||||
put_disk(zram->disk);
|
||||
|
@ -1367,10 +1366,12 @@ static ssize_t hot_remove_store(struct class *class,
|
|||
mutex_lock(&zram_index_mutex);
|
||||
|
||||
zram = idr_find(&zram_index_idr, dev_id);
|
||||
if (zram)
|
||||
if (zram) {
|
||||
ret = zram_remove(zram);
|
||||
else
|
||||
idr_remove(&zram_index_idr, dev_id);
|
||||
} else {
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
mutex_unlock(&zram_index_mutex);
|
||||
return ret ? ret : count;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <drm/exynos_drm.h>
|
||||
|
||||
#include "exynos_drm_drv.h"
|
||||
|
@ -490,7 +491,8 @@ int exynos_drm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
}
|
||||
|
||||
pfn = page_to_pfn(exynos_gem->pages[page_offset]);
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
|
||||
out:
|
||||
switch (ret) {
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/tty.h>
|
||||
#include <linux/slab.h>
|
||||
|
@ -132,7 +133,8 @@ static int psbfb_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
for (i = 0; i < page_num; i++) {
|
||||
pfn = (phys_addr >> PAGE_SHIFT);
|
||||
|
||||
ret = vm_insert_mixed(vma, address, pfn);
|
||||
ret = vm_insert_mixed(vma, address,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
if (unlikely((ret == -EBUSY) || (ret != 0 && i > 0)))
|
||||
break;
|
||||
else if (unlikely(ret != 0)) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/spinlock.h>
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/dma-buf.h>
|
||||
#include <linux/pfn_t.h>
|
||||
|
||||
#include "msm_drv.h"
|
||||
#include "msm_gem.h"
|
||||
|
@ -222,7 +223,8 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
|
||||
pfn, pfn << PAGE_SHIFT);
|
||||
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||
ret = vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
|
||||
out_unlock:
|
||||
mutex_unlock(&dev->struct_mutex);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include <linux/shmem_fs.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/pfn_t.h>
|
||||
|
||||
#include <drm/drm_vma_manager.h>
|
||||
|
||||
|
@ -385,7 +386,8 @@ static int fault_1d(struct drm_gem_object *obj,
|
|||
VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
|
||||
pfn, pfn << PAGE_SHIFT);
|
||||
|
||||
return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address, pfn);
|
||||
return vm_insert_mixed(vma, (unsigned long)vmf->virtual_address,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
}
|
||||
|
||||
/* Special handling for the case of faulting in 2d tiled buffers */
|
||||
|
@ -478,7 +480,8 @@ static int fault_2d(struct drm_gem_object *obj,
|
|||
pfn, pfn << PAGE_SHIFT);
|
||||
|
||||
for (i = n; i > 0; i--) {
|
||||
vm_insert_mixed(vma, (unsigned long)vaddr, pfn);
|
||||
vm_insert_mixed(vma, (unsigned long)vaddr,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
pfn += usergart[fmt].stride_pfn;
|
||||
vaddr += PAGE_SIZE * m;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include <ttm/ttm_placement.h>
|
||||
#include <drm/drm_vma_manager.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <linux/rbtree.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
@ -229,7 +230,8 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
|
|||
}
|
||||
|
||||
if (vma->vm_flags & VM_MIXEDMAP)
|
||||
ret = vm_insert_mixed(&cvma, address, pfn);
|
||||
ret = vm_insert_mixed(&cvma, address,
|
||||
__pfn_to_pfn_t(pfn, PFN_DEV));
|
||||
else
|
||||
ret = vm_insert_pfn(&cvma, address, pfn);
|
||||
|
||||
|
|
|
@ -433,16 +433,15 @@ ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
|
|||
scale_db = true;
|
||||
case IIO_VAL_INT_PLUS_MICRO:
|
||||
if (vals[1] < 0)
|
||||
return sprintf(buf, "-%ld.%06u%s\n", abs(vals[0]),
|
||||
-vals[1],
|
||||
scale_db ? " dB" : "");
|
||||
return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]),
|
||||
-vals[1], scale_db ? " dB" : "");
|
||||
else
|
||||
return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
|
||||
scale_db ? " dB" : "");
|
||||
case IIO_VAL_INT_PLUS_NANO:
|
||||
if (vals[1] < 0)
|
||||
return sprintf(buf, "-%ld.%09u\n", abs(vals[0]),
|
||||
-vals[1]);
|
||||
return sprintf(buf, "-%d.%09u\n", abs(vals[0]),
|
||||
-vals[1]);
|
||||
else
|
||||
return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
||||
case IIO_VAL_FRACTIONAL:
|
||||
|
|
|
@ -901,7 +901,7 @@ static void iwlagn_gain_computation(struct iwl_priv *priv,
|
|||
/* bound gain by 2 bits value max, 3rd bit is sign */
|
||||
data->delta_gain_code[i] =
|
||||
min(abs(delta_g),
|
||||
(long) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
|
||||
(s32) CHAIN_NOISE_MAX_DELTA_GAIN_CODE);
|
||||
|
||||
if (delta_g < 0)
|
||||
/*
|
||||
|
|
|
@ -83,8 +83,7 @@ static ssize_t mode_store(struct device *dev,
|
|||
|
||||
if (strncmp(buf, "pmem\n", n) == 0
|
||||
|| strncmp(buf, "pmem", n) == 0) {
|
||||
/* TODO: allocate from PMEM support */
|
||||
rc = -ENOTTY;
|
||||
nd_pfn->mode = PFN_MODE_PMEM;
|
||||
} else if (strncmp(buf, "ram\n", n) == 0
|
||||
|| strncmp(buf, "ram", n) == 0)
|
||||
nd_pfn->mode = PFN_MODE_RAM;
|
||||
|
|
|
@ -21,10 +21,11 @@
|
|||
#include <linux/init.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/memory_hotplug.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <linux/badblocks.h>
|
||||
#include <linux/memremap.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pmem.h>
|
||||
#include <linux/nd.h>
|
||||
|
@ -40,6 +41,7 @@ struct pmem_device {
|
|||
phys_addr_t phys_addr;
|
||||
/* when non-zero this device is hosting a 'pfn' instance */
|
||||
phys_addr_t data_offset;
|
||||
unsigned long pfn_flags;
|
||||
void __pmem *virt_addr;
|
||||
size_t size;
|
||||
struct badblocks bb;
|
||||
|
@ -135,13 +137,13 @@ static int pmem_rw_page(struct block_device *bdev, sector_t sector,
|
|||
}
|
||||
|
||||
static long pmem_direct_access(struct block_device *bdev, sector_t sector,
|
||||
void __pmem **kaddr, unsigned long *pfn)
|
||||
void __pmem **kaddr, pfn_t *pfn)
|
||||
{
|
||||
struct pmem_device *pmem = bdev->bd_disk->private_data;
|
||||
resource_size_t offset = sector * 512 + pmem->data_offset;
|
||||
|
||||
*kaddr = pmem->virt_addr + offset;
|
||||
*pfn = (pmem->phys_addr + offset) >> PAGE_SHIFT;
|
||||
*pfn = phys_to_pfn_t(pmem->phys_addr + offset, pmem->pfn_flags);
|
||||
|
||||
return pmem->size - offset;
|
||||
}
|
||||
|
@ -157,6 +159,7 @@ static struct pmem_device *pmem_alloc(struct device *dev,
|
|||
struct resource *res, int id)
|
||||
{
|
||||
struct pmem_device *pmem;
|
||||
struct request_queue *q;
|
||||
|
||||
pmem = devm_kzalloc(dev, sizeof(*pmem), GFP_KERNEL);
|
||||
if (!pmem)
|
||||
|
@ -174,16 +177,26 @@ static struct pmem_device *pmem_alloc(struct device *dev,
|
|||
return ERR_PTR(-EBUSY);
|
||||
}
|
||||
|
||||
if (pmem_should_map_pages(dev))
|
||||
pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res);
|
||||
else
|
||||
q = blk_alloc_queue_node(GFP_KERNEL, dev_to_node(dev));
|
||||
if (!q)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
pmem->pfn_flags = PFN_DEV;
|
||||
if (pmem_should_map_pages(dev)) {
|
||||
pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, res,
|
||||
&q->q_usage_counter, NULL);
|
||||
pmem->pfn_flags |= PFN_MAP;
|
||||
} else
|
||||
pmem->virt_addr = (void __pmem *) devm_memremap(dev,
|
||||
pmem->phys_addr, pmem->size,
|
||||
ARCH_MEMREMAP_PMEM);
|
||||
|
||||
if (IS_ERR(pmem->virt_addr))
|
||||
if (IS_ERR(pmem->virt_addr)) {
|
||||
blk_cleanup_queue(q);
|
||||
return (void __force *) pmem->virt_addr;
|
||||
}
|
||||
|
||||
pmem->pmem_queue = q;
|
||||
return pmem;
|
||||
}
|
||||
|
||||
|
@ -203,10 +216,6 @@ static int pmem_attach_disk(struct device *dev,
|
|||
int nid = dev_to_node(dev);
|
||||
struct gendisk *disk;
|
||||
|
||||
pmem->pmem_queue = blk_alloc_queue_node(GFP_KERNEL, nid);
|
||||
if (!pmem->pmem_queue)
|
||||
return -ENOMEM;
|
||||
|
||||
blk_queue_make_request(pmem->pmem_queue, pmem_make_request);
|
||||
blk_queue_physical_block_size(pmem->pmem_queue, PAGE_SIZE);
|
||||
blk_queue_max_hw_sectors(pmem->pmem_queue, UINT_MAX);
|
||||
|
@ -352,12 +361,17 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
|
|||
struct nd_namespace_io *nsio = to_nd_namespace_io(&ndns->dev);
|
||||
struct nd_pfn *nd_pfn = to_nd_pfn(ndns->claim);
|
||||
struct device *dev = &nd_pfn->dev;
|
||||
struct vmem_altmap *altmap;
|
||||
struct nd_region *nd_region;
|
||||
struct vmem_altmap *altmap;
|
||||
struct nd_pfn_sb *pfn_sb;
|
||||
struct pmem_device *pmem;
|
||||
struct request_queue *q;
|
||||
phys_addr_t offset;
|
||||
int rc;
|
||||
struct vmem_altmap __altmap = {
|
||||
.base_pfn = __phys_to_pfn(nsio->res.start),
|
||||
.reserve = __phys_to_pfn(SZ_8K),
|
||||
};
|
||||
|
||||
if (!nd_pfn->uuid || !nd_pfn->ndns)
|
||||
return -ENODEV;
|
||||
|
@ -375,6 +389,17 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
|
|||
return -EINVAL;
|
||||
nd_pfn->npfns = le64_to_cpu(pfn_sb->npfns);
|
||||
altmap = NULL;
|
||||
} else if (nd_pfn->mode == PFN_MODE_PMEM) {
|
||||
nd_pfn->npfns = (resource_size(&nsio->res) - offset)
|
||||
/ PAGE_SIZE;
|
||||
if (le64_to_cpu(nd_pfn->pfn_sb->npfns) > nd_pfn->npfns)
|
||||
dev_info(&nd_pfn->dev,
|
||||
"number of pfns truncated from %lld to %ld\n",
|
||||
le64_to_cpu(nd_pfn->pfn_sb->npfns),
|
||||
nd_pfn->npfns);
|
||||
altmap = & __altmap;
|
||||
altmap->free = __phys_to_pfn(offset - SZ_8K);
|
||||
altmap->alloc = 0;
|
||||
} else {
|
||||
rc = -ENXIO;
|
||||
goto err;
|
||||
|
@ -382,8 +407,11 @@ static int nvdimm_namespace_attach_pfn(struct nd_namespace_common *ndns)
|
|||
|
||||
/* establish pfn range for lookup, and switch to direct map */
|
||||
pmem = dev_get_drvdata(dev);
|
||||
q = pmem->pmem_queue;
|
||||
devm_memunmap(dev, (void __force *) pmem->virt_addr);
|
||||
pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res);
|
||||
pmem->virt_addr = (void __pmem *) devm_memremap_pages(dev, &nsio->res,
|
||||
&q->q_usage_counter, altmap);
|
||||
pmem->pfn_flags |= PFN_MAP;
|
||||
if (IS_ERR(pmem->virt_addr)) {
|
||||
rc = PTR_ERR(pmem->virt_addr);
|
||||
goto err;
|
||||
|
@ -424,19 +452,22 @@ static int nd_pmem_probe(struct device *dev)
|
|||
return -ENOMEM;
|
||||
nvdimm_namespace_add_poison(ndns, &pmem->bb, 0);
|
||||
|
||||
if (is_nd_btt(dev))
|
||||
if (is_nd_btt(dev)) {
|
||||
/* btt allocates its own request_queue */
|
||||
blk_cleanup_queue(pmem->pmem_queue);
|
||||
pmem->pmem_queue = NULL;
|
||||
return nvdimm_namespace_attach_btt(ndns);
|
||||
}
|
||||
|
||||
if (is_nd_pfn(dev))
|
||||
return nvdimm_namespace_attach_pfn(ndns);
|
||||
|
||||
if (nd_btt_probe(ndns, pmem) == 0) {
|
||||
/* we'll come back as btt-pmem */
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
if (nd_pfn_probe(ndns, pmem) == 0) {
|
||||
/* we'll come back as pfn-pmem */
|
||||
if (nd_btt_probe(ndns, pmem) == 0 || nd_pfn_probe(ndns, pmem) == 0) {
|
||||
/*
|
||||
* We'll come back as either btt-pmem, or pfn-pmem, so
|
||||
* drop the queue allocation for now.
|
||||
*/
|
||||
blk_cleanup_queue(pmem->pmem_queue);
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/completion.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/pfn_t.h>
|
||||
#include <asm/extmem.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
|
@ -30,7 +31,7 @@ static void dcssblk_release(struct gendisk *disk, fmode_t mode);
|
|||
static blk_qc_t dcssblk_make_request(struct request_queue *q,
|
||||
struct bio *bio);
|
||||
static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
|
||||
void __pmem **kaddr, unsigned long *pfn);
|
||||
void __pmem **kaddr, pfn_t *pfn);
|
||||
|
||||
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
|
||||
|
||||
|
@ -883,20 +884,18 @@ fail:
|
|||
|
||||
static long
|
||||
dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
|
||||
void __pmem **kaddr, unsigned long *pfn)
|
||||
void __pmem **kaddr, pfn_t *pfn)
|
||||
{
|
||||
struct dcssblk_dev_info *dev_info;
|
||||
unsigned long offset, dev_sz;
|
||||
void *addr;
|
||||
|
||||
dev_info = bdev->bd_disk->private_data;
|
||||
if (!dev_info)
|
||||
return -ENODEV;
|
||||
dev_sz = dev_info->end - dev_info->start;
|
||||
offset = secnum * 512;
|
||||
addr = (void *) (dev_info->start + offset);
|
||||
*pfn = virt_to_phys(addr) >> PAGE_SHIFT;
|
||||
*kaddr = (void __pmem *) addr;
|
||||
*kaddr = (void __pmem *) (dev_info->start + offset);
|
||||
*pfn = __pfn_to_pfn_t(PFN_DOWN(dev_info->start + offset), PFN_DEV);
|
||||
|
||||
return dev_sz - offset;
|
||||
}
|
||||
|
|
|
@ -50,7 +50,8 @@ config FS_DAX_PMD
|
|||
bool
|
||||
default FS_DAX
|
||||
depends on FS_DAX
|
||||
depends on BROKEN
|
||||
depends on ZONE_DEVICE
|
||||
depends on TRANSPARENT_HUGEPAGE
|
||||
|
||||
endif # BLOCK
|
||||
|
||||
|
|
|
@ -455,10 +455,7 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
|
|||
/**
|
||||
* bdev_direct_access() - Get the address for directly-accessibly memory
|
||||
* @bdev: The device containing the memory
|
||||
* @sector: The offset within the device
|
||||
* @addr: Where to put the address of the memory
|
||||
* @pfn: The Page Frame Number for the memory
|
||||
* @size: The number of bytes requested
|
||||
* @dax: control and output parameters for ->direct_access
|
||||
*
|
||||
* If a block device is made up of directly addressable memory, this function
|
||||
* will tell the caller the PFN and the address of the memory. The address
|
||||
|
@ -469,10 +466,10 @@ EXPORT_SYMBOL_GPL(bdev_write_page);
|
|||
* Return: negative errno if an error occurs, otherwise the number of bytes
|
||||
* accessible at this address.
|
||||
*/
|
||||
long bdev_direct_access(struct block_device *bdev, sector_t sector,
|
||||
void __pmem **addr, unsigned long *pfn, long size)
|
||||
long bdev_direct_access(struct block_device *bdev, struct blk_dax_ctl *dax)
|
||||
{
|
||||
long avail;
|
||||
sector_t sector = dax->sector;
|
||||
long avail, size = dax->size;
|
||||
const struct block_device_operations *ops = bdev->bd_disk->fops;
|
||||
|
||||
/*
|
||||
|
@ -491,9 +488,11 @@ long bdev_direct_access(struct block_device *bdev, sector_t sector,
|
|||
sector += get_start_sect(bdev);
|
||||
if (sector % (PAGE_SIZE / 512))
|
||||
return -EINVAL;
|
||||
avail = ops->direct_access(bdev, sector, addr, pfn);
|
||||
avail = ops->direct_access(bdev, sector, &dax->addr, &dax->pfn);
|
||||
if (!avail)
|
||||
return -ERANGE;
|
||||
if (avail > 0 && avail & ~PAGE_MASK)
|
||||
return -ENXIO;
|
||||
return min(avail, size);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bdev_direct_access);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue