clk: meson: g12: use devm variant to register notifiers
[platform/kernel/linux-starfive.git] / mm / hugetlb.c
index 67fc638..fe76f8f 100644 (file)
@@ -240,7 +240,6 @@ get_file_region_entry_from_cache(struct resv_map *resv, long from, long to)
 
        resv->region_cache_count--;
        nrg = list_first_entry(&resv->region_cache, struct file_region, link);
-       VM_BUG_ON(!nrg);
        list_del(&nrg->link);
 
        nrg->from = from;
@@ -309,8 +308,7 @@ static void coalesce_file_region(struct resv_map *resv, struct file_region *rg)
                list_del(&rg->link);
                kfree(rg);
 
-               coalesce_file_region(resv, prg);
-               return;
+               rg = prg;
        }
 
        nrg = list_next_entry(rg, link);
@@ -320,22 +318,20 @@ static void coalesce_file_region(struct resv_map *resv, struct file_region *rg)
 
                list_del(&rg->link);
                kfree(rg);
-
-               coalesce_file_region(resv, nrg);
-               return;
        }
 }
 
-/* Must be called with resv->lock held. Calling this with count_only == true
- * will count the number of pages to be added but will not modify the linked
- * list. If regions_needed != NULL and count_only == true, then regions_needed
- * will indicate the number of file_regions needed in the cache to carry out to
- * add the regions for this range.
+/*
+ * Must be called with resv->lock held.
+ *
+ * Calling this with regions_needed != NULL will count the number of pages
+ * to be added but will not modify the linked list. And regions_needed will
+ * indicate the number of file_regions needed in the cache to carry out to add
+ * the regions for this range.
  */
 static long add_reservation_in_range(struct resv_map *resv, long f, long t,
                                     struct hugetlb_cgroup *h_cg,
-                                    struct hstate *h, long *regions_needed,
-                                    bool count_only)
+                                    struct hstate *h, long *regions_needed)
 {
        long add = 0;
        struct list_head *head = &resv->regions;
@@ -371,14 +367,14 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
                 */
                if (rg->from > last_accounted_offset) {
                        add += rg->from - last_accounted_offset;
-                       if (!count_only) {
+                       if (!regions_needed) {
                                nrg = get_file_region_entry_from_cache(
                                        resv, last_accounted_offset, rg->from);
                                record_hugetlb_cgroup_uncharge_info(h_cg, h,
                                                                    resv, nrg);
                                list_add(&nrg->link, rg->link.prev);
                                coalesce_file_region(resv, nrg);
-                       } else if (regions_needed)
+                       } else
                                *regions_needed += 1;
                }
 
@@ -390,13 +386,13 @@ static long add_reservation_in_range(struct resv_map *resv, long f, long t,
         */
        if (last_accounted_offset < t) {
                add += t - last_accounted_offset;
-               if (!count_only) {
+               if (!regions_needed) {
                        nrg = get_file_region_entry_from_cache(
                                resv, last_accounted_offset, t);
                        record_hugetlb_cgroup_uncharge_info(h_cg, h, resv, nrg);
                        list_add(&nrg->link, rg->link.prev);
                        coalesce_file_region(resv, nrg);
-               } else if (regions_needed)
+               } else
                        *regions_needed += 1;
        }
 
@@ -448,11 +444,8 @@ static int allocate_file_region_entries(struct resv_map *resv,
 
                spin_lock(&resv->lock);
 
-               list_for_each_entry_safe(rg, trg, &allocated_regions, link) {
-                       list_del(&rg->link);
-                       list_add(&rg->link, &resv->region_cache);
-                       resv->region_cache_count++;
-               }
+               list_splice(&allocated_regions, &resv->region_cache);
+               resv->region_cache_count += to_allocate;
        }
 
        return 0;
@@ -492,8 +485,8 @@ static long region_add(struct resv_map *resv, long f, long t,
 retry:
 
        /* Count how many regions are actually needed to execute this add. */
-       add_reservation_in_range(resv, f, t, NULL, NULL, &actual_regions_needed,
-                                true);
+       add_reservation_in_range(resv, f, t, NULL, NULL,
+                                &actual_regions_needed);
 
        /*
         * Check for sufficient descriptors in the cache to accommodate
@@ -521,7 +514,7 @@ retry:
                goto retry;
        }
 
-       add = add_reservation_in_range(resv, f, t, h_cg, h, NULL, false);
+       add = add_reservation_in_range(resv, f, t, h_cg, h, NULL);
 
        resv->adds_in_progress -= in_regions_needed;
 
@@ -557,9 +550,9 @@ static long region_chg(struct resv_map *resv, long f, long t,
 
        spin_lock(&resv->lock);
 
-       /* Count how many hugepages in this range are NOT respresented. */
+       /* Count how many hugepages in this range are NOT represented. */
        chg = add_reservation_in_range(resv, f, t, NULL, NULL,
-                                      out_regions_needed, true);
+                                      out_regions_needed);
 
        if (*out_regions_needed == 0)
                *out_regions_needed = 1;
@@ -1047,21 +1040,17 @@ static struct page *dequeue_huge_page_node_exact(struct hstate *h, int nid)
                if (nocma && is_migrate_cma_page(page))
                        continue;
 
-               if (!PageHWPoison(page))
-                       break;
+               if (PageHWPoison(page))
+                       continue;
+
+               list_move(&page->lru, &h->hugepage_activelist);
+               set_page_refcounted(page);
+               h->free_huge_pages--;
+               h->free_huge_pages_node[nid]--;
+               return page;
        }
 
-       /*
-        * if 'non-isolated free hugepage' not found on the list,
-        * the allocation fails.
-        */
-       if (&h->hugepage_freelists[nid] == &page->lru)
-               return NULL;
-       list_move(&page->lru, &h->hugepage_activelist);
-       set_page_refcounted(page);
-       h->free_huge_pages--;
-       h->free_huge_pages_node[nid]--;
-       return page;
+       return NULL;
 }
 
 static struct page *dequeue_huge_page_nodemask(struct hstate *h, gfp_t gfp_mask, int nid,
@@ -1511,9 +1500,9 @@ static void prep_new_huge_page(struct hstate *h, struct page *page, int nid)
 {
        INIT_LIST_HEAD(&page->lru);
        set_compound_page_dtor(page, HUGETLB_PAGE_DTOR);
-       spin_lock(&hugetlb_lock);
        set_hugetlb_cgroup(page, NULL);
        set_hugetlb_cgroup_rsvd(page, NULL);
+       spin_lock(&hugetlb_lock);
        h->nr_huge_pages++;
        h->nr_huge_pages_node[nid]++;
        spin_unlock(&hugetlb_lock);
@@ -2423,7 +2412,7 @@ struct page *alloc_huge_page(struct vm_area_struct *vma,
                        h->resv_huge_pages--;
                }
                spin_lock(&hugetlb_lock);
-               list_move(&page->lru, &h->hugepage_activelist);
+               list_add(&page->lru, &h->hugepage_activelist);
                /* Fall through */
        }
        hugetlb_cgroup_commit_charge(idx, pages_per_huge_page(h), h_cg, page);
@@ -3582,18 +3571,20 @@ void hugetlb_report_meminfo(struct seq_file *m)
        seq_printf(m, "Hugetlb:        %8lu kB\n", total / 1024);
 }
 
