mm: have zonelist contains structs with both a zone pointer and zone_idx
[sfrench/cifs-2.6.git] / mm / mempolicy.c
index 83c69f8a64c29dd0878050b3912e5f0c2b1af3ac..90193a2a915b0fb3b359971682cf8bb6ebf1e842 100644 (file)
@@ -116,22 +116,51 @@ static void mpol_rebind_policy(struct mempolicy *pol,
 /* Do sanity checking on a policy */
 static int mpol_check_policy(int mode, nodemask_t *nodes)
 {
-       int empty = nodes_empty(*nodes);
+       int was_empty, is_empty;
+
+       if (!nodes)
+               return 0;
+
+       /*
+        * "Contextualize" the in-coming nodemast for cpusets:
+        * Remember whether in-coming nodemask was empty,  If not,
+        * restrict the nodes to the allowed nodes in the cpuset.
+        * This is guaranteed to be a subset of nodes with memory.
+        */
+       cpuset_update_task_memory_state();
+       is_empty = was_empty = nodes_empty(*nodes);
+       if (!was_empty) {
+               nodes_and(*nodes, *nodes, cpuset_current_mems_allowed);
+               is_empty = nodes_empty(*nodes); /* after "contextualization" */
+       }
 
        switch (mode) {
        case MPOL_DEFAULT:
-               if (!empty)
+               /*
+                * require caller to specify an empty nodemask
+                * before "contextualization"
+                */
+               if (!was_empty)
                        return -EINVAL;
                break;
        case MPOL_BIND:
        case MPOL_INTERLEAVE:
-               /* Preferred will only use the first bit, but allow
-                  more for now. */
-               if (empty)
+               /*
+                * require at least 1 valid node after "contextualization"
+                */
+               if (is_empty)
+                       return -EINVAL;
+               break;
+       case MPOL_PREFERRED:
+               /*
+                * Did caller specify invalid nodes?
+                * Don't silently accept this as "local allocation".
+                */
+               if (!was_empty && is_empty)
                        return -EINVAL;
                break;
        }
-       return nodes_subset(*nodes, node_states[N_HIGH_MEMORY]) ? 0 : -EINVAL;
+       return 0;
 }
 
 /* Generate a custom zonelist for the BIND policy. */
@@ -157,7 +186,7 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)
                for_each_node_mask(nd, *nodes) { 
                        struct zone *z = &NODE_DATA(nd)->node_zones[k];
                        if (z->present_pages > 0) 
-                               zl->zones[num++] = z;
+                               zoneref_set_zone(z, &zl->_zonerefs[num++]);
                }
                if (k == 0)
                        break;
@@ -167,7 +196,8 @@ static struct zonelist *bind_zonelist(nodemask_t *nodes)
                kfree(zl);
                return ERR_PTR(-EINVAL);
        }
-       zl->zones[num] = NULL;
+       zl->_zonerefs[num].zone = NULL;
+       zl->_zonerefs[num].zone_idx = 0;
        return zl;
 }
 
@@ -188,8 +218,6 @@ static struct mempolicy *mpol_new(int mode, nodemask_t *nodes)
        switch (mode) {
        case MPOL_INTERLEAVE:
                policy->v.nodes = *nodes;
-               nodes_and(policy->v.nodes, policy->v.nodes,
-                                       node_states[N_HIGH_MEMORY]);
                if (nodes_weight(policy->v.nodes) == 0) {
                        kmem_cache_free(policy_cache, policy);
                        return ERR_PTR(-EINVAL);
@@ -421,18 +449,6 @@ static int mbind_range(struct vm_area_struct *vma, unsigned long start,
        return err;
 }
 
-static int contextualize_policy(int mode, nodemask_t *nodes)
-{
-       if (!nodes)
-               return 0;
-
-       cpuset_update_task_memory_state();
-       if (!cpuset_nodes_subset_current_mems_allowed(*nodes))
-               return -EINVAL;
-       return mpol_check_policy(mode, nodes);
-}
-
-
 /*
  * Update task->flags PF_MEMPOLICY bit: set iff non-default
  * mempolicy.  Allows more rapid checking of this (combined perhaps
@@ -468,7 +484,7 @@ static long do_set_mempolicy(int mode, nodemask_t *nodes)
 {
        struct mempolicy *new;
 
-       if (contextualize_policy(mode, nodes))
+       if (mpol_check_policy(mode, nodes))
                return -EINVAL;
        new = mpol_new(mode, nodes);
        if (IS_ERR(new))
@@ -489,9 +505,11 @@ static void get_zonemask(struct mempolicy *p, nodemask_t *nodes)
        nodes_clear(*nodes);
        switch (p->policy) {
        case MPOL_BIND:
-               for (i = 0; p->v.zonelist->zones[i]; i++)
-                       node_set(zone_to_nid(p->v.zonelist->zones[i]),
-                               *nodes);
+               for (i = 0; p->v.zonelist->_zonerefs[i].zone; i++) {
+                       struct zoneref *zref;
+                       zref = &p->v.zonelist->_zonerefs[i];
+                       node_set(zonelist_node_idx(zref), *nodes);
+               }
                break;
        case MPOL_DEFAULT:
                break;
@@ -915,10 +933,6 @@ asmlinkage long sys_mbind(unsigned long start, unsigned long len,
        err = get_nodes(&nodes, nmask, maxnode);
        if (err)
                return err;
-#ifdef CONFIG_CPUSETS
-       /* Restrict the nodes to the allowed nodes in the cpuset */
-       nodes_and(nodes, nodes, current->mems_allowed);
-#endif
        return do_mbind(start, len, mode, &nodes, flags);
 }
 
@@ -1172,7 +1186,7 @@ static struct zonelist *zonelist_policy(gfp_t gfp, struct mempolicy *policy)
                nd = 0;
                BUG();
        }
