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 */
                return ERR_PTR(-ENOMEM);
        atomic_set(&policy->refcnt, 1);
        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) {
        case MPOL_INTERLEAVE:
                if (nodes_empty(*nodes) || nodes_empty(cpuset_context_nmask))
        mode &= ~MPOL_MODE_FLAGS;
        if (mode >= MPOL_MAX)
                return -EINVAL;
+       if ((mode_flags & MPOL_F_STATIC_NODES) &&
+           (mode_flags & MPOL_F_RELATIVE_NODES))
+               return -EINVAL;
        err = get_nodes(&nodes, nmask, maxnode);
        if (err)
                return err;
        mode &= ~MPOL_MODE_FLAGS;
        if ((unsigned int)mode >= MPOL_MAX)
                return -EINVAL;
+       if ((flags & MPOL_F_STATIC_NODES) && (flags & MPOL_F_RELATIVE_NODES))
+               return -EINVAL;
        err = get_nodes(&nodes, nmask, maxnode);
        if (err)
                return err;
 {
        nodemask_t tmp;
        int static_nodes;
+       int relative_nodes;
 
        if (!pol)
                return;
        static_nodes = pol->flags & MPOL_F_STATIC_NODES;
+       relative_nodes = pol->flags & MPOL_F_RELATIVE_NODES;
        if (!mpol_store_user_nodemask(pol) &&
            nodes_equal(pol->w.cpuset_mems_allowed, *newmask))
                return;
        case MPOL_INTERLEAVE:
                if (static_nodes)
                        nodes_and(tmp, pol->w.user_nodemask, *newmask);
+               else if (relative_nodes)
+                       mpol_relative_nodemask(&tmp, &pol->w.user_nodemask,
+                                              newmask);
                else {
                        nodes_remap(tmp, pol->v.nodes,
                                    pol->w.cpuset_mems_allowed, *newmask);
                                pol->v.preferred_node = node;
                        else
                                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 {
                        pol->v.preferred_node = node_remap(pol->v.preferred_node,
                                        pol->w.cpuset_mems_allowed, *newmask);
 
                if (flags & MPOL_F_STATIC_NODES)
                        p += sprintf(p, "%sstatic", need_bar++ ? "|" : "");
+               if (flags & MPOL_F_RELATIVE_NODES)
+                       p += sprintf(p, "%srelative", need_bar++ ? "|" : "");
        }
 
        if (!nodes_empty(nodes)) {