|
@@ -416,8 +416,8 @@ static bool memcg_kmem_test_and_clear_dead(struct mem_cgroup *memcg)
|
|
|
|
|
|
/* Stuffs for move charges at task migration. */
|
|
|
/*
|
|
|
- * Types of charges to be moved. "move_charge_at_immitgrate" is treated as a
|
|
|
- * left-shifted bitmap of these types.
|
|
|
+ * Types of charges to be moved. "move_charge_at_immitgrate" and
|
|
|
+ * "immigrate_flags" are treated as a left-shifted bitmap of these types.
|
|
|
*/
|
|
|
enum move_type {
|
|
|
MOVE_CHARGE_TYPE_ANON, /* private anonymous page and swap of it */
|
|
@@ -430,6 +430,7 @@ static struct move_charge_struct {
|
|
|
spinlock_t lock; /* for from, to */
|
|
|
struct mem_cgroup *from;
|
|
|
struct mem_cgroup *to;
|
|
|
+ unsigned long immigrate_flags;
|
|
|
unsigned long precharge;
|
|
|
unsigned long moved_charge;
|
|
|
unsigned long moved_swap;
|
|
@@ -442,14 +443,12 @@ static struct move_charge_struct {
|
|
|
|
|
|
static bool move_anon(void)
|
|
|
{
|
|
|
- return test_bit(MOVE_CHARGE_TYPE_ANON,
|
|
|
- &mc.to->move_charge_at_immigrate);
|
|
|
+ return test_bit(MOVE_CHARGE_TYPE_ANON, &mc.immigrate_flags);
|
|
|
}
|
|
|
|
|
|
static bool move_file(void)
|
|
|
{
|
|
|
- return test_bit(MOVE_CHARGE_TYPE_FILE,
|
|
|
- &mc.to->move_charge_at_immigrate);
|
|
|
+ return test_bit(MOVE_CHARGE_TYPE_FILE, &mc.immigrate_flags);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -5193,15 +5192,14 @@ static int mem_cgroup_move_charge_write(struct cgroup *cgrp,
|
|
|
|
|
|
if (val >= (1 << NR_MOVE_TYPE))
|
|
|
return -EINVAL;
|
|
|
+
|
|
|
/*
|
|
|
- * We check this value several times in both in can_attach() and
|
|
|
- * attach(), so we need cgroup lock to prevent this value from being
|
|
|
- * inconsistent.
|
|
|
+ * No kind of locking is needed in here, because ->can_attach() will
|
|
|
+ * check this value once in the beginning of the process, and then carry
|
|
|
+ * on with stale data. This means that changes to this value will only
|
|
|
+ * affect task migrations starting after the change.
|
|
|
*/
|
|
|
- cgroup_lock();
|
|
|
memcg->move_charge_at_immigrate = val;
|
|
|
- cgroup_unlock();
|
|
|
-
|
|
|
return 0;
|
|
|
}
|
|
|
#else
|
|
@@ -6559,8 +6557,15 @@ static int mem_cgroup_can_attach(struct cgroup *cgroup,
|
|
|
struct task_struct *p = cgroup_taskset_first(tset);
|
|
|
int ret = 0;
|
|
|
struct mem_cgroup *memcg = mem_cgroup_from_cont(cgroup);
|
|
|
+ unsigned long move_charge_at_immigrate;
|
|
|
|
|
|
- if (memcg->move_charge_at_immigrate) {
|
|
|
+ /*
|
|
|
+ * We are now commited to this value whatever it is. Changes in this
|
|
|
+ * tunable will only affect upcoming migrations, not the current one.
|
|
|
+ * So we need to save it, and keep it going.
|
|
|
+ */
|
|
|
+ move_charge_at_immigrate = memcg->move_charge_at_immigrate;
|
|
|
+ if (move_charge_at_immigrate) {
|
|
|
struct mm_struct *mm;
|
|
|
struct mem_cgroup *from = mem_cgroup_from_task(p);
|
|
|
|
|
@@ -6580,6 +6585,7 @@ static int mem_cgroup_can_attach(struct cgroup *cgroup,
|
|
|
spin_lock(&mc.lock);
|
|
|
mc.from = from;
|
|
|
mc.to = memcg;
|
|
|
+ mc.immigrate_flags = move_charge_at_immigrate;
|
|
|
spin_unlock(&mc.lock);
|
|
|
/* We set mc.moving_task later */
|
|
|
|