-int hugetlb_report_node_meminfo(int nid, char *buf)
+int hugetlb_report_node_meminfo(char *buf, int len, int nid)
 {
        struct hstate *h = &default_hstate;
+
        if (!hugepages_supported())
                return 0;
-       return sprintf(buf,
-               "Node %d HugePages_Total: %5u\n"
-               "Node %d HugePages_Free:  %5u\n"
-               "Node %d HugePages_Surp:  %5u\n",
-               nid, h->nr_huge_pages_node[nid],
-               nid, h->free_huge_pages_node[nid],
-               nid, h->surplus_huge_pages_node[nid]);
+
+       return sysfs_emit_at(buf, len,
+                            "Node %d HugePages_Total: %5u\n"
+                            "Node %d HugePages_Free:  %5u\n"
+                            "Node %d HugePages_Surp:  %5u\n",
+                            nid, h->nr_huge_pages_node[nid],
+                            nid, h->free_huge_pages_node[nid],
+                            nid, h->surplus_huge_pages_node[nid]);
 }
 
 void hugetlb_show_meminfo(void)
@@ -3799,23 +3790,23 @@ bool is_hugetlb_entry_migration(pte_t pte)
        if (huge_pte_none(pte) || pte_present(pte))
                return false;
        swp = pte_to_swp_entry(pte);
