aboutsummaryrefslogtreecommitdiffstats
path: root/mm/hugetlb.c
diff options
context:
space:
mode:
Diffstat (limited to 'mm/hugetlb.c')
-rw-r--r--mm/hugetlb.c72
1 files changed, 50 insertions, 22 deletions
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 67a71191136e..421aee99b84a 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -7,6 +7,7 @@
7#include <linux/init.h> 7#include <linux/init.h>
8#include <linux/module.h> 8#include <linux/module.h>
9#include <linux/mm.h> 9#include <linux/mm.h>
10#include <linux/seq_file.h>
10#include <linux/sysctl.h> 11#include <linux/sysctl.h>
11#include <linux/highmem.h> 12#include <linux/highmem.h>
12#include <linux/mmu_notifier.h> 13#include <linux/mmu_notifier.h>
@@ -262,7 +263,7 @@ struct resv_map {
262 struct list_head regions; 263 struct list_head regions;
263}; 264};
264 265
265struct resv_map *resv_map_alloc(void) 266static struct resv_map *resv_map_alloc(void)
266{ 267{
267 struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL); 268 struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL);
268 if (!resv_map) 269 if (!resv_map)
@@ -274,7 +275,7 @@ struct resv_map *resv_map_alloc(void)
274 return resv_map; 275 return resv_map;
275} 276}
276 277
277void resv_map_release(struct kref *ref) 278static void resv_map_release(struct kref *ref)
278{ 279{
279 struct resv_map *resv_map = container_of(ref, struct resv_map, refs); 280 struct resv_map *resv_map = container_of(ref, struct resv_map, refs);
280 281
@@ -289,7 +290,7 @@ static struct resv_map *vma_resv_map(struct vm_area_struct *vma)
289 if (!(vma->vm_flags & VM_SHARED)) 290 if (!(vma->vm_flags & VM_SHARED))
290 return (struct resv_map *)(get_vma_private_data(vma) & 291 return (struct resv_map *)(get_vma_private_data(vma) &
291 ~HPAGE_RESV_MASK); 292 ~HPAGE_RESV_MASK);
292 return 0; 293 return NULL;
293} 294}
294 295
295static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map) 296static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map)
@@ -1455,15 +1456,15 @@ int hugetlb_overcommit_handler(struct ctl_table *table, int write,
1455 1456
1456#endif /* CONFIG_SYSCTL */ 1457#endif /* CONFIG_SYSCTL */
1457 1458
1458int hugetlb_report_meminfo(char *buf) 1459void hugetlb_report_meminfo(struct seq_file *m)
1459{ 1460{
1460 struct hstate *h = &default_hstate; 1461 struct hstate *h = &default_hstate;
1461 return sprintf(buf, 1462 seq_printf(m,
1462 "HugePages_Total: %5lu\n" 1463 "HugePages_Total: %5lu\n"
1463 "HugePages_Free: %5lu\n" 1464 "HugePages_Free: %5lu\n"
1464 "HugePages_Rsvd: %5lu\n" 1465 "HugePages_Rsvd: %5lu\n"
1465 "HugePages_Surp: %5lu\n" 1466 "HugePages_Surp: %5lu\n"
1466 "Hugepagesize: %5lu kB\n", 1467 "Hugepagesize: %8lu kB\n",
1467 h->nr_huge_pages, 1468 h->nr_huge_pages,
1468 h->free_huge_pages, 1469 h->free_huge_pages,
1469 h->resv_huge_pages, 1470 h->resv_huge_pages,
@@ -1747,10 +1748,8 @@ void unmap_hugepage_range(struct vm_area_struct *vma, unsigned long start,
1747 * from other VMAs and let the children be SIGKILLed if they are faulting the 1748 * from other VMAs and let the children be SIGKILLed if they are faulting the
1748 * same region. 1749 * same region.
1749 */ 1750 */
1750int unmap_ref_private(struct mm_struct *mm, 1751static int unmap_ref_private(struct mm_struct *mm, struct vm_area_struct *vma,
1751 struct vm_area_struct *vma, 1752 struct page *page, unsigned long address)
1752 struct page *page,
1753 unsigned long address)
1754{ 1753{
1755 struct vm_area_struct *iter_vma; 1754 struct vm_area_struct *iter_vma;
1756 struct address_space *mapping; 1755 struct address_space *mapping;
@@ -2008,7 +2007,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
2008 entry = huge_ptep_get(ptep); 2007 entry = huge_ptep_get(ptep);
2009 if (huge_pte_none(entry)) { 2008 if (huge_pte_none(entry)) {
2010 ret = hugetlb_no_page(mm, vma, address, ptep, write_access); 2009 ret = hugetlb_no_page(mm, vma, address, ptep, write_access);
2011 goto out_unlock; 2010 goto out_mutex;
2012 } 2011 }
2013 2012
2014 ret = 0; 2013 ret = 0;
@@ -2024,7 +2023,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
2024 if (write_access && !pte_write(entry)) { 2023 if (write_access && !pte_write(entry)) {
2025 if (vma_needs_reservation(h, vma, address) < 0) { 2024 if (vma_needs_reservation(h, vma, address) < 0) {
2026 ret = VM_FAULT_OOM; 2025 ret = VM_FAULT_OOM;
2027 goto out_unlock; 2026 goto out_mutex;
2028 } 2027 }
2029 2028
2030 if (!(vma->vm_flags & VM_SHARED)) 2029 if (!(vma->vm_flags & VM_SHARED))
@@ -2034,10 +2033,23 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
2034 2033
2035 spin_lock(&mm->page_table_lock); 2034 spin_lock(&mm->page_table_lock);
2036 /* Check for a racing update before calling hugetlb_cow */ 2035 /* Check for a racing update before calling hugetlb_cow */
2037 if (likely(pte_same(entry, huge_ptep_get(ptep)))) 2036 if (unlikely(!pte_same(entry, huge_ptep_get(ptep))))
2038 if (write_access && !pte_write(entry)) 2037 goto out_page_table_lock;
2038
2039
2040 if (write_access) {
2041 if (!pte_write(entry)) {
2039 ret = hugetlb_cow(mm, vma, address, ptep, entry, 2042 ret = hugetlb_cow(mm, vma, address, ptep, entry,
2040 pagecache_page); 2043 pagecache_page);
2044 goto out_page_table_lock;
2045 }
2046 entry = pte_mkdirty(entry);
2047 }
2048 entry = pte_mkyoung(entry);
2049 if (huge_ptep_set_access_flags(vma, address, ptep, entry, write_access))
2050 update_mmu_cache(vma, address, entry);
2051
2052out_page_table_lock:
2041 spin_unlock(&mm->page_table_lock); 2053 spin_unlock(&mm->page_table_lock);
2042 2054
2043 if (pagecache_page) { 2055 if (pagecache_page) {
@@ -2045,7 +2057,7 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
2045 put_page(pagecache_page); 2057 put_page(pagecache_page);
2046 } 2058 }
2047 2059
2048out_unlock: 2060out_mutex:
2049 mutex_unlock(&hugetlb_instantiation_mutex); 2061 mutex_unlock(&hugetlb_instantiation_mutex);
2050 2062
2051 return ret; 2063 return ret;
@@ -2060,6 +2072,14 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,
2060 return NULL; 2072 return NULL;
2061} 2073}
2062 2074
2075static int huge_zeropage_ok(pte_t *ptep, int write, int shared)
2076{
2077 if (!ptep || write || shared)
2078 return 0;
2079 else
2080 return huge_pte_none(huge_ptep_get(ptep));
2081}
2082
2063int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma, 2083int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
2064 struct page **pages, struct vm_area_struct **vmas, 2084 struct page **pages, struct vm_area_struct **vmas,
2065 unsigned long *position, int *length, int i, 2085 unsigned long *position, int *length, int i,
@@ -2069,6 +2089,8 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
2069 unsigned long vaddr = *position; 2089 unsigned long vaddr = *position;
2070 int remainder = *length; 2090 int remainder = *length;
2071 struct hstate *h = hstate_vma(vma); 2091 struct hstate *h = hstate_vma(vma);
2092 int zeropage_ok = 0;
2093 int shared = vma->vm_flags & VM_SHARED;
2072 2094
2073 spin_lock(&mm->page_table_lock); 2095 spin_lock(&mm->page_table_lock);
2074 while (vaddr < vma->vm_end && remainder) { 2096 while (vaddr < vma->vm_end && remainder) {
@@ -2081,8 +2103,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
2081 * first, for the page indexing below to work. 2103 * first, for the page indexing below to work.
2082 */ 2104 */
2083 pte = huge_pte_offset(mm, vaddr & huge_page_mask(h)); 2105 pte = huge_pte_offset(mm, vaddr & huge_page_mask(h));
2106 if (huge_zeropage_ok(pte, write, shared))
2107 zeropage_ok = 1;
2084 2108
2085 if (!pte || huge_pte_none(huge_ptep_get(pte)) || 2109 if (!pte ||
2110 (huge_pte_none(huge_ptep_get(pte)) && !zeropage_ok) ||
2086 (write && !pte_write(huge_ptep_get(pte)))) { 2111 (write && !pte_write(huge_ptep_get(pte)))) {
2087 int ret; 2112 int ret;
2088 2113
@@ -2102,8 +2127,11 @@ int follow_hugetlb_page(struct mm_struct *mm, struct vm_area_struct *vma,
2102 page = pte_page(huge_ptep_get(pte)); 2127 page = pte_page(huge_ptep_get(pte));
2103same_page: 2128same_page:
2104 if (pages) { 2129 if (pages) {
2105 get_page(page); 2130 if (zeropage_ok)
2106 pages[i] = page + pfn_offset; 2131 pages[i] = ZERO_PAGE(0);
2132 else
2133 pages[i] = page + pfn_offset;
2134 get_page(pages[i]);
2107 } 2135 }
2108 2136
2109 if (vmas) 2137 if (vmas)