LXC1.0.7-- lxc-start 源码分析 04

来源:互联网 发布:淘宝为什么打压外贸店 编辑:程序博客网 时间:2024/05/22 15:12

lxc start部分的源码的大致工作流程已经熟悉,那么就要关注他的核心内容了,就是关于namespace 和 cgroup的内容了。

根据前面的分析已经知道,lxc根据一些配置会自动将flag设置成CLONE_NEWXXX,然后会通过cgroup init 来初始化一堆 cgroup。我们先来看一下。

首先通过cgroup_create 来创建 cgroup,前面介绍都是有个ops 指向函数指针,这里先假设我们用的cgfs,理论上应该和cgroupmanager是一样的方式,可能细节有区别而已。

那么顺理成章create指向cgfs_create,后面就直接说函数指针的位置了。

函数内部通过调用lxc_cgroupfs_create。那么就要从create a newcgroup

static struct cgroup_process_info *lxc_cgroupfs_create(const char*name, const char *path_pattern, struct cgroup_meta_data *meta_data, const char*sub_pattern)

 

char**cgroup_path_components = NULL;

    char **p = NULL;

    char *path_so_far = NULL;

    char **new_cgroup_paths =NULL;

    char **new_cgroup_paths_sub =NULL;

    struct cgroup_mount_point*mp;

    struct cgroup_hierarchy *h;

    struct cgroup_process_info*base_info = NULL;

    struct cgroup_process_info*info_ptr;

    int saved_errno;

    int r;

    unsigned suffix = 0;

    bool had_sub_pattern = false;

size_t i;

 

if (!is_valid_cgroup(name)){                                      //判断name 是否有效

        ERROR("Invalidcgroup name: '%s'", name);

        errno = EINVAL;

        return NULL;

}

 

if (!strstr(path_pattern,"%n")) {

        ERROR("Invalidcgroup path pattern: '%s'; contains no %%n for specifying container name",path_pattern);

        errno = EINVAL;

        return NULL;

}

根据privilege 和unprivilege  container的不同读取到proc 下面的pid的不同来确定不同的cgroup 信息。

base_info = (path_pattern[0]== '/') ?

       lxc_cgroup_process_info_get_init(meta_data) :

       lxc_cgroup_process_info_get_self(meta_data);

    if (!base_info)

        return NULL;

new_cgroup_paths =calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));

    if (!new_cgroup_paths)

        goto out_initial_error;

 

在自己机子上面,看到的cgroup:

gudh@lxc-D3F2-CM:~$ cat/proc/self/cgroup

11:name=systemd:/user/1004.user/5.session

10:hugetlb:/user/1004.user/5.session

9:perf_event:/user/1004.user/5.session

8:blkio:/user/1004.user/5.session

7:freezer:/user/1004.user/5.session

6:devices:/user/1004.user/5.session

5:memory:/user/1004.user/5.session

4:cpuacct:/user/1004.user/5.session

3:cpu:/user/1004.user/5.session

2:cpuset:/user/1004.user/5.session

gudh@lxc-D3F2-CM:~$ id

uid=1004(gudh)gid=1004(gudh) groups=1004(gudh),0(root),4(adm)

gudh@lxc-D3F2-CM:~$ cat/proc/1/cgroup

11:name=systemd:/

10:hugetlb:/

9:perf_event:/

8:blkio:/

7:freezer:/

6:devices:/

5:memory:/

4:cpuacct:/

3:cpu:/

2:cpuset:/

然后就是分配path的大小

    new_cgroup_paths_sub =calloc(meta_data->maximum_hierarchy + 1, sizeof(char *));

    if (!new_cgroup_paths_sub)

        goto out_initial_error;

 

查找可以挂载的点,然后创建。

/* find mount points we canuse */

    for (info_ptr = base_info; info_ptr;info_ptr = info_ptr->next) {

        h = info_ptr->hierarchy;

        mp = lxc_cgroup_find_mount_point(h,info_ptr->cgroup_path, true);

        if (!mp) {

            ERROR("Could not find writablemount point for cgroup hierarchy %d while trying to create cgroup.",h->index);

            goto out_initial_error;

        }

        info_ptr->designated_mount_point =mp;

 

        if (lxc_string_in_array("ns",(const char **)h->subsystems))

            continue;

        if (handle_cgroup_settings(mp,info_ptr->cgroup_path) < 0) {

            ERROR("Could not setclone_children to 1 for cpuset hierarchy in parent cgroup.");

            goto out_initial_error;

        }

    }

 

