Linux Kernel:4.4.17
CGroup的freezer子系統對於成批作業管理系統很有用,可以成批啟動/停止任務,以達到及其資源的調度。
freezer子系統也有助於針對運行一組任務設置檢查點。通過強制一組任務進入靜默狀態(quiescent state),freezer子系統可以獲得任務的鏡像。如果任務處於靜默狀態,其他任務就可以查看其proc或者讀取內核接口來獲取信息。通過收集必要信息到另一個node,然后在新node重啟任務,被檢查的任務可以在cluster中不同node之間遷移。
freezer是按等級划分的,凍結一個CGroup會凍結旗下的所有任務,並且包括他的所有子CGroup。每個freezer都有自己的狀態和從父集成的狀態。只有父子狀態都為THAWED的時候,當前的CGroup才是THAWED。
代碼解析
freezer的代碼位於kernel/cgroup_freezer.c中,執行freeze的具體函數位於kernel/freezer.c中。
freezer_cgrp_subsys結構體如下:
struct cgroup_subsys freezer_cgrp_subsys = { |
freezer子系統用來管理CGroup的結構體如下,只有一個參數state:
struct freezer { |
freezer的sysfs文件節點:
static struct cftype files[] = { |
繼續引申出freezer的狀態:
enum freezer_state_flags { /* mask for all FREEZING flags */ |
freezer.state
那么這些狀態和freezer.state的對應關系如何呢?
CGROUP_FREEZING FREEZING (凍結中)
CGROUP_FROZEN FROZEN(已凍結)
CGROUP_FREEZER_ONLINE THAWED(解凍狀態)
FREEZING不是一個常態,他是當前CGroup(或其子CGroup)一組任務將要轉換到FROZEN狀態的一種中間狀態。同時,如果當前或子CGroup有新任務加入,狀態會從FROZEN返回到FRZEEING,直到任務被凍結。
只有FROZEN和THAWED兩個狀態是寫有效的。如果寫入FROZEN,當CGroup沒有完全進入凍結狀態,包括其所有子CGroup都會進入FREEZING狀態。
如果寫入THAWED,當前的CGroup狀態就會變成THAWED。有一種例外是如果父CGroup還是被凍結,則不會變成THAWED。如果一個CGroup的有效狀態變成THAWED,因當前CGroup造成的凍結都會停止,並離開凍結狀態。
freezer.self_freezing
只讀。0表示狀態是THAWED,其他為1。
freezer.parent_freezing
只讀。0表示父CGroup沒有一個進入凍結狀態,其他為1。
freezer_read
此函數會從子CGroup向上遍歷所有CGroup,直到最后一個遍歷當前CGroup。
static int freezer_read(struct seq_file *m, void *v) mutex_lock(&freezer_mutex); /* update states bottom-up */ update_if_frozen(pos); 更新當前css的state,這樣確保當前css狀態是最新的。然后根css的狀態也是最新的。 rcu_read_lock(); rcu_read_unlock(); seq_puts(m, freezer_state_strs(css_freezer(css)->state)); |
freezer_write
static ssize_t freezer_write(struct kernfs_open_file *of, buf = strstrip(buf); if (strcmp(buf, freezer_state_strs(0)) == 0) 對應THAWED狀態 freezer_change_state(css_freezer(of_css(of)), freeze); 切換freezer狀態 |
freezer_change_state
static void freezer_change_state(struct freezer *freezer, bool freeze) /* if (!css_tryget_online(pos)) if (pos_f == freezer) 如果是根css則進入CGROUP_FREEZING_SELF rcu_read_lock(); |
freezer_apply_state
static void freezer_apply_state(struct freezer *freezer, bool freeze, if (!(freezer->state & CGROUP_FREEZER_ONLINE)) if (freeze) { 需要freeze,調用freeze_cgroup。凍結當前Cgroup下面所有task freezer->state &= ~state; if (!(freezer->state & CGROUP_FREEZING)) { 並且不是CGROUP_FREEZING狀態 |
freeze_task和__thaw_task
在kernel/freezer.c中定義了凍結和解凍task的執行函數freeze_task和__thaw_task。
在freezer的tasks中存放了所有的進程,遍歷所有進程執行freeze_task或者__thaw_task,即可凍結或解凍此freezer CGroup。
bool freeze_task(struct task_struct *p) /* spin_lock_irqsave(&freezer_lock, flags); if (!(p->flags & PF_KTHREAD)) spin_unlock_irqrestore(&freezer_lock, flags); |
void __thaw_task(struct task_struct *p) spin_lock_irqsave(&freezer_lock, flags); |
應用?
一個小實驗
為了直觀的理解,做一個小實驗。
源碼在:https://github.com/arnoldlu/common-use/blob/master/tools/loop.py
1.啟動一個占用率100%的進程:
2.top查看進程情況,CPU占用率100%:
3.新建一個freezer CGroup,並將7234進程寫入tasks:
4.將FROZEN寫入freezer.state:
5.top –p 7234查看進程情況,:
6.將THAWED寫入freezer.state之后:
7.可以看到7234的CPU占用率立馬又變成100%:
其他應用
比如LISA工具在測試的時候,為了排除干擾,只保留必須的進程,凍結其余進程:
參考資料
Freezer Subsystem:http://lxr.free-electrons.com/source/Documentation/cgroups/freezer-subsystem.txt?v=4.4