Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 198229
b: refs/heads/master
c: 708c1bb
h: refs/heads/master
i:
  198227: ec325b1
v: v3
  • Loading branch information
Miao Xie authored and Linus Torvalds committed May 25, 2010
1 parent 6ba4399 commit 9b6780d
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 25 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 971ada0f6659488c3f36aed4c6f7670ff5ce4368
refs/heads/master: 708c1bbc9d0c3e57f40501794d9b0eed29d10fce
15 changes: 12 additions & 3 deletions trunk/include/linux/mempolicy.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ enum {
MPOL_MAX, /* always last member of enum */
};

enum mpol_rebind_step {
MPOL_REBIND_ONCE, /* do rebind work at once(not by two step) */
MPOL_REBIND_STEP1, /* first step(set all the newly nodes) */
MPOL_REBIND_STEP2, /* second step(clean all the disallowed nodes)*/
MPOL_REBIND_NSTEP,
};

/* Flags for set_mempolicy */
#define MPOL_F_STATIC_NODES (1 << 15)
#define MPOL_F_RELATIVE_NODES (1 << 14)
Expand Down Expand Up @@ -51,6 +58,7 @@ enum {
*/
#define MPOL_F_SHARED (1 << 0) /* identify shared policies */
#define MPOL_F_LOCAL (1 << 1) /* preferred local allocation */
#define MPOL_F_REBINDING (1 << 2) /* identify policies in rebinding */

#ifdef __KERNEL__

Expand Down Expand Up @@ -193,8 +201,8 @@ struct mempolicy *mpol_shared_policy_lookup(struct shared_policy *sp,

extern void numa_default_policy(void);
extern void numa_policy_init(void);
extern void mpol_rebind_task(struct task_struct *tsk,
const nodemask_t *new);
extern void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
enum mpol_rebind_step step);
extern void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new);
extern void mpol_fix_fork_child_flag(struct task_struct *p);

Expand Down Expand Up @@ -308,7 +316,8 @@ static inline void numa_default_policy(void)
}

static inline void mpol_rebind_task(struct task_struct *tsk,
const nodemask_t *new)
const nodemask_t *new,
enum mpol_rebind_step step)
{
}

Expand Down
4 changes: 2 additions & 2 deletions trunk/kernel/cpuset.c
Original file line number Diff line number Diff line change
Expand Up @@ -953,8 +953,8 @@ static void cpuset_change_task_nodemask(struct task_struct *tsk,
nodemask_t *newmems)
{
nodes_or(tsk->mems_allowed, tsk->mems_allowed, *newmems);
mpol_rebind_task(tsk, &tsk->mems_allowed);
mpol_rebind_task(tsk, newmems);
mpol_rebind_task(tsk, &tsk->mems_allowed, MPOL_REBIND_ONCE);
mpol_rebind_task(tsk, newmems, MPOL_REBIND_ONCE);
tsk->mems_allowed = *newmems;
}

Expand Down
124 changes: 105 additions & 19 deletions trunk/mm/mempolicy.c
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,22 @@ struct mempolicy default_policy = {

static const struct mempolicy_operations {
int (*create)(struct mempolicy *pol, const nodemask_t *nodes);
void (*rebind)(struct mempolicy *pol, const nodemask_t *nodes);
/*
* If read-side task has no lock to protect task->mempolicy, write-side
* task will rebind the task->mempolicy by two step. The first step is
* setting all the newly nodes, and the second step is cleaning all the
* disallowed nodes. In this way, we can avoid finding no node to alloc
* page.
* If we have a lock to protect task->mempolicy in read-side, we do
* rebind directly.
*
* step:
* MPOL_REBIND_ONCE - do rebind work at once
* MPOL_REBIND_STEP1 - set all the newly nodes
* MPOL_REBIND_STEP2 - clean all the disallowed nodes
*/
void (*rebind)(struct mempolicy *pol, const nodemask_t *nodes,
enum mpol_rebind_step step);
} mpol_ops[MPOL_MAX];

/* Check that the nodemask contains at least one populated zone */
Expand Down Expand Up @@ -274,12 +289,19 @@ void __mpol_put(struct mempolicy *p)
kmem_cache_free(policy_cache, p);
}

static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes)
static void mpol_rebind_default(struct mempolicy *pol, const nodemask_t *nodes,
enum mpol_rebind_step step)
{
}

