终于讲清楚了,Linux Cgroup机制以及其树形结构怎么创建的

目录

1.cgroup基础理论和数据结构

1.1 struct cgroup_subsys是什么

1.2 struct cgroup_subsys_state是什么,以及与strcut cgroup关系

1.3 struct cgroup是什么

1.4 cgroup和subsys_cgroup是什么关系

1.5 cgroup和mem_cgroup是怎么创建出来的

1.6 /sys/fs/cgroup/memcg/test1目录结构怎么知道对应哪个控制组?

1.7 怎么知道一个进程是属于哪个控制组?

2. 源码剖析

2.1 树形结构是怎么创建起来的

cgroup_create函数

2.2 怎么遍历cgroup树


了解Linux Cgroup机制的都清楚,cgroup机制最终是通过树形结构表示的,既然是树形结构,我们必须搞清楚这个树形结构是怎么创建起来的,以及在内核源码中是怎么表达这种树形结构的,我们是否非常清楚怎么遍历整个树,本文将基于Linux5.15源码分析cgroup树形结构的创建过程。

假设我们有如下层级结构:

/sys/fs/cgroup/memcg/app

/sys/fs/cgroup/memcg/app/test1

/sys/fs/cgroup/memcg/app/test2

app就是test1和test2的父节点,test1和test2是兄弟节点,我们按照这个例子具体展开分析。

1.cgroup基础理论和数据结构

第一个很容易想到的问题就是test1是一个控制组,那么这个控制组在内核是用什么数据结构表示呢?这个数据结构还要能够表达出树形结构;同时我们怎么知道这个控制组是一个memory,还是blkio,还是其他呢?这就要从内核控制组的源码开始入手,内核通过struct cgroup表示一个控制组。

注意:这里说的cgroup并不是我们经常看到的mem_cgroup这种,cgroup结构体代表的是一个通用的控制组概念,而mem_cgroup代表的是具体的某个控制,内核称为subsys cgroup:为什么叫子控制组,因为内核中包含非常多的子控制组,比如memory或者io等等,具体在内核include/linux/cgroup_subsys.h 


/* generate an array of cgroup subsystem pointers */
#define SUBSYS(_x) [_x ## _cgrp_id] = &_x ## _cgrp_subsys,
struct cgroup_subsys *cgroup_subsys[] = {
#include <linux/cgroup_subsys.h>
};
#undef SUBSYS

#if IS_ENABLED(CONFIG_CPUSETS)
SUBSYS(cpuset)
#endif

#if IS_ENABLED(CONFIG_CGROUP_SCHED)
SUBSYS(cpu)
#endif

#if IS_ENABLED(CONFIG_CGROUP_CPUACCT)
SUBSYS(cpuacct)
#endif

#if IS_ENABLED(CONFIG_BLK_CGROUP)
SUBSYS(io)
#endif

#if IS_ENABLED(CONFIG_MEMCG)
SUBSYS(memory)
#endif

#if IS_ENABLED(CONFIG_CGROUP_DEVICE)
SUBSYS(devices)
#endif

#if IS_ENABLED(CONFIG_CGROUP_FREEZER)
SUBSYS(freezer)
#endif

#if IS_ENABLED(CONFIG_CGROUP_NET_CLASSID)
SUBSYS(net_cls)
#endif

#if IS_ENABLED(CONFIG_CGROUP_PERF)
SUBSYS(perf_event)
#endif

#if IS_ENABLED(CONFIG_CGROUP_NET_PRIO)
SUBSYS(net_prio)
#endif

#if IS_ENABLED(CONFIG_CGROUP_HUGETLB)
SUBSYS(hugetlb)
#endif

#if IS_ENABLED(CONFIG_CGROUP_PIDS)
SUBSYS(pids)
#endif

#if IS_ENABLED(CONFIG_CGROUP_RDMA)
SUBSYS(rdma)
#endif

#if IS_ENABLED(CONFIG_CGROUP_MISC)
SUBSYS(misc)
#endif
1.1 struct cgroup_subsys是什么

通过上面的介绍我们知道linux内核定义类似memory,io,cpu等几种具体的子控制组,cgroup_subsys数据结构本质上其实不代表某个具体的控制组实体,而是控制组实体的操控的结构体,定义了具体控制实体的函数,比如创建一个子控制组实体mem_cgroup:

/*
 * Control Group subsystem type.
 * See Documentation/admin-guide/cgroup-v1/cgroups.rst for details
 */
