|
@@ -154,14 +154,12 @@ static inline void get_head_page_multiple(struct page *page, int nr)
|
|
SetPageReferenced(page);
|
|
SetPageReferenced(page);
|
|
}
|
|
}
|
|
|
|
|
|
-static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr,
|
|
|
|
|
|
+static int __gup_device_huge(unsigned long pfn, unsigned long addr,
|
|
unsigned long end, struct page **pages, int *nr)
|
|
unsigned long end, struct page **pages, int *nr)
|
|
{
|
|
{
|
|
int nr_start = *nr;
|
|
int nr_start = *nr;
|
|
- unsigned long pfn = pmd_pfn(pmd);
|
|
|
|
struct dev_pagemap *pgmap = NULL;
|
|
struct dev_pagemap *pgmap = NULL;
|
|
|
|
|
|
- pfn += (addr & ~PMD_MASK) >> PAGE_SHIFT;
|
|
|
|
do {
|
|
do {
|
|
struct page *page = pfn_to_page(pfn);
|
|
struct page *page = pfn_to_page(pfn);
|
|
|
|
|
|
@@ -180,6 +178,24 @@ static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr,
|
|
return 1;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int __gup_device_huge_pmd(pmd_t pmd, unsigned long addr,
|
|
|
|
+ unsigned long end, struct page **pages, int *nr)
|
|
|
|
+{
|
|
|
|
+ unsigned long fault_pfn;
|
|
|
|
+
|
|
|
|
+ fault_pfn = pmd_pfn(pmd) + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
|
|
|
|
+ return __gup_device_huge(fault_pfn, addr, end, pages, nr);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int __gup_device_huge_pud(pud_t pud, unsigned long addr,
|
|
|
|
+ unsigned long end, struct page **pages, int *nr)
|
|
|
|
+{
|
|
|
|
+ unsigned long fault_pfn;
|
|
|
|
+
|
|
|
|
+ fault_pfn = pud_pfn(pud) + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
|
|
|
|
+ return __gup_device_huge(fault_pfn, addr, end, pages, nr);
|
|
|
|
+}
|
|
|
|
+
|
|
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
|
static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
|
|
unsigned long end, int write, struct page **pages, int *nr)
|
|
unsigned long end, int write, struct page **pages, int *nr)
|
|
{
|
|
{
|
|
@@ -251,9 +267,13 @@ static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
|
|
|
|
|
|
if (!pte_allows_gup(pud_val(pud), write))
|
|
if (!pte_allows_gup(pud_val(pud), write))
|
|
return 0;
|
|
return 0;
|
|
|
|
+
|
|
|
|
+ VM_BUG_ON(!pfn_valid(pud_pfn(pud)));
|
|
|
|
+ if (pud_devmap(pud))
|
|
|
|
+ return __gup_device_huge_pud(pud, addr, end, pages, nr);
|
|
|
|
+
|
|
/* hugepages are never "special" */
|
|
/* hugepages are never "special" */
|
|
VM_BUG_ON(pud_flags(pud) & _PAGE_SPECIAL);
|
|
VM_BUG_ON(pud_flags(pud) & _PAGE_SPECIAL);
|
|
- VM_BUG_ON(!pfn_valid(pud_pfn(pud)));
|
|
|
|
|
|
|
|
refs = 0;
|
|
refs = 0;
|
|
head = pud_page(pud);
|
|
head = pud_page(pud);
|