aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--include/linux/mempolicy.h8
-rw-r--r--include/uapi/linux/mempolicy.h1
-rw-r--r--mm/mempolicy.c76
3 files changed, 85 insertions, 0 deletions
diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h
index e5ccb9ddd90e..c511e2523560 100644
--- a/include/linux/mempolicy.h
+++ b/include/linux/mempolicy.h
@@ -198,6 +198,8 @@ static inline int vma_migratable(struct vm_area_struct *vma)
198 return 1; 198 return 1;
199} 199}
200 200
201extern int mpol_misplaced(struct page *, struct vm_area_struct *, unsigned long);
202
201#else 203#else
202 204
203struct mempolicy {}; 205struct mempolicy {};
@@ -323,5 +325,11 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol,
323 return 0; 325 return 0;
324} 326}
325 327
328static inline int mpol_misplaced(struct page *page, struct vm_area_struct *vma,
329 unsigned long address)
330{
331 return -1; /* no node preference */
332}
333
326#endif /* CONFIG_NUMA */ 334#endif /* CONFIG_NUMA */
327#endif 335#endif
diff --git a/include/uapi/linux/mempolicy.h b/include/uapi/linux/mempolicy.h
index d23dca8367cc..472de8a5d37e 100644
--- a/include/uapi/linux/mempolicy.h
+++ b/include/uapi/linux/mempolicy.h
@@ -61,6 +61,7 @@ enum mpol_rebind_step {
61#define MPOL_F_SHARED (1 << 0) /* identify shared policies */ 61#define MPOL_F_SHARED (1 << 0) /* identify shared policies */
62#define MPOL_F_LOCAL (1 << 1) /* preferred local allocation */ 62#define MPOL_F_LOCAL (1 << 1) /* preferred local allocation */
63#define MPOL_F_REBINDING (1 << 2) /* identify policies in rebinding */ 63#define MPOL_F_REBINDING (1 << 2) /* identify policies in rebinding */
64#define MPOL_F_MOF (1 << 3) /* this policy wants migrate on fault */
64 65
65 66
66#endif /* _UAPI_LINUX_MEMPOLICY_H */ 67#endif /* _UAPI_LINUX_MEMPOLICY_H */
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);