-       return NODE_DATA(nd)->node_zonelists + gfp_zone(gfp);
+       return node_zonelist(nd, gfp);
 }
 
 /* Do dynamic interleaving for a process */
@@ -1201,12 +1215,13 @@ unsigned slab_node(struct mempolicy *policy)
        case MPOL_INTERLEAVE:
                return interleave_nodes(policy);
 
-       case MPOL_BIND:
+       case MPOL_BIND: {
                /*
                 * Follow bind policy behavior and start allocation at the
                 * first node.
                 */
-               return zone_to_nid(policy->v.zonelist->zones[0]);
+               return zonelist_node_idx(policy->v.zonelist->_zonerefs);
+       }
 
        case MPOL_PREFERRED:
                if (policy->v.preferred_node >= 0)
@@ -1285,8 +1300,10 @@ struct zonelist *huge_zonelist(struct vm_area_struct *vma, unsigned long addr,
                unsigned nid;
 
                nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
-               __mpol_free(pol);               /* finished with pol */
-               return NODE_DATA(nid)->node_zonelists + gfp_zone(gfp_flags);
+               if (unlikely(pol != &default_policy &&
+                               pol != current->mempolicy))
+                       __mpol_free(pol);       /* finished with pol */
+               return node_zonelist(nid, gfp_flags);
        }
 
        zl = zonelist_policy(GFP_HIGHUSER, pol);
@@ -1308,9 +1325,9 @@ static struct page *alloc_page_interleave(gfp_t gfp, unsigned order,
        struct zonelist *zl;
        struct page *page;
 
-       zl = NODE_DATA(nid)->node_zonelists + gfp_zone(gfp);
+       zl = node_zonelist(nid, gfp);
        page = __alloc_pages(gfp, order, zl);
-       if (page && page_zone(page) == zl->zones[0])
+       if (page && page_zone(page) == zonelist_zone(&zl->_zonerefs[0]))
                inc_zone_page_state(page, NUMA_INTERLEAVE_HIT);
        return page;
 }
@@ -1349,6 +1366,9 @@ alloc_page_vma(gfp_t gfp, struct vm_area_struct *vma, unsigned long addr)
                unsigned nid;
 
                nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
+               if (unlikely(pol != &default_policy &&
+                               pol != current->mempolicy))
+                       __mpol_free(pol);       /* finished with pol */
                return alloc_page_interleave(gfp, 0, nid);
        }
        zl = zonelist_policy(gfp, pol);
@@ -1447,10 +1467,14 @@ int __mpol_equal(struct mempolicy *a, struct mempolicy *b)
                return a->v.preferred_node == b->v.preferred_node;
        case MPOL_BIND: {
                int i;
-               for (i = 0; a->v.zonelist->zones[i]; i++)
-                       if (a->v.zonelist->zones[i] != b->v.zonelist->zones[i])
+               for (i = 0; a->v.zonelist->_zonerefs[i].zone; i++) {
+                       struct zone *za, *zb;
+                       za = zonelist_zone(&a->v.zonelist->_zonerefs[i]);
+                       zb = zonelist_zone(&b->v.zonelist->_zonerefs[i]);
+                       if (za != zb)
                                return 0;
-               return b->v.zonelist->zones[i] == NULL;
+               }
+               return b->v.zonelist->_zonerefs[i].zone == NULL;
        }
        default:
                BUG();
@@ -1769,12 +1793,12 @@ static void mpol_rebind_policy(struct mempolicy *pol,
                break;
        case MPOL_BIND: {
                nodemask_t nodes;
-               struct zone **z;
+               struct zoneref *z;
                struct zonelist *zonelist;
 
                nodes_clear(nodes);
-               for (z = pol->v.zonelist->zones; *z; z++)
-                       node_set(zone_to_nid(*z), nodes);
+               for (z = pol->v.zonelist->_zonerefs; z->zone; z++)
+                       node_set(zonelist_node_idx(z), nodes);
                nodes_remap(tmp, nodes, *mpolmask, *newmask);
                nodes = tmp;
 
@@ -1985,7 +2009,7 @@ int show_numa_map(struct seq_file *m, void *v)
 
        if (file) {
                seq_printf(m, " file=");
-               seq_path(m, file->f_path.mnt, file->f_path.dentry, "\n\t= ");
+               seq_path(m, &file->f_path, "\n\t= ");
        } else if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) {
                seq_printf(m, " heap");
        } else if (vma->vm_start <= mm->start_stack &&