Commit 4c50bc01 authored by David Rientjes's avatar David Rientjes Committed by Linus Torvalds

mempolicy: add MPOL_F_RELATIVE_NODES flag

Adds another optional mode flag, MPOL_F_RELATIVE_NODES, that specifies
nodemasks passed via set_mempolicy() or mbind() should be considered relative
to the current task's mems_allowed.

When the mempolicy is created, the passed nodemask is folded and mapped onto
the current task's mems_allowed.  For example, consider a task using
set_mempolicy() to pass MPOL_INTERLEAVE | MPOL_F_RELATIVE_NODES with a
nodemask of 1-3.  If current's mems_allowed is 4-7, the effected nodemask is
5-7 (the second, third, and fourth node of mems_allowed).

If the same task is attached to a cpuset, the mempolicy nodemask is rebound
each time the mems are changed.  Some possible rebinds and results are:

	mems			result
	1-3			1-3
	1-7			2-4
	1,5-6			1,5-6
	1,5-7			5-7

Likewise, the zonelist built for MPOL_BIND acts on the set of zones assigned
to the resultant nodemask from the relative remap.

In the MPOL_PREFERRED case, the preferred node is remapped from the currently
effected nodemask to the relative nodemask.

This mempolicy mode flag was conceived of by Paul Jackson <pj@sgi.com>.