-       if (non_swap_entry(swp) && is_migration_entry(swp))
+       if (is_migration_entry(swp))
                return true;
        else
                return false;
 }
 
-static int is_hugetlb_entry_hwpoisoned(pte_t pte)
+static bool is_hugetlb_entry_hwpoisoned(pte_t pte)
 {
        swp_entry_t swp;
 
        if (huge_pte_none(pte) || pte_present(pte))
-               return 0;
+               return false;
        swp = pte_to_swp_entry(pte);
-       if (non_swap_entry(swp) && is_hwpoison_entry(swp))
-               return 1;
+       if (is_hwpoison_entry(swp))
+               return true;
        else
-               return 0;
+               return false;
 }
 
 int copy_hugetlb_page_range(struct mm_struct *dst, struct mm_struct *src,
@@ -5348,10 +5339,16 @@ void adjust_range_if_pmd_sharing_possible(struct vm_area_struct *vma,
  * !shared pmd case because we can allocate the pmd later as well, it makes the
  * code much cleaner.
  *
- * This routine must be called with i_mmap_rwsem held in at least read mode.
- * For hugetlbfs, this prevents removal of any page table entries associated
- * with the address space.  This is important as we are setting up sharing
- * based on existing page table entries (mappings).
+ * This routine must be called with i_mmap_rwsem held in at least read mode if
+ * sharing is possible.  For hugetlbfs, this prevents removal of any page
+ * table entries associated with the address space.  This is important as we
+ * are setting up sharing based on existing page table entries (mappings).
+ *
+ * NOTE: This routine is only called from huge_pte_alloc.  Some callers of
+ * huge_pte_alloc know that sharing is not possible and do not take
+ * i_mmap_rwsem as a performance optimization.  This is handled by the
+ * if !vma_shareable check at the beginning of the routine. i_mmap_rwsem is
+ * only required for subsequent processing.
  */
 pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
 {
@@ -5368,6 +5365,7 @@ pte_t *huge_pmd_share(struct mm_struct *mm, unsigned long addr, pud_t *pud)
        if (!vma_shareable(vma, addr))
                return (pte_t *)pmd_alloc(mm, pud, addr);
 
+       i_mmap_assert_locked(mapping);
        vma_interval_tree_foreach(svma, &mapping->i_mmap, idx, idx) {
                if (svma == vma)
                        continue;
@@ -5708,12 +5706,12 @@ void __init hugetlb_cma_reserve(int order)
        reserved = 0;
        for_each_node_state(nid, N_ONLINE) {
                int res;
-               char name[20];
+               char name[CMA_MAX_NAME];
 
                size = min(per_node, hugetlb_cma_size - reserved);
                size = round_up(size, PAGE_SIZE << order);
 
-               snprintf(name, 20, "hugetlb%d", nid);
+               snprintf(name, sizeof(name), "hugetlb%d", nid);
                res = cma_declare_contiguous_nid(0, size, 0, PAGE_SIZE << order,
                                                 0, false, name,
                                                 &hugetlb_cma[nid], nid);