cgroup_path_components = lxc_normalize_path(path_pattern);

    if (!cgroup_path_components)

        goto out_initial_error;

 

然后根据normalize的path去创建他们。

/* go through the pathcomponents to see if we can create them */

    for (p = cgroup_path_components; *p ||(sub_pattern && !had_sub_pattern); p++) {

        /* we only want to create the samecomponent with -1, -2, etc.

         * if the component contains thecontainer name itself, otherwise

         * it's not an error if it alreadyexists

         */

        char *p_eff = *p ? *p : (char*)sub_pattern;

        bool contains_name = strstr(p_eff,"%n");

        char *current_component = NULL;

        char *current_subpath = NULL;

        char *current_entire_path = NULL;

        char *parts[3];

        size_t j = 0;

        i = 0;

 

       /* if we are processing the subpattern, we want to make sure

         * loop is ended the next time around

         */

        if (!*p) {

            had_sub_pattern = true;

            p--;

        }

 

然后就到find_name_on_this_level,这里面pattern 应该是/lxc/%n

 

        goto find_name_on_this_level;

find_name_on_this_level:

        /* determine name of the path componentwe should create */

        if (contains_name && suffix> 0) {

            char *buf = calloc(strlen(name) +32, 1);

            if (!buf)

               goto out_initial_error;

            snprintf(buf, strlen(name) + 32,"%s-%u", name, suffix);

            current_component =lxc_string_replace("%n", buf, p_eff);

            free(buf);

        } else {

            current_component = contains_name ?lxc_string_replace("%n", name, p_eff) : p_eff;

        }

        parts[0] = path_so_far;

        parts[1] = current_component;

        parts[2] = NULL;

        current_subpath = path_so_far ?lxc_string_join("/", (const char **)parts, false) :current_component;

紧接着创建相应的cgroup

for (i = 0, info_ptr =base_info; info_ptr; info_ptr = info_ptr->next, i++) {

            char *parts2[3];

 

            if(lxc_string_in_array("ns", (const char**)info_ptr->hierarchy->subsystems))

                continue;

            current_entire_path = NULL;

 

            parts2[0] =!strcmp(info_ptr->cgroup_path, "/") ? "" :info_ptr->cgroup_path;

            parts2[1] = current_subpath;

            parts2[2] = NULL;

            current_entire_path = lxc_string_join("/",(const char **)parts2, false);

 

            if (!*p) {

                /* we are processing thesubpath, so only update that one */

                free(new_cgroup_paths_sub[i]);

                new_cgroup_paths_sub[i] =strdup(current_entire_path);

                if (!new_cgroup_paths_sub[i])

                    goto cleanup_from_error;

            } else {

                /* remember which path was usedon this controller */

                free(new_cgroup_paths[i]);

                new_cgroup_paths[i] =strdup(current_entire_path);

                if (!new_cgroup_paths[i])

                    goto cleanup_from_error;

            }

 

            r =create_cgroup(info_ptr->designated_mount_point, current_entire_path);

这样就完成相应的代码设置。

对于pattern 为/lxc/%n 就分两次不同创建在相应的目录,这样cgroup subpath 也同时受到顶层/lxc 的控制,cgroup就成功创建了。

 

       然后就到cgroup_create_legacy最终调用lxc_cgroup_create_legacy

直接看注释

/*  

     * if cgroup is mounted at/cgroup and task is in cgroup /ab/, pid 2375 and

     * name is c1,

     * dir: /ab

     * fulloldpath =/cgroup/ab/2375

     * fullnewpath =/cgroup/ab/c1

     * newname = /ab/c1

     */

如果老名字为/sys/cgroup/cpu/lxc/android/2375

那么就改成/sys/cgroup/cpu/lxc/android/android?

加入cgroup一些创建file的 capability

 

cgroup_setup_limits 名字很明显设置限额 with_device是false

将在config中加入的device.allow 和device.deny 配置

手动设置的地方

 

然后就是cgfs_enter 最后到lxc_cgroupfs_enter

lxc_cgroup_find_mount_point 查找path下面的mount point

cgroup_to_absolute_path absolute path

lxc_write_to_file然后将pid写入到cgroup的absolutepath下面

这样就将pid 与cgroup成功绑定。

 

cgroup_chown chown的指针目前是NULL 暂时不分析

 

后面又来了一次 cgroup_setup_limits 这是with_device 是true

 

此时应该就完成了cgroup的相关设置

 

 

 

0 0