/* * Update CGRP_FROZEN of cgroup.flag * Return true if flags is updated; false if flags has no change
*/ staticbool cgroup_update_frozen_flag(struct cgroup *cgrp, bool frozen)
{
lockdep_assert_held(&css_set_lock);
/* Already there? */ if (test_bit(CGRP_FROZEN, &cgrp->flags) == frozen) returnfalse;
if (frozen)
set_bit(CGRP_FROZEN, &cgrp->flags); else
clear_bit(CGRP_FROZEN, &cgrp->flags);
/* * Propagate the cgroup frozen state upwards by the cgroup tree.
*/ staticvoid cgroup_propagate_frozen(struct cgroup *cgrp, bool frozen)
{ int desc = 1;
/* * If the new state is frozen, some freezing ancestor cgroups may change * their state too, depending on if all their descendants are frozen. * * Otherwise, all ancestor cgroups are forced into the non-frozen state.
*/ while ((cgrp = cgroup_parent(cgrp))) { if (frozen) {
cgrp->freezer.nr_frozen_descendants += desc; if (!test_bit(CGRP_FREEZE, &cgrp->flags) ||
(cgrp->freezer.nr_frozen_descendants !=
cgrp->nr_descendants)) continue;
} else {
cgrp->freezer.nr_frozen_descendants -= desc;
}
if (cgroup_update_frozen_flag(cgrp, frozen))
desc++;
}
}
/* * Revisit the cgroup frozen state. * Checks if the cgroup is really frozen and perform all state transitions.
*/ void cgroup_update_frozen(struct cgroup *cgrp)
{ bool frozen;
/* * If the cgroup has to be frozen (CGRP_FREEZE bit set), * and all tasks are frozen and/or stopped, let's consider * the cgroup frozen. Otherwise it's not frozen.
*/
frozen = test_bit(CGRP_FREEZE, &cgrp->flags) &&
cgrp->freezer.nr_frozen_tasks == __cgroup_task_count(cgrp);
/* If flags is updated, update the state of ancestor cgroups. */ if (cgroup_update_frozen_flag(cgrp, frozen))
cgroup_propagate_frozen(cgrp, frozen);
}
/* * Enter frozen/stopped state, if not yet there. Update cgroup's counters, * and revisit the state of the cgroup, if necessary.
*/ void cgroup_enter_frozen(void)
{ struct cgroup *cgrp;
/* * Conditionally leave frozen/stopped state. Update cgroup's counters, * and revisit the state of the cgroup, if necessary. * * If always_leave is not set, and the cgroup is freezing, * we're racing with the cgroup freezing. In this case, we don't * drop the frozen counter to avoid a transient switch to * the unfrozen state.
*/ void cgroup_leave_frozen(bool always_leave)
{ struct cgroup *cgrp;
/* * Freeze or unfreeze all tasks in the given cgroup.
*/ staticvoid cgroup_do_freeze(struct cgroup *cgrp, bool freeze)
{ struct css_task_iter it; struct task_struct *task;
lockdep_assert_held(&cgroup_mutex);
spin_lock_irq(&css_set_lock); if (freeze)
set_bit(CGRP_FREEZE, &cgrp->flags); else
clear_bit(CGRP_FREEZE, &cgrp->flags);
spin_unlock_irq(&css_set_lock);
if (freeze)
TRACE_CGROUP_PATH(freeze, cgrp); else
TRACE_CGROUP_PATH(unfreeze, cgrp);
/* * Cgroup state should be revisited here to cover empty leaf cgroups * and cgroups which descendants are already in the desired state.
*/
spin_lock_irq(&css_set_lock); if (cgrp->nr_descendants == cgrp->freezer.nr_frozen_descendants)
cgroup_update_frozen(cgrp);
spin_unlock_irq(&css_set_lock);
}
/* * Adjust the task state (freeze or unfreeze) and revisit the state of * source and destination cgroups.
*/ void cgroup_freezer_migrate_task(struct task_struct *task, struct cgroup *src, struct cgroup *dst)
{
lockdep_assert_held(&css_set_lock);
/* * Kernel threads are not supposed to be frozen at all.
*/ if (task->flags & PF_KTHREAD) return;
/* * It's not necessary to do changes if both of the src and dst cgroups * are not freezing and task is not frozen.
*/ if (!test_bit(CGRP_FREEZE, &src->flags) &&
!test_bit(CGRP_FREEZE, &dst->flags) &&
!task->frozen) return;
/* * Adjust counters of freezing and frozen tasks. * Note, that if the task is frozen, but the destination cgroup is not * frozen, we bump both counters to keep them balanced.
*/ if (task->frozen) {
cgroup_inc_frozen_cnt(dst);
cgroup_dec_frozen_cnt(src);
}
cgroup_update_frozen(dst);
cgroup_update_frozen(src);
/* * Force the task to the desired state.
*/
cgroup_freeze_task(task, test_bit(CGRP_FREEZE, &dst->flags));
}
/* * e_freeze is affected by parent's e_freeze and dst's freeze. * If old e_freeze eq new e_freeze, no change, its children * will not be affected. So do nothing and skip the subtree
*/
old_e = dsct->freezer.e_freeze;
parent = cgroup_parent(dsct);
dsct->freezer.e_freeze = (dsct->freezer.freeze ||
parent->freezer.e_freeze); if (dsct->freezer.e_freeze == old_e) {
css = css_rightmost_descendant(css); continue;
}
/* * Do change actual state: freeze or unfreeze.
*/
cgroup_do_freeze(dsct, freeze);
applied = true;
}
/* * Even if the actual state hasn't changed, let's notify a user. * The state can be enforced by an ancestor cgroup: the cgroup * can already be in the desired state or it can be locked in the * opposite state, so that the transition will never happen. * In both cases it's better to notify a user, that there is * nothing to wait for.
*/ if (!applied) {
TRACE_CGROUP_PATH(notify_frozen, cgrp,
test_bit(CGRP_FROZEN, &cgrp->flags));
cgroup_file_notify(&cgrp->events_file);
}
}
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.