net/mlx4_core: Adjust port number in qp_attach wrapper when detaching
[cascardo/linux.git] / mm / hugetlb.c
index c01cb9f..2461929 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/nodemask.h>
 #include <linux/pagemap.h>
 #include <linux/mempolicy.h>
+#include <linux/compiler.h>
 #include <linux/cpuset.h>
 #include <linux/mutex.h>
 #include <linux/bootmem.h>
@@ -22,6 +23,7 @@
 #include <linux/swap.h>
 #include <linux/swapops.h>
 #include <linux/page-isolation.h>
+#include <linux/jhash.h>
 
 #include <asm/page.h>
 #include <asm/pgtable.h>
@@ -53,6 +55,13 @@ static unsigned long __initdata default_hstate_size;
  */
 DEFINE_SPINLOCK(hugetlb_lock);
 
+/*
+ * Serializes faults on the same logical page.  This is used to
+ * prevent spurious OOMs when the hugepage pool is fully utilized.
+ */
+static int num_fault_mutexes;
+static struct mutex *htlb_fault_mutex_table ____cacheline_aligned_in_smp;
+
 static inline void unlock_or_release_subpool(struct hugepage_subpool *spool)
 {
        bool free = (spool->count == 0) && (spool->used_hpages == 0);
@@ -135,15 +144,8 @@ static inline struct hugepage_subpool *subpool_vma(struct vm_area_struct *vma)
  * Region tracking -- allows tracking of reservations and instantiated pages
  *                    across the pages in a mapping.
  *
- * The region data structures are protected by a combination of the mmap_sem
- * and the hugetlb_instantiation_mutex.  To access or modify a region the caller
- * must either hold the mmap_sem for write, or the mmap_sem for read and
- * the hugetlb_instantiation_mutex:
- *
- *     down_write(&mm->mmap_sem);
- * or
- *     down_read(&mm->mmap_sem);
- *     mutex_lock(&hugetlb_instantiation_mutex);
+ * The region data structures are embedded into a resv_map and
+ * protected by a resv_map's lock
  */
 struct file_region {
        struct list_head link;
@@ -151,10 +153,12 @@ struct file_region {
        long to;
 };
 
-static long region_add(struct list_head *head, long f, long t)
+static long region_add(struct resv_map *resv, long f, long t)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg, *nrg, *trg;
 
+       spin_lock(&resv->lock);
        /* Locate the region we are either in or before. */
        list_for_each_entry(rg, head, link)
                if (f <= rg->to)
@@ -184,14 +188,18 @@ static long region_add(struct list_head *head, long f, long t)
        }
        nrg->from = f;
        nrg->to = t;
+       spin_unlock(&resv->lock);
        return 0;
 }
 
-static long region_chg(struct list_head *head, long f, long t)
+static long region_chg(struct resv_map *resv, long f, long t)
 {
-       struct file_region *rg, *nrg;
+       struct list_head *head = &resv->regions;
+       struct file_region *rg, *nrg = NULL;
        long chg = 0;
 
+retry:
+       spin_lock(&resv->lock);
        /* Locate the region we are before or in. */
        list_for_each_entry(rg, head, link)
                if (f <= rg->to)
@@ -201,15 +209,21 @@ static long region_chg(struct list_head *head, long f, long t)
         * Subtle, allocate a new region at the position but make it zero
         * size such that we can guarantee to record the reservation. */
        if (&rg->link == head || t < rg->from) {
-               nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
-               if (!nrg)
-                       return -ENOMEM;
-               nrg->from = f;
-               nrg->to   = f;
-               INIT_LIST_HEAD(&nrg->link);
-               list_add(&nrg->link, rg->link.prev);
+               if (!nrg) {
+                       spin_unlock(&resv->lock);
+                       nrg = kmalloc(sizeof(*nrg), GFP_KERNEL);
+                       if (!nrg)
+                               return -ENOMEM;
+
+                       nrg->from = f;
+                       nrg->to   = f;
+                       INIT_LIST_HEAD(&nrg->link);
+                       goto retry;
+               }
 
-               return t - f;
+               list_add(&nrg->link, rg->link.prev);
+               chg = t - f;
+               goto out_nrg;
        }
 
        /* Round our left edge to the current segment if it encloses us. */
@@ -222,7 +236,7 @@ static long region_chg(struct list_head *head, long f, long t)
                if (&rg->link == head)
                        break;
                if (rg->from > t)
-                       return chg;
+                       goto out;
 
                /* We overlap with this area, if it extends further than
                 * us then we must extend ourselves.  Account for its
@@ -233,20 +247,30 @@ static long region_chg(struct list_head *head, long f, long t)
                }
                chg -= rg->to - rg->from;
        }
+
+out:
+       spin_unlock(&resv->lock);
+       /*  We already know we raced and no longer need the new region */
+       kfree(nrg);
+       return chg;
+out_nrg:
+       spin_unlock(&resv->lock);
        return chg;
 }
 
