diff options
Diffstat (limited to 'mm')
-rw-r--r-- | mm/mempolicy.c | 30 | ||||
-rw-r--r-- | mm/slab.c | 12 |
2 files changed, 42 insertions, 0 deletions
diff --git a/mm/mempolicy.c b/mm/mempolicy.c index a683a66..71430d4 100644 --- a/mm/mempolicy.c +++ b/mm/mempolicy.c @@ -976,6 +976,36 @@ static unsigned interleave_nodes(struct mempolicy *policy) return nid; } +/* + * Depending on the memory policy provide a node from which to allocate the + * next slab entry. + */ +unsigned slab_node(struct mempolicy *policy) +{ + if (in_interrupt()) + return numa_node_id(); + + switch (policy->policy) { + case MPOL_INTERLEAVE: + return interleave_nodes(policy); + + case MPOL_BIND: + /* + * Follow bind policy behavior and start allocation at the + * first node. + */ + return policy->v.zonelist->zones[0]->zone_pgdat->node_id; + + case MPOL_PREFERRED: + if (policy->v.preferred_node >= 0) + return policy->v.preferred_node; + /* Fall through */ + + default: + return numa_node_id(); + } +} + /* Do static interleaving for a VMA with known offset. */ static unsigned offset_il_node(struct mempolicy *pol, struct vm_area_struct *vma, unsigned long off) @@ -103,6 +103,7 @@ #include <linux/rcupdate.h> #include <linux/string.h> #include <linux/nodemask.h> +#include <linux/mempolicy.h> #include <linux/mutex.h> #include <asm/uaccess.h> @@ -773,6 +774,8 @@ static struct array_cache *alloc_arraycache(int node, int entries, } #ifdef CONFIG_NUMA +static void *__cache_alloc_node(kmem_cache_t *, gfp_t, int); + static inline struct array_cache **alloc_alien_cache(int node, int limit) { struct array_cache **ac_ptr; @@ -2570,6 +2573,15 @@ static inline void *____cache_alloc(kmem_cache_t *cachep, gfp_t flags) void *objp; struct array_cache *ac; +#ifdef CONFIG_NUMA + if (current->mempolicy) { + int nid = slab_node(current->mempolicy); + + if (nid != numa_node_id()) + return __cache_alloc_node(cachep, flags, nid); + } +#endif + check_irq_off(); ac = ac_data(cachep); if (likely(ac->avail)) { |