{
struct mempolicy *policy;
nodemask_t cpuset_context_nmask;
- int localalloc = 0;
int ret;
pr_debug("setting mode %d flags %d nodes[0] %lx\n",
mode, flags, nodes ? nodes_addr(*nodes)[0] : -1);
- if (mode == MPOL_DEFAULT)
- return NULL;
- if (!nodes || nodes_empty(*nodes)) {
- if (mode != MPOL_PREFERRED)
+ if (mode == MPOL_DEFAULT) {
+ if (nodes && !nodes_empty(*nodes))
return ERR_PTR(-EINVAL);
- localalloc = 1; /* special case: no mode flags */
+ return NULL;
}
+ VM_BUG_ON(!nodes);
+
+ /*
+ * MPOL_PREFERRED cannot be used with MPOL_F_STATIC_NODES or
+ * MPOL_F_RELATIVE_NODES if the nodemask is empty (local allocation).
+ * All other modes require a valid pointer to a non-empty nodemask.
+ */
+ if (mode == MPOL_PREFERRED) {
+ if (nodes_empty(*nodes)) {
+ if (((flags & MPOL_F_STATIC_NODES) ||
+ (flags & MPOL_F_RELATIVE_NODES)))
+ return ERR_PTR(-EINVAL);
+ nodes = NULL; /* flag local alloc */
+ }
+ } else if (nodes_empty(*nodes))
+ return ERR_PTR(-EINVAL);
policy = kmem_cache_alloc(policy_cache, GFP_KERNEL);
if (!policy)
return ERR_PTR(-ENOMEM);
atomic_set(&policy->refcnt, 1);
policy->policy = mode;
+ policy->flags = flags;
- if (!localalloc) {
- policy->flags = flags;
+ if (nodes) {
+ /*
+ * cpuset related setup doesn't apply to local allocation
+ */
cpuset_update_task_memory_state();
if (flags & MPOL_F_RELATIVE_NODES)
mpol_relative_nodemask(&cpuset_context_nmask, nodes,
}
ret = mpol_ops[mode].create(policy,
- localalloc ? NULL : &cpuset_context_nmask);
+ nodes ? &cpuset_context_nmask : NULL);
if (ret < 0) {
kmem_cache_free(policy_cache, policy);
return ERR_PTR(ret);
{
nodemask_t tmp;
- /*
- * check 'STATIC_NODES first, as preferred_node == -1 may be
- * a temporary, "fallback" state for this policy.
- */
if (pol->flags & MPOL_F_STATIC_NODES) {
int node = first_node(pol->w.user_nodemask);
pol->v.preferred_node = node;
else
pol->v.preferred_node = -1;
- } else if (pol->v.preferred_node == -1) {
- return; /* no remap required for explicit local alloc */
} else if (pol->flags & MPOL_F_RELATIVE_NODES) {
mpol_relative_nodemask(&tmp, &pol->w.user_nodemask, nodes);
pol->v.preferred_node = first_node(tmp);
- } else {
+ } else if (pol->v.preferred_node != -1) {
pol->v.preferred_node = node_remap(pol->v.preferred_node,
pol->w.cpuset_mems_allowed,
*nodes);
if (!err) {
mpol_get(new);
vma->vm_policy = new;
- mpol_free(old);
+ mpol_put(old);
}
return err;
}
nodemask_t *nodes)
{
struct mempolicy *new;
+ struct mm_struct *mm = current->mm;
new = mpol_new(mode, flags, nodes);
if (IS_ERR(new))
return PTR_ERR(new);
- mpol_free(current->mempolicy);
+
+ /*
+ * prevent changing our mempolicy while show_numa_maps()
+ * is using it.
+ * Note: do_set_mempolicy() can be called at init time
+ * with no 'mm'.
+ */
+ if (mm)
+ down_write(&mm->mmap_sem);
+ mpol_put(current->mempolicy);
current->mempolicy = new;
mpol_set_task_struct_flag();
if (new && new->policy == MPOL_INTERLEAVE &&
nodes_weight(new->v.nodes))
current->il_next = first_node(new->v.nodes);
+ if (mm)
+ up_write(&mm->mmap_sem);
+
return 0;
}
}
up_write(&mm->mmap_sem);
- mpol_free(new);
+ mpol_put(new);
return err;
}
nid = interleave_nid(pol, vma, addr, HPAGE_SHIFT);
if (unlikely(pol != &default_policy &&
pol != current->mempolicy))
- __mpol_free(pol); /* finished with pol */
+ __mpol_put(pol); /* finished with pol */
return node_zonelist(nid, gfp_flags);
}
zl = zonelist_policy(GFP_HIGHUSER, pol);
if (unlikely(pol != &default_policy && pol != current->mempolicy)) {
if (pol->policy != MPOL_BIND)
- __mpol_free(pol); /* finished with pol */
+ __mpol_put(pol); /* finished with pol */
else
*mpol = pol; /* unref needed after allocation */
}
nid = interleave_nid(pol, vma, addr, PAGE_SHIFT);
if (unlikely(pol != &default_policy &&
pol != current->mempolicy))
- __mpol_free(pol); /* finished with pol */
+ __mpol_put(pol); /* finished with pol */
return alloc_page_interleave(gfp, 0, nid);
}
zl = zonelist_policy(gfp, pol);
*/
struct page *page = __alloc_pages_nodemask(gfp, 0,
zl, nodemask_policy(gfp, pol));
- __mpol_free(pol);
+ __mpol_put(pol);
return page;
}
/*
EXPORT_SYMBOL(alloc_pages_current);
/*
- * If mpol_copy() sees current->cpuset == cpuset_being_rebound, then it
+ * If mpol_dup() sees current->cpuset == cpuset_being_rebound, then it
* rebinds the mempolicy its copying by calling mpol_rebind_policy()
* with the mems_allowed returned by cpuset_mems_allowed(). This
* keeps mempolicies cpuset relative after its cpuset moves. See
* further kernel/cpuset.c update_nodemask().
*/
-/* Slow path of a mempolicy copy */
-struct mempolicy *__mpol_copy(struct mempolicy *old)
+/* Slow path of a mempolicy duplicate */
+struct mempolicy *__mpol_dup(struct mempolicy *old)
{
struct mempolicy *new = kmem_cache_alloc(policy_cache, GFP_KERNEL);
}
/* Slow path of a mpol destructor. */
-void __mpol_free(struct mempolicy *p)
+void __mpol_put(struct mempolicy *p)
{
if (!atomic_dec_and_test(&p->refcnt))
return;
{
pr_debug("deleting %lx-l%lx\n", n->start, n->end);
rb_erase(&n->nd, &sp->root);
- mpol_free(n->policy);
+ mpol_put(n->policy);
kmem_cache_free(sn_cache, n);
}
sp_insert(sp, new);
spin_unlock(&sp->lock);
if (new2) {
- mpol_free(new2->policy);
+ mpol_put(new2->policy);
kmem_cache_free(sn_cache, new2);
}
return 0;
/* Policy covers entire file */
pvma.vm_end = TASK_SIZE;
mpol_set_shared_policy(info, &pvma, newpol);
- mpol_free(newpol);
+ mpol_put(newpol);
}
}
}
n = rb_entry(next, struct sp_node, nd);
next = rb_next(&n->nd);
rb_erase(&n->nd, &p->root);
- mpol_free(n->policy);
+ mpol_put(n->policy);
kmem_cache_free(sn_cache, n);
}
spin_unlock(&p->lock);
* unref shared or other task's mempolicy
*/
if (pol != &default_policy && pol != current->mempolicy)
- __mpol_free(pol);
+ __mpol_put(pol);
seq_printf(m, "%08lx %s", vma->vm_start, buffer);