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 = {
    .css_alloc    = freezer_css_alloc,
    .css_online    = freezer_css_online,
    .css_offline    = freezer_css_offline,
    .css_free    = freezer_css_free,
    .attach        = freezer_attach,
    .fork        = freezer_fork,
    .legacy_cftypes    = files,
};

freezer子系统用来管理CGroup的结构体如下,只有一个参数state:

struct freezer {
    struct cgroup_subsys_state    css;
    unsigned int            state;
};

freezer的sysfs文件节点:

static struct cftype files[] = {
    {
        .name = "state",  子系统当前的状态
        .flags = CFTYPE_NOT_ON_ROOT,
        .seq_show = freezer_read,
        .write = freezer_write,
    },
    {
        .name = "self_freezing",  自身当前是否处于freezing状态
        .flags = CFTYPE_NOT_ON_ROOT,
        .read_u64 = freezer_self_freezing_read,
    },
    {
        .name = "parent_freezing",  父子系统是否处于freezing状态
        .flags = CFTYPE_NOT_ON_ROOT,
        .read_u64 = freezer_parent_freezing_read,
    },
    { }    /* terminate */
};

继续引申出freezer的状态:

enum freezer_state_flags {
    CGROUP_FREEZER_ONLINE    = (1 << 0), /* freezer is fully online */  freezer没有被冻结
    CGROUP_FREEZING_SELF    = (1 << 1), /* this freezer is freezing */  freezer自身正在冻结中
    CGROUP_FREEZING_PARENT    = (1 << 2), /* the parent freezer is freezing */  父freezer正在冻结中
    CGROUP_FROZEN        = (1 << 3), /* this and its descendants frozen */  自身和者子freezer已经被冻结

/* mask for all FREEZING flags */
    CGROUP_FREEZING        = CGROUP_FREEZING_SELF | CGROUP_FREEZING_PARENT,  自身或者父freezer处于冻结过程中
};

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)
{
    struct cgroup_subsys_state *css = seq_css(m), *pos;

mutex_lock(&freezer_mutex);
    rcu_read_lock();

/* update states bottom-up */
    css_for_each_descendant_post(pos, css) { 倒序遍历当前css的所有子css,最后一个遍历根css。
        if (!css_tryget_online(pos))
            continue;
        rcu_read_unlock();

update_if_frozen(pos);  更新当前css的state,这样确保当前css状态是最新的。然后根css的状态也是最新的。

rcu_read_lock();
        css_put(pos);
    }

rcu_read_unlock();
    mutex_unlock(&freezer_mutex);

seq_puts(m, freezer_state_strs(css_freezer(css)->state));
    seq_putc(m, '\n');
    return 0;
}

freezer_write

static ssize_t freezer_write(struct kernfs_open_file *of,
                 char *buf, size_t nbytes, loff_t off)
{
    bool freeze;

buf = strstrip(buf);

if (strcmp(buf, freezer_state_strs(0)) == 0)  对应THAWED状态
        freeze = false;
    else if (strcmp(buf, freezer_state_strs(CGROUP_FROZEN)) == 0)  对应FROZEN状态
        freeze = true;
    else
        return -EINVAL;

freezer_change_state(css_freezer(of_css(of)), freeze); 切换freezer状态
    return nbytes;
}

freezer_change_state

static void freezer_change_state(struct freezer *freezer, bool freeze)
{
    struct cgroup_subsys_state *pos;

/*
     * Update all its descendants in pre-order traversal.  Each
     * descendant will try to inherit its parent's FREEZING state as
     * CGROUP_FREEZING_PARENT.
     */
    mutex_lock(&freezer_mutex);
    rcu_read_lock();
    css_for_each_descendant_pre(pos, &freezer->css) {  这里和freezer_read是一个相反的过程,这是从跟css开始,逐级遍历所有css。
        struct freezer *pos_f = css_freezer(pos);
        struct freezer *parent = parent_freezer(pos_f);

if (!css_tryget_online(pos))
            continue;
        rcu_read_unlock();

if (pos_f == freezer)  如果是根css则进入CGROUP_FREEZING_SELF
            freezer_apply_state(pos_f, freeze,
                        CGROUP_FREEZING_SELF);
        else
            freezer_apply_state(pos_f,  其他css,表示是继承CGROUP_FREEZING_PARENT
                        parent->state & CGROUP_FREEZING,
                        CGROUP_FREEZING_PARENT);

rcu_read_lock();
        css_put(pos);
    }
    rcu_read_unlock();
    mutex_unlock(&freezer_mutex);
}

freezer_apply_state

static void freezer_apply_state(struct freezer *freezer, bool freeze,
                unsigned int state)
{
    /* also synchronizes against task migration, see freezer_attach() */
    lockdep_assert_held(&freezer_mutex);

if (!(freezer->state & CGROUP_FREEZER_ONLINE))
        return;

if (freeze) {  需要freeze,调用freeze_cgroup。冻结当前Cgroup下面所有task
        if (!(freezer->state & CGROUP_FREEZING))
            atomic_inc(&system_freezing_cnt);
        freezer->state |= state;
        freeze_cgroup(freezer);
    } else {  不需要freeze
        bool was_freezing = freezer->state & CGROUP_FREEZING;

freezer->state &= ~state;

if (!(freezer->state & CGROUP_FREEZING)) {  并且不是CGROUP_FREEZING状态
            if (was_freezing)
                atomic_dec(&system_freezing_cnt);
            freezer->state &= ~CGROUP_FROZEN;
            unfreeze_cgroup(freezer);  此CGroup下的所有tasks解冻
        }
    }
}

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)
{
    unsigned long flags;

/*
     * This check can race with freezer_do_not_count, but worst case that
     * will result in an extra wakeup being sent to the task.  It does not
     * race with freezer_count(), the barriers in freezer_count() and
     * freezer_should_skip() ensure that either freezer_count() sees
     * freezing == true in try_to_freeze() and freezes, or
     * freezer_should_skip() sees !PF_FREEZE_SKIP and freezes the task
     * normally.
     */
    if (freezer_should_skip(p))  在需要冻结的时候,是否跳过此进程
        return false;

spin_lock_irqsave(&freezer_lock, flags);
    if (!freezing(p) || frozen(p)) {  如果进程不是freezing,或已经被FROZEN,返回false
        spin_unlock_irqrestore(&freezer_lock, flags);
        return false;
    }

if (!(p->flags & PF_KTHREAD))
        fake_signal_wake_up(p);  不是内核线程,发送伪唤醒信号
    else
        wake_up_state(p, TASK_INTERRUPTIBLE);  设置进程唤醒条件为TASK_INTERRUPTIBLE

spin_unlock_irqrestore(&freezer_lock, flags);
    return true;
}

