diff options
author | Christoph Hellwig <hch@lst.de> | 2019-07-11 23:57:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-07-12 14:05:45 -0400 |
commit | cbd34da7dc9afd521e0bea5e7d12701f4a9da7c7 (patch) | |
tree | 01134464a578f6e5ec091a739b3671528eaf3d54 /mm | |
parent | 817be129e6f254e5bd8c17b1da834c8f612dca28 (diff) |
mm: move the powerpc hugepd code to mm/gup.c
While only powerpc supports the hugepd case, the code is pretty generic
and I'd like to keep all GUP internals in one place.
Link: http://lkml.kernel.org/r/20190625143715.1689-15-hch@lst.de
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Andrey Konovalov <andreyknvl@google.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: David Miller <davem@davemloft.net>
Cc: James Hogan <jhogan@kernel.org>
Cc: Jason Gunthorpe <jgg@mellanox.com>
Cc: Khalid Aziz <khalid.aziz@oracle.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Paul Burton <paul.burton@mips.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Ralf Baechle <ralf@linux-mips.org>
Cc: Rich Felker <dalias@libc.org>
Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'mm')
-rw-r--r-- | mm/Kconfig | 10 | ||||
-rw-r--r-- | mm/gup.c | 82 |
2 files changed, 92 insertions, 0 deletions
diff --git a/mm/Kconfig b/mm/Kconfig index 48840b28482b..0b4352557dd5 100644 --- a/mm/Kconfig +++ b/mm/Kconfig | |||
@@ -769,4 +769,14 @@ config GUP_GET_PTE_LOW_HIGH | |||
769 | config ARCH_HAS_PTE_SPECIAL | 769 | config ARCH_HAS_PTE_SPECIAL |
770 | bool | 770 | bool |
771 | 771 | ||
772 | # | ||
773 | # Some architectures require a special hugepage directory format that is | ||
774 | # required to support multiple hugepage sizes. For example a4fe3ce76 | ||
775 | # "powerpc/mm: Allow more flexible layouts for hugepage pagetables" | ||
776 | # introduced it on powerpc. This allows for a more flexible hugepage | ||
777 | # pagetable layouts. | ||
778 | # | ||
779 | config ARCH_HAS_HUGEPD | ||
780 | bool | ||
781 | |||
772 | endmenu | 782 | endmenu |
@@ -1966,6 +1966,88 @@ static int __gup_device_huge_pud(pud_t pud, pud_t *pudp, unsigned long addr, | |||
1966 | } | 1966 | } |
1967 | #endif | 1967 | #endif |
1968 | 1968 | ||
1969 | #ifdef CONFIG_ARCH_HAS_HUGEPD | ||
1970 | static unsigned long hugepte_addr_end(unsigned long addr, unsigned long end, | ||
1971 | unsigned long sz) | ||
1972 | { | ||
1973 | unsigned long __boundary = (addr + sz) & ~(sz-1); | ||
1974 | return (__boundary - 1 < end - 1) ? __boundary : end; | ||
1975 | } | ||
1976 | |||
1977 | static int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr, | ||
1978 | unsigned long end, int write, struct page **pages, int *nr) | ||
1979 | { | ||
1980 | unsigned long pte_end; | ||
1981 | struct page *head, *page; | ||
1982 | pte_t pte; | ||
1983 | int refs; | ||
1984 | |||
1985 | pte_end = (addr + sz) & ~(sz-1); | ||
1986 | if (pte_end < end) | ||
1987 | end = pte_end; | ||
1988 | |||
1989 | pte = READ_ONCE(*ptep); | ||
1990 | |||
1991 | if (!pte_access_permitted(pte, write)) | ||
1992 | return 0; | ||
1993 | |||
1994 | /* hugepages are never "special" */ | ||
1995 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | ||
1996 | |||
1997 | refs = 0; | ||
1998 | head = pte_page(pte); | ||
1999 | |||
2000 | page = head + ((addr & (sz-1)) >> PAGE_SHIFT); | ||
2001 | do { | ||
2002 | VM_BUG_ON(compound_head(page) != head); | ||
2003 | pages[*nr] = page; | ||
2004 | (*nr)++; | ||
2005 | page++; | ||
2006 | refs++; | ||
2007 | } while (addr += PAGE_SIZE, addr != end); | ||
2008 | |||
2009 | if (!page_cache_add_speculative(head, refs)) { | ||
2010 | *nr -= refs; | ||
2011 | return 0; | ||
2012 | } | ||
2013 | |||
2014 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | ||
2015 | /* Could be optimized better */ | ||
2016 | *nr -= refs; | ||
2017 | while (refs--) | ||
2018 | put_page(head); | ||
2019 | return 0; | ||
2020 | } | ||
2021 | |||
2022 | return 1; | ||
2023 | } | ||
2024 | |||
2025 | static int gup_huge_pd(hugepd_t hugepd, unsigned long addr, | ||
2026 | unsigned int pdshift, unsigned long end, int write, | ||
2027 | struct page **pages, int *nr) | ||
2028 | { | ||
2029 | pte_t *ptep; | ||
2030 | unsigned long sz = 1UL << hugepd_shift(hugepd); | ||
2031 | unsigned long next; | ||
2032 | |||
2033 | ptep = hugepte_offset(hugepd, addr, pdshift); | ||
2034 | do { | ||
2035 | next = hugepte_addr_end(addr, end, sz); | ||
2036 | if (!gup_hugepte(ptep, sz, addr, end, write, pages, nr)) | ||
2037 | return 0; | ||
2038 | } while (ptep++, addr = next, addr != end); | ||
2039 | |||
2040 | return 1; | ||
2041 | } | ||
2042 | #else | ||
2043 | static inline int gup_huge_pd(hugepd_t hugepd, unsigned long addr, | ||
2044 | unsigned pdshift, unsigned long end, int write, | ||
2045 | struct page **pages, int *nr) | ||
2046 | { | ||
2047 | return 0; | ||
2048 | } | ||
2049 | #endif /* CONFIG_ARCH_HAS_HUGEPD */ | ||
2050 | |||
1969 | static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, | 2051 | static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, |
1970 | unsigned long end, unsigned int flags, struct page **pages, int *nr) | 2052 | unsigned long end, unsigned int flags, struct page **pages, int *nr) |
1971 | { | 2053 | { |