static void mpol_rebind_nodemask(struct mempolicy *pol,
const nodemask_t *nodes)
/*
* step:
* MPOL_REBIND_ONCE - do rebind work at once
* MPOL_REBIND_STEP1 - set all the newly nodes
* MPOL_REBIND_STEP2 - clean all the disallowed nodes
*/
static void mpol_rebind_nodemask(struct mempolicy *pol, const nodemask_t *nodes,
enum mpol_rebind_step step)
{
nodemask_t tmp;

Expand All @@ -288,12 +310,31 @@ static void mpol_rebind_nodemask(struct mempolicy *pol,
else if (pol->flags & MPOL_F_RELATIVE_NODES)
mpol_relative_nodemask(&tmp, &pol->w.user_nodemask, nodes);
else {
nodes_remap(tmp, pol->v.nodes, pol->w.cpuset_mems_allowed,
*nodes);
pol->w.cpuset_mems_allowed = *nodes;
/*
* if step == 1, we use ->w.cpuset_mems_allowed to cache the
* result
*/
if (step == MPOL_REBIND_ONCE || step == MPOL_REBIND_STEP1) {
nodes_remap(tmp, pol->v.nodes,
pol->w.cpuset_mems_allowed, *nodes);
pol->w.cpuset_mems_allowed = step ? tmp : *nodes;
} else if (step == MPOL_REBIND_STEP2) {
tmp = pol->w.cpuset_mems_allowed;
pol->w.cpuset_mems_allowed = *nodes;
} else
BUG();
}

pol->v.nodes = tmp;
if (nodes_empty(tmp))
tmp = *nodes;

if (step == MPOL_REBIND_STEP1)
nodes_or(pol->v.nodes, pol->v.nodes, tmp);
else if (step == MPOL_REBIND_ONCE || step == MPOL_REBIND_STEP2)
pol->v.nodes = tmp;
else
BUG();

if (!node_isset(current->il_next, tmp)) {
current->il_next = next_node(current->il_next, tmp);
if (current->il_next >= MAX_NUMNODES)
Expand All @@ -304,7 +345,8 @@ static void mpol_rebind_nodemask(struct mempolicy *pol,
}

static void mpol_rebind_preferred(struct mempolicy *pol,
const nodemask_t *nodes)
const nodemask_t *nodes,
enum mpol_rebind_step step)
{
nodemask_t tmp;

Expand All @@ -327,16 +369,45 @@ static void mpol_rebind_preferred(struct mempolicy *pol,
}
}

/* Migrate a policy to a different set of nodes */
static void mpol_rebind_policy(struct mempolicy *pol,
const nodemask_t *newmask)
/*
* mpol_rebind_policy - Migrate a policy to a different set of nodes
*
* If read-side task has no lock to protect task->mempolicy, write-side
* task will rebind the task->mempolicy by two step. The first step is
* setting all the newly nodes, and the second step is cleaning all the
* disallowed nodes. In this way, we can avoid finding no node to alloc
* page.
* If we have a lock to protect task->mempolicy in read-side, we do
* rebind directly.
*
* step:
* MPOL_REBIND_ONCE - do rebind work at once
* MPOL_REBIND_STEP1 - set all the newly nodes
* MPOL_REBIND_STEP2 - clean all the disallowed nodes
*/
static void mpol_rebind_policy(struct mempolicy *pol, const nodemask_t *newmask,
enum mpol_rebind_step step)
{
if (!pol)
return;
if (!mpol_store_user_nodemask(pol) &&
if (!mpol_store_user_nodemask(pol) && step == 0 &&
nodes_equal(pol->w.cpuset_mems_allowed, *newmask))
return;
mpol_ops[pol->mode].rebind(pol, newmask);

if (step == MPOL_REBIND_STEP1 && (pol->flags & MPOL_F_REBINDING))
return;

if (step == MPOL_REBIND_STEP2 && !(pol->flags & MPOL_F_REBINDING))
BUG();

if (step == MPOL_REBIND_STEP1)
pol->flags |= MPOL_F_REBINDING;
else if (step == MPOL_REBIND_STEP2)
pol->flags &= ~MPOL_F_REBINDING;
else if (step >= MPOL_REBIND_NSTEP)
BUG();

mpol_ops[pol->mode].rebind(pol, newmask, step);
}

/*
Expand All @@ -346,9 +417,10 @@ static void mpol_rebind_policy(struct mempolicy *pol,
* Called with task's alloc_lock held.
*/

void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new)
void mpol_rebind_task(struct task_struct *tsk, const nodemask_t *new,
enum mpol_rebind_step step)
{
mpol_rebind_policy(tsk->mempolicy, new);
mpol_rebind_policy(tsk->mempolicy, new, step);
}

/*
Expand All @@ -363,7 +435,7 @@ void mpol_rebind_mm(struct mm_struct *mm, nodemask_t *new)

down_write(&mm->mmap_sem);
for (vma = mm->mmap; vma; vma = vma->vm_next)
mpol_rebind_policy(vma->vm_policy, new);
mpol_rebind_policy(vma->vm_policy, new, MPOL_REBIND_ONCE);
up_write(&mm->mmap_sem);
}

Expand Down Expand Up @@ -1745,6 +1817,9 @@ EXPORT_SYMBOL(alloc_pages_current);
* 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().
*
* current's mempolicy may be rebinded by the other task(the task that changes
* cpuset's mems), so we needn't do rebind work for current task.
*/

/* Slow path of a mempolicy duplicate */
Expand All @@ -1754,13 +1829,24 @@ struct mempolicy *__mpol_dup(struct mempolicy *old)

if (!new)
return ERR_PTR(-ENOMEM);

/* task's mempolicy is protected by alloc_lock */
if (old == current->mempolicy) {
task_lock(current);
*new = *old;
task_unlock(current);
} else
*new = *old;

rcu_read_lock();
if (current_cpuset_is_being_rebound()) {
nodemask_t mems = cpuset_mems_allowed(current);
mpol_rebind_policy(old, &mems);
if (new->flags & MPOL_F_REBINDING)
mpol_rebind_policy(new, &mems, MPOL_REBIND_STEP2);
else
mpol_rebind_policy(new, &mems, MPOL_REBIND_ONCE);
}
rcu_read_unlock();
*new = *old;
atomic_set(&new->refcnt, 1);
return new;
}
Expand Down

0 comments on commit 9b6780d

Please sign in to comment.