void __thaw_task(struct task_struct *p)
{
    unsigned long flags;

spin_lock_irqsave(&freezer_lock, flags);
    if (frozen(p))  如果已经被FROZEN,则简单的去唤醒
        wake_up_process(p);
    spin_unlock_irqrestore(&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

freezer子系统:http://www.cnblogs.com/lisperl/archive/2012/04/25/2469587.html

Linux CGroup之freezer分析与应用相关推荐

  1. Linux cgroup机制分析之cpuset subsystem

    ------------------------------------------ 本文系本站原创,欢迎转载! 转载请注明出处:http://ericxiao.cublog.cn/ -------- ...

  2. [转载] linux cgroup

    原文: http://coolshell.cn/articles/17049.html 感谢左耳朵耗子的精彩文章. 前面,我们介绍了Linux Namespace,但是Namespace解决的问题主要 ...

  3. linux cgroup、kubernetes limit

    linux cgroup.kubernetes limit 1.cgroups 简介 cgroups,其名称源自控制组群(control groups)的缩写,是内核的一个特性,用于限制.记录和隔离一 ...

  4. 一文给你解决linux内存源码分析- SLUB分配器概述(超详细)

    SLUB和SLAB的区别 首先为什么要说slub分配器,内核里小内存分配一共有三种,SLAB/SLUB/SLOB,slub分配器是slab分配器的进化版,而slob是一种精简的小内存分配算法,主要用于 ...

  5. Linux cgroup详解(理论与实例)

    1.导言: Linux系统每个进程都可以自由竞争系统资源,有时候会导致一些次要进程占用了系统某个资源(如CPU)的绝大部分,主要进程就不能很好地执行,从而影响系统效率,重则在linux资源耗尽时可能会 ...

  6. 慢慢欣赏linux cgroup

    创建cpu的cgroup的过程 root@cliffr zl]# cat /proc/cpuinfo processor : 0 vendor_id : GenuineIntel cpu family ...

  7. linux文件系统和日志分析!

    linux文件系统和日志分析 一.inode和block block(块) inode(索引节点) inode的元信息 简述文件的读取过程 inode的特殊作用 stat命令 二.硬链接与软链接 硬链 ...

  8. linux cgroup

    了解cgroup 1.cgroup描述 官方描述: DESCRIPTION Control groups, usually referred to as cgroups, are a Linux ke ...

  9. LINUX CGROUP总结

    简介: Linux CGroup全称Linux Control Group, 是Linux内核的一个功能,用来限制,控制与分离一个进程组群的资源(如CPU.内存.磁盘输入输出等).这个项目最早是由Go ...

最新文章

  1. Python 多进程、协程异步抓取英雄联盟皮肤并保存在本地
  2. Shell字符串截取——获取oracle group名字
  3. Scrapy框架的使用之Scrapy对接Selenium
  4. json.dumps()和json.loads()
  5. linux中怎样获得进程描述符,linux进程学习-进程描述符,控制块
  6. testmeshpro合批_TextMesh Pro Emoji Align With Text(表情和文字对齐)
  7. 04. 二维数组中的查找
  8. 源于零售业,如何赋能零售业?亚马逊云科技再发布四项新服务
  9. 隐马尔可夫模型三个问题的求解(一)
  10. 机械设计基础复习重点
  11. linux usb转串口驱动报错,USB转串口驱动编译出错
  12. Vb中 继承 多态的实现
  13. 遥感图像通用数据格式(BSQ\BIL\BIP)的理解
  14. 工作日报这样写 大老板也挑不出错
  15. 工业机器人视觉实训平台
  16. 淘宝x-sign, x-mini-wua, x-sgext, x-umt挂unidbg分析
  17. linux编译安装openssl3.0.7
  18. 痞子衡嵌入式:我被邀请做科锐国际旗下数科同道主办的技术沙龙嘉宾
  19. ABP实践(5)-abp前端vue框架之IView实现三级菜单(博友需要特此分享)
  20. Maven Archetype 开发

热门文章

  1. C++ 读取文件时报错“将一个无效参数传递给了将无效参数视为严重错误的函数”解决方法
  2. 苹果显示未找到服务器,苹果浏览器找不到服务器是怎么回事
  3. 使用U盘制做CentOS7.6安装盘并安装CentOS7.6系统
  4. JVM 垃圾收集器(Garbage Collection)
  5. poj2315足球游戏
  6. Linux 下 TC 命令原理及详解<一>
  7. python键盘控制_python如何直接控制鼠标键盘
  8. 23年 车辆检测+车距检测+行人检测+车辆识别+车距预测(附yolo v5最新版源码)
  9. 虚拟化技术(2)系统虚拟化
  10. 神州信息与北京市地方金融监督管理局、房山区人民政府签署战略合作