-static long region_truncate(struct list_head *head, long end)
+static long region_truncate(struct resv_map *resv, long end)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg, *trg;
        long chg = 0;
 
+       spin_lock(&resv->lock);
        /* Locate the region we are either in or before. */
        list_for_each_entry(rg, head, link)
                if (end <= rg->to)
                        break;
        if (&rg->link == head)
-               return 0;
+               goto out;
 
        /* If we are in the middle of a region then adjust it. */
        if (end > rg->from) {
@@ -263,14 +287,19 @@ static long region_truncate(struct list_head *head, long end)
                list_del(&rg->link);
                kfree(rg);
        }
+
+out:
+       spin_unlock(&resv->lock);
        return chg;
 }
 
-static long region_count(struct list_head *head, long f, long t)
+static long region_count(struct resv_map *resv, long f, long t)
 {
+       struct list_head *head = &resv->regions;
        struct file_region *rg;
        long chg = 0;
 
+       spin_lock(&resv->lock);
        /* Locate each segment we overlap with, and count that overlap. */
        list_for_each_entry(rg, head, link) {
                long seg_from;
@@ -286,6 +315,7 @@ static long region_count(struct list_head *head, long f, long t)
 
                chg += seg_to - seg_from;
        }
+       spin_unlock(&resv->lock);
 
        return chg;
 }
@@ -376,39 +406,46 @@ static void set_vma_private_data(struct vm_area_struct *vma,
        vma->vm_private_data = (void *)value;
 }
 
-struct resv_map {
-       struct kref refs;
-       struct list_head regions;
-};
-
-static struct resv_map *resv_map_alloc(void)
+struct resv_map *resv_map_alloc(void)
 {
        struct resv_map *resv_map = kmalloc(sizeof(*resv_map), GFP_KERNEL);
        if (!resv_map)
                return NULL;
 
        kref_init(&resv_map->refs);
+       spin_lock_init(&resv_map->lock);
        INIT_LIST_HEAD(&resv_map->regions);
 
        return resv_map;
 }
 
-static void resv_map_release(struct kref *ref)
+void resv_map_release(struct kref *ref)
 {
        struct resv_map *resv_map = container_of(ref, struct resv_map, refs);
 
        /* Clear out any active regions before we release the map. */
-       region_truncate(&resv_map->regions, 0);
+       region_truncate(resv_map, 0);
        kfree(resv_map);
 }
 
+static inline struct resv_map *inode_resv_map(struct inode *inode)
+{
+       return inode->i_mapping->private_data;
+}
+
 static struct resv_map *vma_resv_map(struct vm_area_struct *vma)
 {
        VM_BUG_ON(!is_vm_hugetlb_page(vma));
-       if (!(vma->vm_flags & VM_MAYSHARE))
+       if (vma->vm_flags & VM_MAYSHARE) {
+               struct address_space *mapping = vma->vm_file->f_mapping;
+               struct inode *inode = mapping->host;
+
+               return inode_resv_map(inode);
+
+       } else {
                return (struct resv_map *)(get_vma_private_data(vma) &
                                                        ~HPAGE_RESV_MASK);
-       return NULL;
+       }
 }
 
 static void set_vma_resv_map(struct vm_area_struct *vma, struct resv_map *map)