Cc: Paul Jackson <pj@sgi.com>
Cc: Christoph Lameter <clameter@sgi.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
Cc: Andi Kleen <ak@suse.de>
Signed-off-by: default avatarDavid Rientjes <rientjes@google.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 7ea931c9
...@@ -25,12 +25,13 @@ enum { ...@@ -25,12 +25,13 @@ enum {
/* Flags for set_mempolicy */ /* Flags for set_mempolicy */
#define MPOL_F_STATIC_NODES (1 << 15) #define MPOL_F_STATIC_NODES (1 << 15)
#define MPOL_F_RELATIVE_NODES (1 << 14)
/* /*
* MPOL_MODE_FLAGS is the union of all possible optional mode flags passed to * MPOL_MODE_FLAGS is the union of all possible optional mode flags passed to
* either set_mempolicy() or mbind(). * either set_mempolicy() or mbind().
*/ */
#define MPOL_MODE_FLAGS (MPOL_F_STATIC_NODES) #define MPOL_MODE_FLAGS (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES)
/* Flags for get_mempolicy */ /* Flags for get_mempolicy */
#define MPOL_F_NODE (1<<0) /* return next IL mode instead of node mask */ #define MPOL_F_NODE (1<<0) /* return next IL mode instead of node mask */
......
...@@ -136,7 +136,15 @@ static int is_valid_nodemask(nodemask_t *nodemask) ...@@ -136,7 +136,15 @@ static int is_valid_nodemask(nodemask_t *nodemask)
static inline int mpol_store_user_nodemask(const struct mempolicy *pol) static inline int mpol_store_user_nodemask(const struct mempolicy *pol)
{ {
return pol->flags & MPOL_F_STATIC_NODES; return pol->flags & (MPOL_F_STATIC_NODES | MPOL_F_RELATIVE_NODES);
}
static void mpol_relative_nodemask(nodemask_t *ret, const nodemask_t *orig,
const nodemask_t *rel)
{
nodemask_t tmp;
nodes_fold(tmp, *orig, nodes_weight(*rel));
nodes_onto(*ret, tmp, *rel);
} }
/* Create a new policy */ /* Create a new policy */
...@@ -157,7 +165,12 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags, ...@@ -157,7 +165,12 @@ static struct mempolicy *mpol_new(unsigned short mode, unsigned short flags,
return ERR_PTR(-ENOMEM); return ERR_PTR(-ENOMEM);
atomic_set(&policy->refcnt, 1); atomic_set(&policy->refcnt, 1);
cpuset_update_task_memory_state(); cpuset_update_task_memory_state();
nodes_and(cpuset_context_nmask, *nodes, cpuset_current_mems_allowed); if (flags & MPOL_F_RELATIVE_NODES)
mpol_relative_nodemask(&cpuset_context_nmask, nodes,
&cpuset_current_mems_allowed);
else
nodes_and(cpuset_context_nmask, *nodes,
cpuset_current_mems_allowed);
switch (mode) { switch (mode) {
case MPOL_INTERLEAVE: case MPOL_INTERLEAVE:
if (nodes_empty(*nodes) || nodes_empty(cpuset_context_nmask)) if (nodes_empty(*nodes) || nodes_empty(cpuset_context_nmask))
...@@ -873,6 +886,9 @@ asmlinkage long sys_mbind(unsigned long start, unsigned long len, ...@@ -873,6 +886,9 @@ asmlinkage long sys_mbind(unsigned long start, unsigned long len,
mode &= ~MPOL_MODE_FLAGS; mode &= ~MPOL_MODE_FLAGS;
if (mode >= MPOL_MAX) if (mode >= MPOL_MAX)
return -EINVAL; return -EINVAL;
if ((mode_flags & MPOL_F_STATIC_NODES) &&
(mode_flags & MPOL_F_RELATIVE_NODES))
return -EINVAL;
err = get_nodes(&nodes, nmask, maxnode); err = get_nodes(&nodes, nmask, maxnode);
if (err) if (err)
return err; return err;
...@@ -891,6 +907,8 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask, ...@@ -891,6 +907,8 @@ asmlinkage long sys_set_mempolicy(int mode, unsigned long __user *nmask,
mode &= ~MPOL_MODE_FLAGS; mode &= ~MPOL_MODE_FLAGS;
if ((unsigned int)mode >= MPOL_MAX) if ((unsigned int)mode >= MPOL_MAX)
return -EINVAL; return -EINVAL;
if ((flags & MPOL_F_STATIC_NODES) && (flags & MPOL_F_RELATIVE_NODES))
return -EINVAL;
err = get_nodes(&nodes, nmask, maxnode); err = get_nodes(&nodes, nmask, maxnode);
if (err) if (err)
return err; return err;
...@@ -1745,10 +1763,12 @@ static void mpol_rebind_policy(struct mempolicy *pol, ...@@ -1745,10 +1763,12 @@ static void mpol_rebind_policy(struct mempolicy *pol,
{ {
nodemask_t tmp; nodemask_t tmp;
int static_nodes; int static_nodes;
int relative_nodes;
if (!pol) if (!pol)
return; return;
static_nodes = pol->flags & MPOL_F_STATIC_NODES; static_nodes = pol->flags & MPOL_F_STATIC_NODES;
relative_nodes = pol->flags & MPOL_F_RELATIVE_NODES;
if (!mpol_store_user_nodemask(pol) && if (!mpol_store_user_nodemask(pol) &&
nodes_equal(pol->w.cpuset_mems_allowed, *newmask)) nodes_equal(pol->w.cpuset_mems_allowed, *newmask))
return; return;
...@@ -1761,6 +1781,9 @@ static void mpol_rebind_policy(struct mempolicy *pol, ...@@ -1761,6 +1781,9 @@ static void mpol_rebind_policy(struct mempolicy *pol,
case MPOL_INTERLEAVE: case MPOL_INTERLEAVE:
if (static_nodes) if (static_nodes)
nodes_and(tmp, pol->w.user_nodemask, *newmask); nodes_and(tmp, pol->w.user_nodemask, *newmask);
else if (relative_nodes)
mpol_relative_nodemask(&tmp, &pol->w.user_nodemask,
newmask);
else { else {
nodes_remap(tmp, pol->v.nodes, nodes_remap(tmp, pol->v.nodes,
pol->w.cpuset_mems_allowed, *newmask); pol->w.cpuset_mems_allowed, *newmask);
...@@ -1783,6 +1806,10 @@ static void mpol_rebind_policy(struct mempolicy *pol, ...@@ -1783,6 +1806,10 @@ static void mpol_rebind_policy(struct mempolicy *pol,
pol->v.preferred_node = node; pol->v.preferred_node = node;
else else
pol->v.preferred_node = -1; pol->v.preferred_node = -1;
} else if (relative_nodes) {
mpol_relative_nodemask(&tmp, &pol->w.user_nodemask,
newmask);
pol->v.preferred_node = first_node(tmp);
} else { } else {
pol->v.preferred_node = node_remap(pol->v.preferred_node, pol->v.preferred_node = node_remap(pol->v.preferred_node,
pol->w.cpuset_mems_allowed, *newmask); pol->w.cpuset_mems_allowed, *newmask);
...@@ -1878,6 +1905,8 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol) ...@@ -1878,6 +1905,8 @@ static inline int mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
if (flags & MPOL_F_STATIC_NODES) if (flags & MPOL_F_STATIC_NODES)
p += sprintf(p, "%sstatic", need_bar++ ? "|" : ""); p += sprintf(p, "%sstatic", need_bar++ ? "|" : "");
if (flags & MPOL_F_RELATIVE_NODES)
p += sprintf(p, "%srelative", need_bar++ ? "|" : "");
} }
if (!nodes_empty(nodes)) { if (!nodes_empty(nodes)) {
......
...@@ -1128,6 +1128,12 @@ static int shmem_parse_mpol(char *value, unsigned short *policy, ...@@ -1128,6 +1128,12 @@ static int shmem_parse_mpol(char *value, unsigned short *policy,
if (flags) { if (flags) {
if (!strcmp(flags, "static")) if (!strcmp(flags, "static"))
*mode_flags |= MPOL_F_STATIC_NODES; *mode_flags |= MPOL_F_STATIC_NODES;
if (!strcmp(flags, "relative"))
*mode_flags |= MPOL_F_RELATIVE_NODES;
if ((*mode_flags & MPOL_F_STATIC_NODES) &&
(*mode_flags & MPOL_F_RELATIVE_NODES))
err = 1;
} }
out: out:
/* Restore string for error message */ /* Restore string for error message */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment