memblock: stop aliasing __memblock_free_late with memblock_free_late
[linux-block.git] / mm / mempolicy.c
index 1592b081c58ef6dd63c6f075ad24722f2be7cb5d..ce722333d9f64303f947310d7f62ed34e955eddc 100644 (file)
@@ -856,16 +856,6 @@ static long do_set_mempolicy(unsigned short mode, unsigned short flags,
                goto out;
        }
 
-       if (flags & MPOL_F_NUMA_BALANCING) {
-               if (new && new->mode == MPOL_BIND) {
-                       new->flags |= (MPOL_F_MOF | MPOL_F_MORON);
-               } else {
-                       ret = -EINVAL;
-                       mpol_put(new);
-                       goto out;
-               }
-       }
-
        ret = mpol_set_nodemask(new, nodes, scratch);
        if (ret) {
                mpol_put(new);
@@ -1458,7 +1448,11 @@ static inline int sanitize_mpol_flags(int *mode, unsigned short *flags)
                return -EINVAL;
        if ((*flags & MPOL_F_STATIC_NODES) && (*flags & MPOL_F_RELATIVE_NODES))
                return -EINVAL;
-
+       if (*flags & MPOL_F_NUMA_BALANCING) {
+               if (*mode != MPOL_BIND)
+                       return -EINVAL;
+               *flags |= (MPOL_F_MOF | MPOL_F_MORON);
+       }
        return 0;
 }
 
@@ -2202,6 +2196,88 @@ struct page *alloc_pages(gfp_t gfp, unsigned order)
 }
 EXPORT_SYMBOL(alloc_pages);
 
+static unsigned long alloc_pages_bulk_array_interleave(gfp_t gfp,
+               struct mempolicy *pol, unsigned long nr_pages,
+               struct page **page_array)
+{
+       int nodes;
+       unsigned long nr_pages_per_node;
+       int delta;
+       int i;
+       unsigned long nr_allocated;
+       unsigned long total_allocated = 0;
+
+       nodes = nodes_weight(pol->nodes);
+       nr_pages_per_node = nr_pages / nodes;
+       delta = nr_pages - nodes * nr_pages_per_node;
+
+       for (i = 0; i < nodes; i++) {
+               if (delta) {
+                       nr_allocated = __alloc_pages_bulk(gfp,
+                                       interleave_nodes(pol), NULL,
+                                       nr_pages_per_node + 1, NULL,
+                                       page_array);
+                       delta--;
+               } else {
+                       nr_allocated = __alloc_pages_bulk(gfp,
+                                       interleave_nodes(pol), NULL,
+                                       nr_pages_per_node, NULL, page_array);
+               }
+
+               page_array += nr_allocated;
+               total_allocated += nr_allocated;
+       }
+
+       return total_allocated;
+}
+
+static unsigned long alloc_pages_bulk_array_preferred_many(gfp_t gfp, int nid,
+               struct mempolicy *pol, unsigned long nr_pages,
+               struct page **page_array)
+{
+       gfp_t preferred_gfp;
+       unsigned long nr_allocated = 0;
+
+       preferred_gfp = gfp | __GFP_NOWARN;
+       preferred_gfp &= ~(__GFP_DIRECT_RECLAIM | __GFP_NOFAIL);
+
+       nr_allocated  = __alloc_pages_bulk(preferred_gfp, nid, &pol->nodes,
+                                          nr_pages, NULL, page_array);
+
+       if (nr_allocated < nr_pages)
+               nr_allocated += __alloc_pages_bulk(gfp, numa_node_id(), NULL,
+                               nr_pages - nr_allocated, NULL,
+                               page_array + nr_allocated);
+       return nr_allocated;
+}
+
+/* alloc pages bulk and mempolicy should be considered at the
+ * same time in some situation such as vmalloc.
+ *
+ * It can accelerate memory allocation especially interleaving
+ * allocate memory.
+ */
+unsigned long alloc_pages_bulk_array_mempolicy(gfp_t gfp,
+               unsigned long nr_pages, struct page **page_array)
+{
+       struct mempolicy *pol = &default_policy;
+
+       if (!in_interrupt() && !(gfp & __GFP_THISNODE))
+               pol = get_task_policy(current);
+
+       if (pol->mode == MPOL_INTERLEAVE)
+               return alloc_pages_bulk_array_interleave(gfp, pol,
+                                                        nr_pages, page_array);
+
+       if (pol->mode == MPOL_PREFERRED_MANY)
+               return alloc_pages_bulk_array_preferred_many(gfp,
+                               numa_node_id(), pol, nr_pages, page_array);
+
+       return __alloc_pages_bulk(gfp, policy_node(gfp, pol, numa_node_id()),
+                                 policy_nodemask(gfp, pol), nr_pages, NULL,
+                                 page_array);
+}
+
 int vma_dup_policy(struct vm_area_struct *src, struct vm_area_struct *dst)
 {
        struct mempolicy *pol = mpol_dup(vma_policy(src));