diff options
Diffstat (limited to 'mm/gup.c')
-rw-r--r-- | mm/gup.c | 48 |
1 files changed, 36 insertions, 12 deletions
@@ -160,8 +160,12 @@ retry: | |||
160 | goto retry; | 160 | goto retry; |
161 | } | 161 | } |
162 | 162 | ||
163 | if (flags & FOLL_GET) | 163 | if (flags & FOLL_GET) { |
164 | get_page(page); | 164 | if (unlikely(!try_get_page(page))) { |
165 | page = ERR_PTR(-ENOMEM); | ||
166 | goto out; | ||
167 | } | ||
168 | } | ||
165 | if (flags & FOLL_TOUCH) { | 169 | if (flags & FOLL_TOUCH) { |
166 | if ((flags & FOLL_WRITE) && | 170 | if ((flags & FOLL_WRITE) && |
167 | !pte_dirty(pte) && !PageDirty(page)) | 171 | !pte_dirty(pte) && !PageDirty(page)) |
@@ -298,7 +302,10 @@ retry_locked: | |||
298 | if (pmd_trans_unstable(pmd)) | 302 | if (pmd_trans_unstable(pmd)) |
299 | ret = -EBUSY; | 303 | ret = -EBUSY; |
300 | } else { | 304 | } else { |
301 | get_page(page); | 305 | if (unlikely(!try_get_page(page))) { |
306 | spin_unlock(ptl); | ||
307 | return ERR_PTR(-ENOMEM); | ||
308 | } | ||
302 | spin_unlock(ptl); | 309 | spin_unlock(ptl); |
303 | lock_page(page); | 310 | lock_page(page); |
304 | ret = split_huge_page(page); | 311 | ret = split_huge_page(page); |
@@ -500,7 +507,10 @@ static int get_gate_page(struct mm_struct *mm, unsigned long address, | |||
500 | if (is_device_public_page(*page)) | 507 | if (is_device_public_page(*page)) |
501 | goto unmap; | 508 | goto unmap; |
502 | } | 509 | } |
503 | get_page(*page); | 510 | if (unlikely(!try_get_page(*page))) { |
511 | ret = -ENOMEM; | ||
512 | goto unmap; | ||
513 | } | ||
504 | out: | 514 | out: |
505 | ret = 0; | 515 | ret = 0; |
506 | unmap: | 516 | unmap: |
@@ -1545,6 +1555,20 @@ static void undo_dev_pagemap(int *nr, int nr_start, struct page **pages) | |||
1545 | } | 1555 | } |
1546 | } | 1556 | } |
1547 | 1557 | ||
1558 | /* | ||
1559 | * Return the compund head page with ref appropriately incremented, | ||
1560 | * or NULL if that failed. | ||
1561 | */ | ||
1562 | static inline struct page *try_get_compound_head(struct page *page, int refs) | ||
1563 | { | ||
1564 | struct page *head = compound_head(page); | ||
1565 | if (WARN_ON_ONCE(page_ref_count(head) < 0)) | ||
1566 | return NULL; | ||
1567 | if (unlikely(!page_cache_add_speculative(head, refs))) | ||
1568 | return NULL; | ||
1569 | return head; | ||
1570 | } | ||
1571 | |||
1548 | #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL | 1572 | #ifdef CONFIG_ARCH_HAS_PTE_SPECIAL |
1549 | static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, | 1573 | static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, |
1550 | int write, struct page **pages, int *nr) | 1574 | int write, struct page **pages, int *nr) |
@@ -1579,9 +1603,9 @@ static int gup_pte_range(pmd_t pmd, unsigned long addr, unsigned long end, | |||
1579 | 1603 | ||
1580 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); | 1604 | VM_BUG_ON(!pfn_valid(pte_pfn(pte))); |
1581 | page = pte_page(pte); | 1605 | page = pte_page(pte); |
1582 | head = compound_head(page); | ||
1583 | 1606 | ||
1584 | if (!page_cache_get_speculative(head)) | 1607 | head = try_get_compound_head(page, 1); |
1608 | if (!head) | ||
1585 | goto pte_unmap; | 1609 | goto pte_unmap; |
1586 | 1610 | ||
1587 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { | 1611 | if (unlikely(pte_val(pte) != pte_val(*ptep))) { |
@@ -1720,8 +1744,8 @@ static int gup_huge_pmd(pmd_t orig, pmd_t *pmdp, unsigned long addr, | |||
1720 | refs++; | 1744 | refs++; |
1721 | } while (addr += PAGE_SIZE, addr != end); | 1745 | } while (addr += PAGE_SIZE, addr != end); |
1722 | 1746 | ||
1723 | head = compound_head(pmd_page(orig)); | 1747 | head = try_get_compound_head(pmd_page(orig), refs); |
1724 | if (!page_cache_add_speculative(head, refs)) { | 1748 | if (!head) { |
1725 | *nr -= refs; | 1749 | *nr -= refs; |
1726 | return 0; | 1750 | return 0; |
1727 | } | 1751 | } |
@@ -1758,8 +1782,8 @@ static int gup_huge_pud(pud_t orig, pud_t *pudp, unsigned long addr, | |||
1758 | refs++; | 1782 | refs++; |
1759 | } while (addr += PAGE_SIZE, addr != end); | 1783 | } while (addr += PAGE_SIZE, addr != end); |
1760 | 1784 | ||
1761 | head = compound_head(pud_page(orig)); | 1785 | head = try_get_compound_head(pud_page(orig), refs); |
1762 | if (!page_cache_add_speculative(head, refs)) { | 1786 | if (!head) { |
1763 | *nr -= refs; | 1787 | *nr -= refs; |
1764 | return 0; | 1788 | return 0; |
1765 | } | 1789 | } |
@@ -1795,8 +1819,8 @@ static int gup_huge_pgd(pgd_t orig, pgd_t *pgdp, unsigned long addr, | |||
1795 | refs++; | 1819 | refs++; |
1796 | } while (addr += PAGE_SIZE, addr != end); | 1820 | } while (addr += PAGE_SIZE, addr != end); |
1797 | 1821 | ||
1798 | head = compound_head(pgd_page(orig)); | 1822 | head = try_get_compound_head(pgd_page(orig), refs); |
1799 | if (!page_cache_add_speculative(head, refs)) { | 1823 | if (!head) { |
1800 | *nr -= refs; | 1824 | *nr -= refs; |
1801 | return 0; | 1825 | return 0; |
1802 | } | 1826 | } |