struct cgroup_subsys {
	struct cgroup_subsys_state *(*css_alloc)(struct cgroup_subsys_state *parent_css);
	int (*css_online)(struct cgroup_subsys_state *css);
	void (*css_offline)(struct cgroup_subsys_state *css);
	void (*css_released)(struct cgroup_subsys_state *css);
	void (*css_free)(struct cgroup_subsys_state *css);
	void (*css_reset)(struct cgroup_subsys_state *css);
	void (*css_rstat_flush)(struct cgroup_subsys_state *css, int cpu);
	int (*css_extra_stat_show)(struct seq_file *seq,
				   struct cgroup_subsys_state *css);

	int (*can_attach)(struct cgroup_taskset *tset);
	void (*cancel_attach)(struct cgroup_taskset *tset);
	void (*attach)(struct cgroup_taskset *tset);
	void (*post_attach)(void);
	int (*can_fork)(struct task_struct *task,
			struct css_set *cset);
	void (*cancel_fork)(struct task_struct *task, struct css_set *cset);
	void (*fork)(struct task_struct *task);
	void (*exit)(struct task_struct *task);
	void (*release)(struct task_struct *task);
    ...
}
1.2 struct cgroup_subsys_state是什么,以及与strcut cgroup关系

我们知道cgroup_subsys不代表具体的控制组实体,那么像mem_cgroup这种具体的子控制组是用什么数据结构表示:cgroup_subsys_state,这个类是所有具体子控制组对象的基类,就是说mem_cgroup的基类就是cgroup_subsys_state。注意:struct cgroup的struct cgroup_subsys_state是通过self字段表示,主要用来表示cgroup本身,而不是指向具体的subsys cgroup,具体的subsys cgroup是有struct cgroup的subsys[]数组存储的。

/*
 * Per-subsystem/per-cgroup state maintained by the system.  This is the
 * fundamental structural building block that controllers deal with.
 *
 * Fields marked with "PI:" are public and immutable and may be accessed
 * directly without synchronization.
 */
struct cgroup_subsys_state {
	/* PI: the cgroup that this css is attached to */
	struct cgroup *cgroup;

	/* PI: the cgroup subsystem that this css is attached to */
	struct cgroup_subsys *ss;

	/* reference count - access via css_[try]get() and css_put() */
	struct percpu_ref refcnt;

	/* siblings list anchored at the parent's ->children */
	struct list_head sibling;
	struct list_head children;

	/* flush target list anchored at cgrp->rstat_css_list */
	struct list_head rstat_css_node;

	/*
	 * PI: Subsys-unique ID.  0 is unused and root is always 1.  The
	 * matching css can be looked up using css_from_id().
	 */
	int id;

	unsigned int flags;

	/*
	 * Monotonically increasing unique serial number which defines a
	 * uniform order among all csses.  It's guaranteed that all
	 * ->children lists are in the ascending order of ->serial_nr and
	 * used to allow interrupting and resuming iterations.
	 */
	u64 serial_nr;

	/*
	 * Incremented by online self and children.  Used to guarantee that
	 * parents are not offlined before their children.
	 */
	atomic_t online_cnt;

	/* percpu_ref killing and RCU release */
	struct work_struct destroy_work;
	struct rcu_work destroy_rwork;

	/*
	 * PI: the parent css.	Placed here for cache proximity to following
	 * fields of the containing structure.
	 */
	struct cgroup_subsys_state *parent;
};

struct mem_cgroup {
	struct cgroup_subsys_state css;

	/* Private memcg ID. Used to ID objects that outlive the cgroup */
	struct mem_cgroup_id id;

	/* Accounted resources */
	struct page_counter memory;		/* Both v1 & v2 */

	union {
		struct page_counter swap;	/* v2 only */
		struct page_counter memsw;	/* v1 only */
	};

	/* Legacy consumer-oriented counters */
	struct page_counter kmem;		/* v1 only */
	struct page_counter tcpmem;		/* v1 only */

	/* Range enforcement for interrupt charges */
	struct work_struct high_work;

	unsigned long soft_limit;

	/* vmpressure notifications */
	struct vmpressure vmpressure;
    ...
}

 我们知道基类一般要做一些公共的操作,那么cgroup的树形结构正好放在cgroup_subsys_state数据结构中,因为树形结构是每一种控制组都需要的基础逻辑,而某个具体的subsys cgroup可以定义该类控制组差异化的定字段。

树形结构通过cgroup_subsys_state的几个重要的字段完成:parent,sibling,children

按照本文刚开始的例子说明:

parent:当前控制组的父控制组。如果当前控制组指test1,那么parent指向的就是app控制组

children:当前控制组的子控制组。如果当前控制组是app,那么children就包括了test1,test2

sibling:兄弟控制组,test1和test2就是兄弟控制组。

那么上面的三个字段构建树形的呢?children相当于一个list_head的head,那么sibling就是add到children的每个元素,如下:

1.3 struct cgroup是什么

通过上面的分析,我们已经知道cgroup是指控制组的概念,如果我们在

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值