Skip to content

Commit 652ea69

Browse files
Nick Piggintorvalds
authored andcommitted
x86: support 1GB hugepages with get_user_pages_lockless()
Signed-off-by: Nick Piggin <[email protected]> Cc: Ingo Molnar <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Andi Kleen <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent bc40d73 commit 652ea69

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

arch/x86/mm/gup.c

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ static noinline int gup_huge_pmd(pmd_t pmd, unsigned long addr,
124124

125125
refs = 0;
126126
head = pte_page(pte);
127-
page = head + ((addr & ~HPAGE_MASK) >> PAGE_SHIFT);
127+
page = head + ((addr & ~PMD_MASK) >> PAGE_SHIFT);
128128
do {
129129
VM_BUG_ON(compound_head(page) != head);
130130
pages[*nr] = page;
@@ -162,6 +162,38 @@ static int gup_pmd_range(pud_t pud, unsigned long addr, unsigned long end,
162162
return 1;
163163
}
164164

165+
static noinline int gup_huge_pud(pud_t pud, unsigned long addr,
166+
unsigned long end, int write, struct page **pages, int *nr)
167+
{
168+
unsigned long mask;
169+
pte_t pte = *(pte_t *)&pud;
170+
struct page *head, *page;
171+
int refs;
172+
173+
mask = _PAGE_PRESENT|_PAGE_USER;
174+
if (write)
175+
mask |= _PAGE_RW;
176+
if ((pte_val(pte) & mask) != mask)
177+
return 0;
178+
/* hugepages are never "special" */
179+
VM_BUG_ON(pte_val(pte) & _PAGE_SPECIAL);
180+
VM_BUG_ON(!pfn_valid(pte_pfn(pte)));
181+
182+
refs = 0;
183+
head = pte_page(pte);
184+
page = head + ((addr & ~PUD_MASK) >> PAGE_SHIFT);
185+
do {
186+
VM_BUG_ON(compound_head(page) != head);
187+
pages[*nr] = page;
188+
(*nr)++;
189+
page++;
190+
refs++;
191+
} while (addr += PAGE_SIZE, addr != end);
192+
get_head_page_multiple(head, refs);
193+
194+
return 1;
195+
}
196+
165197
static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
166198
int write, struct page **pages, int *nr)
167199
{
@@ -175,8 +207,13 @@ static int gup_pud_range(pgd_t pgd, unsigned long addr, unsigned long end,
175207
next = pud_addr_end(addr, end);
176208
if (pud_none(pud))
177209
return 0;
178-
if (!gup_pmd_range(pud, addr, next, write, pages, nr))
179-
return 0;
210+
if (unlikely(pud_large(pud))) {
211+
if (!gup_huge_pud(pud, addr, next, write, pages, nr))
212+
return 0;
213+
} else {
214+
if (!gup_pmd_range(pud, addr, next, write, pages, nr))
215+
return 0;
216+
}
180217
} while (pudp++, addr = next, addr != end);
181218

182219
return 1;

0 commit comments

Comments
 (0)