@@ -540,7 +577,7 @@ static struct page *dequeue_huge_page_vma(struct hstate *h,
                goto err;
 
 retry_cpuset:
-       cpuset_mems_cookie = get_mems_allowed();
+       cpuset_mems_cookie = read_mems_allowed_begin();
        zonelist = huge_zonelist(vma, address,
                                        htlb_alloc_mask(h), &mpol, &nodemask);
 
@@ -562,7 +599,7 @@ retry_cpuset:
        }
 
        mpol_cond_put(mpol);
-       if (unlikely(!put_mems_allowed(cpuset_mems_cookie) && !page))
+       if (unlikely(!page && read_mems_allowed_retry(cpuset_mems_cookie)))
                goto retry_cpuset;
        return page;
 
@@ -653,7 +690,8 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
        put_page(page); /* free it into the hugepage allocator */
 }
 
-static void prep_compound_gigantic_page(struct page *page, unsigned long order)
+static void __init prep_compound_gigantic_page(struct page *page,
+                                              unsigned long order)
 {
        int i;
        int nr_pages = 1 << order;
@@ -1134,6 +1172,7 @@ static void return_unused_surplus_pages(struct hstate *h,
        while (nr_pages--) {
                if (!free_pool_huge_page(h, &node_states[N_MEMORY], 1))
                        break;
+               cond_resched_lock(&hugetlb_lock);
        }
 }
 
@@ -1150,45 +1189,34 @@ static void return_unused_surplus_pages(struct hstate *h,
 static long vma_needs_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
-       struct address_space *mapping = vma->vm_file->f_mapping;
-       struct inode *inode = mapping->host;
-
-       if (vma->vm_flags & VM_MAYSHARE) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               return region_chg(&inode->i_mapping->private_list,
-                                                       idx, idx + 1);
+       struct resv_map *resv;
+       pgoff_t idx;
+       long chg;
 
-       } else if (!is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
+       resv = vma_resv_map(vma);
+       if (!resv)
                return 1;
 
-       } else  {
-               long err;
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *resv = vma_resv_map(vma);
+       idx = vma_hugecache_offset(h, vma, addr);
+       chg = region_chg(resv, idx, idx + 1);
 
-               err = region_chg(&resv->regions, idx, idx + 1);
-               if (err < 0)
-                       return err;
-               return 0;
-       }
+       if (vma->vm_flags & VM_MAYSHARE)
+               return chg;
+       else
+               return chg < 0 ? chg : 0;
 }
 static void vma_commit_reservation(struct hstate *h,
                        struct vm_area_struct *vma, unsigned long addr)
 {
-       struct address_space *mapping = vma->vm_file->f_mapping;
-       struct inode *inode = mapping->host;
-
-       if (vma->vm_flags & VM_MAYSHARE) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               region_add(&inode->i_mapping->private_list, idx, idx + 1);
+       struct resv_map *resv;
+       pgoff_t idx;
 
-       } else if (is_vma_resv_set(vma, HPAGE_RESV_OWNER)) {
-               pgoff_t idx = vma_hugecache_offset(h, vma, addr);
-               struct resv_map *resv = vma_resv_map(vma);
+       resv = vma_resv_map(vma);
+       if (!resv)
+               return;
 
-               /* Mark this page used in the map. */
-               region_add(&resv->regions, idx, idx + 1);
-       }
+       idx = vma_hugecache_offset(h, vma, addr);
+       region_add(resv, idx, idx + 1);
 }
 
 static struct page *alloc_huge_page(struct vm_area_struct *vma,
@@ -1294,7 +1322,7 @@ found:
        return 1;
 }
 
