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

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

  2. Docker基础技术:Linux CGroup

    前面,我们介绍了Linux Namespace,但是Namespace解决的问题主要是环境隔离的问题,这只是虚拟化中最最基础的一步,我们还需要解决对计算机资源使用上的隔离.也就是说,虽然你通过Name ...

  3. Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3.0 ARMv7)

    http://blog.chinaunix.net/uid-20543672-id-3157283.html Linux内核源码分析--内核启动之(3)Image内核启动(C语言部分)(Linux-3 ...

  4. linux内存源码分析 - 内存压缩(实现流程)

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ 概述 本文章最好结合linux内存管理源码分析 - 页框分配器与linux内存源码分析 -伙伴系统(初始化和申请 ...

  5. linux内存源码分析 - SLUB分配器概述

    本文为原创,转载请注明:http://www.cnblogs.com/tolimit/ SLUB和SLAB的区别 首先为什么要说slub分配器,内核里小内存分配一共有三种,SLAB/SLUB/SLOB ...

  6. Linux CGroup

    catalog . 引言 . Cgroup安装配置 . Cgroup使用方式 . CGroup的子系统 1. 引言 我们已经讨论了Linux下命名空间(Namespace)的基本知识,详情请参阅另一篇 ...

  7. Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7)【转】

    原文地址:Linux内核源码分析--内核启动之(6)Image内核启动(do_basic_setup函数)(Linux-3.0 ARMv7) 作者:tekkamanninja 转自:http://bl ...

  8. LINUX CGROUP总结

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

  9. Linux Cgroup 入门教程:cpuset

    这是 Cgroup 系列的第四篇,往期回顾: Linux Cgroup 入门教程:基本概念 Linux Cgroup 入门教程:CPU Linux Cgroup 入门教程:内存 通过上篇文章的学习,我 ...

随机推荐

  1. Keil> 编译器特有的功能 > 关键字和运算符 > __weak

    __weak 此关键字指示编译器弱导出符号. 可以将 __weak 关键字应用于函数和变量声明以及函数定义. 用法 函数和变量声明 对于声明,此存储类指定一个 extern 对象声明,即使不存在,也不 ...

  2. 调用webservice进行身份验证

    因为同事说在调用webservice的时候会弹出身份验证的窗口,直接调用会返回401,原因是站点部署的时候设置了身份验证(账号名称自己配置).因而在调用的时候需要加入身份验证的凭证. 至于如何获取身份 ...

  3. Sql常用语句(3)

    --显示sql server现有的所有数据库 exec sp_helpdb --查看数据表设置的约束 exec sp_helpconstraint SubjectType --update selec ...

  4. C# - 多线程 之 进程与线程

    并行~并发 并发 Concurrency,逻辑上的同时发生,一个处理器(在不同时刻或者说在同一时间间隔内)"同时"处理多个任务.宏观上是并发的,微观上是按排队等待.唤醒.执行的步骤 ...

  5. java单例模式的实现方式

    一.什么是单例模式 单例:保证一个类仅有一个实例,并提供一个访问它的全局访问点. 单例模式是一种常用的软件设计模式之一,其目的是保证整个应用中只存在类的唯一个实例. 比如我们在系统启动时,需要加载一些 ...

  6. CSS3 Flexbox轻松实现元素的水平居中和垂直居中

    CSS3 Flexbox轻松实现元素的水平居中和垂直居中 网上有很多关于Flex的教程,对于Flex的叫法也不一,有的叫Flexbox,有的叫Flex,其实这两种叫法都没有错,只是Flexbox旧一点 ...

  7. canvas贝塞尔曲线

    贝塞尔曲线 Bézier curve(贝塞尔曲线)是应用于二维图形应用程序的数学曲线. 曲线定义:起始点.终止点.控制点.通过调整控制点,贝塞尔曲线的形状会发生变化. 1962年,法国数学家Pierr ...

  8. json简单使用

    web工程中如何将大量数据从服务器端传送到浏览器一直是很重要的一个问题. 其中一个解决方法是在服务器端将将数据封装成json格式,然后传给前台.废话不多说,下面讲干货. 1.要用json必须下载一个库 ...

  9. React-Native坑:Invariant Violation:Application 项目名 has not been registered.

    前言 在学习一门新技术的你也许有跟我一样的困惑,照着书上或者视频上的敲了.但是就是有各种问题没有出来自己想要的结果.我会将自己在这个过程中遇到的坑都记录下来,不一定全覆盖,但希望这些文章可以解决你的问 ...

  10. SQL语句中的where 1=1 和0=1

    摘自:http://blog.sina.com.cn/s/blog_afe616ab0101camd.html SQL where 1=1 和0=1的作用 where 1=1; 这个条件始终为True ...