aboutsummaryrefslogtreecommitdiffstats
path: root/mm/mempolicy.c
diff options
context:
space:
mode:
authorLee Schermerhorn <lee.schermerhorn@hp.com>2012-10-25 08:16:30 -0400
committerMel Gorman <mgorman@suse.de>2012-12-11 09:42:41 -0500
commit771fb4d806a92bf6c988fcfbd286ae40a9374332 (patch)
treeda0070fcf99959e9519ad810133ecacc45d3a096 /mm/mempolicy.c
parentd3a710337b0590f43fd236d5e6518439afc7410a (diff)
mm: mempolicy: Check for misplaced page
This patch provides a new function to test whether a page resides on a node that is appropriate for the mempolicy for the vma and address where the page is supposed to be mapped. This involves looking up the node where the page belongs. So, the function returns that node so that it may be used to allocated the page without consulting the policy again. A subsequent patch will call this function from the fault path. Because of this, I don't want to go ahead and allocate the page, e.g., via alloc_page_vma() only to have to free it if it has the correct policy. So, I just mimic the alloc_page_vma() node computation logic--sort of. Note: we could use this function to implement a MPOL_MF_STRICT behavior when migrating pages to match mbind() mempolicy--e.g., to ensure that pages in an interleaved range are reinterleaved rather than left where they are when they reside on any page in the interleave nodemask. Signed-off-by: Lee Schermerhorn <lee.schermerhorn@hp.com> Reviewed-by: Rik van Riel <riel@redhat.com> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> [ Added MPOL_F_LAZY to trigger migrate-on-fault; simplified code now that we don't have to bother with special crap for interleaved ] Signed-off-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Signed-off-by: Ingo Molnar <mingo@kernel.org> Signed-off-by: Mel Gorman <mgorman@suse.de>
Diffstat (limited to 'mm/mempolicy.c')
-rw-r--r--mm/mempolicy.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c
index c21e91477c4f..df1466d3d2d8 100644
--- a/mm/mempolicy.c
+++ b/mm/mempolicy.c
@@ -2181,6 +2181,82 @@ static void sp_free(struct sp_node *n)
2181 kmem_cache_free(sn_cache, n); 2181 kmem_cache_free(sn_cache, n);
2182} 2182}
2183 2183
2184/**
2185 * mpol_misplaced - check whether current page node is valid in policy
2186 *
2187 * @page - page to be checked
2188 * @vma - vm area where page mapped
2189 * @addr - virtual address where page mapped
2190 *
2191 * Lookup current policy node id for vma,addr and "compare to" page's
2192 * node id.
2193 *
2194 * Returns:
2195 * -1 - not misplaced, page is in the right node
2196 * node - node id where the page should be
2197 *
2198 * Policy determination "mimics" alloc_page_vma().
2199 * Called from fault path where we know the vma and faulting address.
2200 */
2201int mpol_misplaced(struct page *page, struct vm_area_struct *vma, unsigned long addr)
2202{
2203 struct mempolicy *pol;
2204 struct zone *zone;
2205 int curnid = page_to_nid(page);
2206 unsigned long pgoff;
2207 int polnid = -1;
2208 int ret = -1;
2209
2210 BUG_ON(!vma);
2211
2212 pol = get_vma_policy(current, vma, addr);
2213 if (!(pol->flags & MPOL_F_MOF))
2214 goto out;
2215
2216 switch (pol->mode) {
2217 case MPOL_INTERLEAVE:
2218 BUG_ON(addr >= vma->vm_end);
2219 BUG_ON(addr < vma->vm_start);
2220
2221 pgoff = vma->vm_pgoff;
2222 pgoff += (addr - vma->vm_start) >> PAGE_SHIFT;
2223 polnid = offset_il_node(pol, vma, pgoff);
2224 break;
2225
2226 case MPOL_PREFERRED:
2227 if (pol->flags & MPOL_F_LOCAL)
2228 polnid = numa_node_id();
2229 else
2230 polnid = pol->v.preferred_node;
2231 break;
2232
2233 case MPOL_BIND:
2234 /*
2235 * allows binding to multiple nodes.
2236 * use current page if in policy nodemask,
2237 * else select nearest allowed node, if any.
2238 * If no allowed nodes, use current [!misplaced].
2239 */
2240 if (node_isset(curnid, pol->v.nodes))
2241 goto out;
2242 (void)first_zones_zonelist(
2243 node_zonelist(numa_node_id(), GFP_HIGHUSER),
2244 gfp_zone(GFP_HIGHUSER),
2245 &pol->v.nodes, &zone);
2246 polnid = zone->node;
2247 break;
2248
2249 default:
2250 BUG();
2251 }
2252 if (curnid != polnid)
2253 ret = polnid;
2254out:
2255 mpol_cond_put(pol);
2256
2257 return ret;
2258}
2259
2184static void sp_delete(struct shared_policy *sp, struct sp_node *n) 2260static void sp_delete(struct shared_policy *sp, struct sp_node *n)
2185{ 2261{
2186 pr_debug("deleting %lx-l%lx\n", n->start, n->end); 2262 pr_debug("deleting %lx-l%lx\n", n->start, n->end);