-static void prep_compound_huge_page(struct page *page, int order)
+static void __init prep_compound_huge_page(struct page *page, int order)
 {
        if (unlikely(order > (MAX_ORDER - 1)))
                prep_compound_gigantic_page(page, order);
@@ -1509,6 +1537,7 @@ static unsigned long set_max_huge_pages(struct hstate *h, unsigned long count,
        while (min_count < persistent_huge_pages(h)) {
                if (!free_pool_huge_page(h, nodes_allowed, 0))
                        break;
+               cond_resched_lock(&hugetlb_lock);
        }
        while (count < persistent_huge_pages(h)) {
                if (!adjust_pool_surplus(h, nodes_allowed, 1))
@@ -1944,11 +1973,14 @@ static void __exit hugetlb_exit(void)
        }
 
        kobject_put(hugepages_kobj);
+       kfree(htlb_fault_mutex_table);
 }
 module_exit(hugetlb_exit);
 
 static int __init hugetlb_init(void)
 {
+       int i;
+
        /* Some platform decide whether they support huge pages at boot
         * time. On these, such as powerpc, HPAGE_SHIFT is set to 0 when
         * there is no such support
@@ -1973,6 +2005,17 @@ static int __init hugetlb_init(void)
        hugetlb_register_all_nodes();
        hugetlb_cgroup_file_init();
 
+#ifdef CONFIG_SMP
+       num_fault_mutexes = roundup_pow_of_two(8 * num_possible_cpus());
+#else
+       num_fault_mutexes = 1;
+#endif
+       htlb_fault_mutex_table =
+               kmalloc(sizeof(struct mutex) * num_fault_mutexes, GFP_KERNEL);
+       BUG_ON(!htlb_fault_mutex_table);
+
+       for (i = 0; i < num_fault_mutexes; i++)
+               mutex_init(&htlb_fault_mutex_table[i]);
        return 0;
 }
 module_init(hugetlb_init);
@@ -2251,41 +2294,30 @@ static void hugetlb_vm_op_open(struct vm_area_struct *vma)
         * after this open call completes.  It is therefore safe to take a
         * new reference here without additional locking.
         */
-       if (resv)
+       if (resv && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
                kref_get(&resv->refs);
 }
 
-static void resv_map_put(struct vm_area_struct *vma)
-{
-       struct resv_map *resv = vma_resv_map(vma);
-
-       if (!resv)
-               return;
-       kref_put(&resv->refs, resv_map_release);
-}
-
 static void hugetlb_vm_op_close(struct vm_area_struct *vma)
 {
        struct hstate *h = hstate_vma(vma);
        struct resv_map *resv = vma_resv_map(vma);
        struct hugepage_subpool *spool = subpool_vma(vma);
-       unsigned long reserve;
-       unsigned long start;
-       unsigned long end;
+       unsigned long reserve, start, end;
+
+       if (!resv || !is_vma_resv_set(vma, HPAGE_RESV_OWNER))
+               return;
 
-       if (resv) {
-               start = vma_hugecache_offset(h, vma, vma->vm_start);
-               end = vma_hugecache_offset(h, vma, vma->vm_end);
+       start = vma_hugecache_offset(h, vma, vma->vm_start);
+       end = vma_hugecache_offset(h, vma, vma->vm_end);
 
-               reserve = (end - start) -
-                       region_count(&resv->regions, start, end);
+       reserve = (end - start) - region_count(resv, start, end);
 
-               resv_map_put(vma);
+       kref_put(&resv->refs, resv_map_release);
 
-               if (reserve) {
-                       hugetlb_acct_memory(h, -reserve);
-                       hugepage_subpool_put_pages(spool, reserve);
-               }
+       if (reserve) {
+               hugetlb_acct_memory(h, -reserve);
+               hugepage_subpool_put_pages(spool, reserve);
        }
 }
 
@@ -2661,7 +2693,8 @@ retry_avoidcopy:
                                BUG_ON(huge_pte_none(pte));
                                spin_lock(ptl);
                                ptep = huge_pte_offset(mm, address & huge_page_mask(h));
-                               if (likely(pte_same(huge_ptep_get(ptep), pte)))
+                               if (likely(ptep &&
+                                          pte_same(huge_ptep_get(ptep), pte)))
                                        goto retry_avoidcopy;
                                /*
                                 * race occurs while re-acquiring page table
@@ -2705,7 +2738,7 @@ retry_avoidcopy:
         */
        spin_lock(ptl);
        ptep = huge_pte_offset(mm, address & huge_page_mask(h));
-       if (likely(pte_same(huge_ptep_get(ptep), pte))) {
+       if (likely(ptep && pte_same(huge_ptep_get(ptep), pte))) {
                ClearPagePrivate(new_page);
 
                /* Break COW */
@@ -2761,15 +2794,14 @@ static bool hugetlbfs_pagecache_present(struct hstate *h,
 }
 
 static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
-                       unsigned long address, pte_t *ptep, unsigned int flags)
+                          struct address_space *mapping, pgoff_t idx,
+                          unsigned long address, pte_t *ptep, unsigned int flags)
 {
        struct hstate *h = hstate_vma(vma);
        int ret = VM_FAULT_SIGBUS;
        int anon_rmap = 0;
-       pgoff_t idx;
        unsigned long size;
        struct page *page;
-       struct address_space *mapping;
        pte_t new_pte;
        spinlock_t *ptl;
 
@@ -2784,9 +2816,6 @@ static int hugetlb_no_page(struct mm_struct *mm, struct vm_area_struct *vma,
                return ret;
        }
 
-       mapping = vma->vm_file->f_mapping;
-       idx = vma_hugecache_offset(h, vma, address);
-
        /*
         * Use page lock to guard against racing truncation
         * before we get page_table_lock.
@@ -2871,8 +2900,7 @@ retry:
        if (anon_rmap) {
                ClearPagePrivate(page);
                hugepage_add_new_anon_rmap(page, vma, address);
-       }
-       else
+       } else
                page_dup_rmap(page);
        new_pte = make_huge_pte(vma, page, ((vma->vm_flags & VM_WRITE)
                                && (vma->vm_flags & VM_SHARED)));
@@ -2896,17 +2924,53 @@ backout_unlocked:
        goto out;
 }
 
+#ifdef CONFIG_SMP
+static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
+                           struct vm_area_struct *vma,
+                           struct address_space *mapping,
+                           pgoff_t idx, unsigned long address)
+{
+       unsigned long key[2];
+       u32 hash;
+
+       if (vma->vm_flags & VM_SHARED) {
+               key[0] = (unsigned long) mapping;
+               key[1] = idx;
+       } else {
+               key[0] = (unsigned long) mm;
+               key[1] = address >> huge_page_shift(h);
+       }
+
+       hash = jhash2((u32 *)&key, sizeof(key)/sizeof(u32), 0);
+
+       return hash & (num_fault_mutexes - 1);
+}
+#else
+/*
+ * For uniprocesor systems we always use a single mutex, so just
+ * return 0 and avoid the hashing overhead.
+ */
+static u32 fault_mutex_hash(struct hstate *h, struct mm_struct *mm,
+                           struct vm_area_struct *vma,
+                           struct address_space *mapping,
+                           pgoff_t idx, unsigned long address)
+{
+       return 0;
+}
+#endif
+
 int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
                        unsigned long address, unsigned int flags)
 {
-       pte_t *ptep;
-       pte_t entry;
+       pte_t *ptep, entry;
        spinlock_t *ptl;
        int ret;
+       u32 hash;
+       pgoff_t idx;
        struct page *page = NULL;
        struct page *pagecache_page = NULL;
-       static DEFINE_MUTEX(hugetlb_instantiation_mutex);
        struct hstate *h = hstate_vma(vma);
+       struct address_space *mapping;
 
        address &= huge_page_mask(h);
 
@@ -2925,15 +2989,20 @@ int hugetlb_fault(struct mm_struct *mm, struct vm_area_struct *vma,
        if (!ptep)
                return VM_FAULT_OOM;
 
+       mapping = vma->vm_file->f_mapping;
+       idx = vma_hugecache_offset(h, vma, address);
+
        /*
         * Serialize hugepage allocation and instantiation, so that we don't
         * get spurious allocation failures if two CPUs race to instantiate
         * the same page in the page cache.
         */
-       mutex_lock(&hugetlb_instantiation_mutex);
+       hash = fault_mutex_hash(h, mm, vma, mapping, idx, address);
+       mutex_lock(&htlb_fault_mutex_table[hash]);
+
        entry = huge_ptep_get(ptep);
        if (huge_pte_none(entry)) {
-               ret = hugetlb_no_page(mm, vma, address, ptep, flags);
+               ret = hugetlb_no_page(mm, vma, mapping, idx, address, ptep, flags);
                goto out_mutex;
        }
 
@@ -3002,8 +3071,7 @@ out_ptl:
        put_page(page);
 
 out_mutex:
-       mutex_unlock(&hugetlb_instantiation_mutex);
-
+       mutex_unlock(&htlb_fault_mutex_table[hash]);
        return ret;
 }
 
@@ -3120,6 +3188,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
        BUG_ON(address >= end);
        flush_cache_range(vma, address, end);
 
+       mmu_notifier_invalidate_range_start(mm, start, end);
        mutex_lock(&vma->vm_file->f_mapping->i_mmap_mutex);
        for (; address < end; address += huge_page_size(h)) {
                spinlock_t *ptl;
@@ -3149,6 +3218,7 @@ unsigned long hugetlb_change_protection(struct vm_area_struct *vma,
         */
        flush_tlb_range(vma, start, end);
        mutex_unlock(&vma->vm_file->f_mapping->i_mmap_mutex);
+       mmu_notifier_invalidate_range_end(mm, start, end);
 
        return pages << h->order;
 }
@@ -3161,6 +3231,7 @@ int hugetlb_reserve_pages(struct inode *inode,
        long ret, chg;
        struct hstate *h = hstate_inode(inode);
        struct hugepage_subpool *spool = subpool_inode(inode);
+       struct resv_map *resv_map;
 
        /*
         * Only apply hugepage reservation if asked. At fault time, an
@@ -3176,10 +3247,13 @@ int hugetlb_reserve_pages(struct inode *inode,
         * to reserve the full area even if read-only as mprotect() may be
         * called to make the mapping read-write. Assume !vma is a shm mapping
         */
-       if (!vma || vma->vm_flags & VM_MAYSHARE)
-               chg = region_chg(&inode->i_mapping->private_list, from, to);
-       else {
-               struct resv_map *resv_map = resv_map_alloc();
+       if (!vma || vma->vm_flags & VM_MAYSHARE) {
+               resv_map = inode_resv_map(inode);
+
+               chg = region_chg(resv_map, from, to);
+
+       } else {
+               resv_map = resv_map_alloc();
                if (!resv_map)
                        return -ENOMEM;
 
@@ -3222,20 +3296,23 @@ int hugetlb_reserve_pages(struct inode *inode,
         * else has to be done for private mappings here
         */
        if (!vma || vma->vm_flags & VM_MAYSHARE)
-               region_add(&inode->i_mapping->private_list, from, to);
+               region_add(resv_map, from, to);
        return 0;
 out_err:
-       if (vma)
-               resv_map_put(vma);
+       if (vma && is_vma_resv_set(vma, HPAGE_RESV_OWNER))
+               kref_put(&resv_map->refs, resv_map_release);
        return ret;
 }
 
 void hugetlb_unreserve_pages(struct inode *inode, long offset, long freed)
 {
        struct hstate *h = hstate_inode(inode);
-       long chg = region_truncate(&inode->i_mapping->private_list, offset);
+       struct resv_map *resv_map = inode_resv_map(inode);
+       long chg = 0;
        struct hugepage_subpool *spool = subpool_inode(inode);
 
+       if (resv_map)
+               chg = region_truncate(resv_map, offset);
        spin_lock(&inode->i_lock);
        inode->i_blocks -= (blocks_per_huge_page(h) * freed);
        spin_unlock(&inode->i_lock);
@@ -3446,7 +3523,7 @@ follow_huge_pud(struct mm_struct *mm, unsigned long address,
 #else /* !CONFIG_ARCH_WANT_GENERAL_HUGETLB */
 
 /* Can be overriden by architectures */
-__attribute__((weak)) struct page *
+struct page * __weak
 follow_huge_pud(struct mm_struct *mm, unsigned long address,
               pud_t *pud, int write)
 {