环球电气之家-午夜精彩视频-中国专业电气电子产品行业服务网站!

產品分類

當前位置: 首頁 > 工業電氣產品 > 端子與連接器 > 線路板連接器 > FFC連接器

類型分類:
科普知識
數據分類:
FFC連接器

一文詳細了解Cgroup

發布日期:2022-04-25 點擊率:101

作者簡介

偉林,中年碼農,從事過電信、手機、安全、芯片等行業,目前依舊從事Linux方向開發工作,個人愛好Linux相關知識分享,個人微博CSDN pwl999,歡迎大家關注!

Q學員問:我最近在看k8s對cgroup的管理部分,對于cfs對cgroup的調度有些疑惑。想搞明白cgroup里面的 period、quota是如何影響cfs的調度的

A偉林老師給出如下文章進行解答

1.Cgroup

1.1、cgroup概念

cgroup最基本的操作時我們可以使用以下命令創建一個cgroup文件夾:


復制mount-tcgroup-ocpu,cpusetcpu&cpuset/dev/cpu_cpuset_test

那么/dev/cpu_cpuset_test文件夾下就有一系列的cpu、cpuset cgroup相關的控制節點,tasks文件中默認加入了所有進程到這個cgroup中。可以繼續創建子文件夾,子文件夾繼承了父文件夾的結構形式,我們可以給子文件夾配置不同的參數,把一部分進程加入到子文件夾中的tasks文件當中,久可以實現分開的cgroup控制了。


e1a8bb3c-bf93-11ec-9e50-dac502259ad0.png


關于cgroup的結構有以下規則和規律:


  • 1、cgroup有很多subsys,我們平時接觸到的cpu、cpuset、cpuacct、memory、blkio都是cgroup_subsys;

  • 2、一個cgroup hierarchy,就是使用mount命令掛載的一個cgroup文件系統,hierarchy對應mount的根cgroup_root;

  • 3、一個hierarchy可以制定一個subsys,也可以制定多個subsys。可以是一個subsys,也可以是一個subsys組合;

  • 4、一個subsys只能被一個hierarchy引用一次,如果subsys已經被hierarchy引用,新hierarchy創建時不能引用這個subsys;唯一例外的是,我們可以創建和舊的hierarchy相同的subsys組合,這其實沒有創建新的hierarchy,只是簡單的符號鏈接;

  • 5、hierarchy對應一個文件系統,cgroup對應這個文件系統中的文件夾;subsys是基類,而css(cgroup_subsys_state)是cgroup引用subsys的實例;比如父目錄和子目錄分別是兩個cgroup,他們都要引用相同的subsys,但是他們需要不同的配置,所以會創建不同的css供cgroup->subsys[]來引用;

  • 6、一個任務對系統中不同的subsys一定會有引用,但是會引用到不同的hierarchy不同的cgroup即不同css當中;所以系統使用css_set結構來管理任務對css的引。如果任務引用的css組合相同,那他們開源使用相同的css_set;

  • 7、還有cgroup到task的反向引用,系統引入了cg_group_link結構。這部分可以參考Docker背后的內核知識——cgroups資源限制一文的描述,如下圖的結構關系:

cgroup數據結構之間的關系

e1bc5c46-bf93-11ec-9e50-dac502259ad0.png


1、subsys是一組基類(cpu、blkio),css(cgroup_subsys_state)是基類的實例化。


2、cgroup的一組css的集合。


3、hierarchy是多個cgoup的組合,它決定cgroup中能創建哪些subsys的css。hierarchy可以任意引用幾種subsys,但是一個subsys只能被一個hierarchy引用。如果一個hierarchy已經引用某個subsys,那么其他hierarchy就不能再引用這個subsys了。hierarchy對應cgroupfs_root數據結構。


4、一旦hierarchy確定了subsys,那么它下面的cgroup只能創建對應的css實例。一個subsys只能存在于某個hierarchy中,hierarchy下的多個cgroup可以創建這個subsys對應的多個css。


5、hierarchy、cgroup、css三者還使用文件系統來表示層次關系:hierarchy是文件系統掛載點,cgroup是文件夾,css是文件夾中的文件。css的值,以及兄弟和父子關系,表示了subsys資源配額的關系。


6、cgoup是為了劃分資源配額,配置的主體是進程task。每個task在每一類別的subsys上都有配額,所以每個task在每個類別的subsys上有一個唯一的css與之關聯。


7、進程和css是一對多(1 x N)的關系。而系統中的多個進程和多個css,是多對多(M x N)的關系。為了收斂這種多對多的關系,系統把所有css屬性都相同的一組進程放在一個css_set當中,把多個css放在一個cgroup當中,這樣還是多對多但是已經收斂(M/a x N/b)。css_set根據屬性組合,存入css_set_table當中。


8、css_set代表a個css屬性相同的進程,cgroup代表引用的b個subsys。多對多的關系從task vs css的(M x N),收斂到css_set vs cgroup的(M/a x N/b)。為了進一步簡化css_set和cgroup之間多對多關系的雙向查找,引入了cg_group_link數據結構:


e1d577b2-bf93-11ec-9e50-dac502259ad0.png


task_struct通過->cgroup成員找到css_set結構,css_set利用->tasks鏈表把所有css屬性相同的進程鏈接到一起。


dirdescript
css_set → cgroupcss_set的->cgrp_links鏈表上掛載了這組css相關cgroup對應的cg_cgroup_link,通過cg_cgroup_link->cgrp找到cgroup,再通過cgroup->subsys[]找到css。
cgroup → css_setcgroup的->cset_links鏈表上掛載了所有指向本cgoup的task對應的cg_cgroup_link,通過cg_cgroup_link->cset找到css_set,再通過css_set->tasks找到所有的task_struct。


9、還有一條task_struct → cgroup 的通路:


e1ef5e0c-bf93-11ec-9e50-dac502259ad0.png


路徑:task_struct->cgroup → css_set->subsys[] → cgroup_subsys_state->cgroup → cgroup


1.2、代碼分析


1、"/proc/cgroups"


subsys的鏈表:for_each_subsys(ss, i)

一個susbsys對應一個hierarchy:ss->root

一個hierarchy有多少個cgroup:ss->root->nr_cgrps












復制# ount -t cgroup -o freezer,debug bbb freezer_test/ 復制# cat /proc/cgroups復制#subsys_name    hierarchy       num_cgroups     enabled復制cpuset  4       6       1復制cpu     3       2       1復制cpuacct 1       147     1復制schedtune       2       3       1復制freezer 6       1       1復制debug   6       1       1






















復制static int proc_cgroupstats_show(struct seq_file *m, void *v)復制{復制  struct cgroup_subsys *ss;復制  int i;復制  seq_puts(m, "#subsys_name	hierarchy	num_cgroups	enabled
");復制  復制  mutex_lock(&cgroup_mutex);復制  for_each_subsys(ss, i)復制    seq_printf(m, "%s	%d	%d	%d
",復制         ss->legacy_name, ss->root->hierarchy_id,復制         atomic_read(&ss->root->nr_cgrps),復制         cgroup_ssid_enabled(i));復制  mutex_unlock(&cgroup_mutex);復制  return 0;復制}


2、"/proc/pid/cgroup"


每種subsys組合組成一個新的hierarchy,每個hierarchy在for_each_root(root)中創建一個root樹;

每個hierarchy頂層目錄和子目錄都是一個cgroup,一個hierarchy可以有多個cgroup,對應的subsys組合一樣,但是參數不一樣

cgroup_root自帶一個cgroup即root->cgrp,作為hierarchy的頂級目錄

一個cgroup對應多個subsys,使用cgroup_subsys_state類型(css)的cgroup->subsys[CGROUP_SUBSYS_COUNT]數組去和多個subsys鏈接;

一個cgroup自帶一個cgroup_subsys_state即cgrp->self,這個css的作用是css->parent指針,建立起cgroup之間的父子關系;

css一個公用結構,每個subsys使用自己的函數ss->css_alloc()分配自己的css結構,這個結構包含公用css + subsys私有數據;

每個subsys只能存在于一個組合(hierarchy)當中,如果一個subsys已經被一個組合引用,其他組合不能再引用這個subsys。唯一例外的是,我們可以重復mount相同的組合,但是這樣并沒有創建新組合,只是創建了一個鏈接指向舊組合;

進程對應每一種hierarchy,一定有一個cgroup對應。








復制# cat /proc/832/cgroup復制6:freezer,debug:/復制4:cpuset:/復制3:cpu:/復制2:schedtune:/復制1:cpuacct:/







































































復制int proc_cgroup_show(struct seq_file *m, struct pid_namespace *ns,復制         struct pid *pid, struct task_struct *tsk)復制{復制  char *buf, *path;復制  int retval;復制  struct cgroup_root *root;復制  retval = -ENOMEM;復制  buf = kmalloc(PATH_MAX, GFP_KERNEL);復制  if (!buf)復制    goto out;復制  mutex_lock(&cgroup_mutex);復制  spin_lock_bh(&css_set_lock);復制  for_each_root(root) {復制    struct cgroup_subsys *ss;復制    struct cgroup *cgrp;復制    int ssid, count = 0;復制    if (root == &cgrp_dfl_root && !cgrp_dfl_root_visible)復制      continue;復制    seq_printf(m, "%d:", root->hierarchy_id);復制    if (root != &cgrp_dfl_root)復制      for_each_subsys(ss, ssid)復制        if (root->subsys_mask & (1 << ssid))復制          seq_printf(m, "%s%s", count++ ? "," : "",復制               ss->legacy_name);復制    if (strlen(root->name))復制      seq_printf(m, "%sname=%s", count ? "," : "",復制           root->name);復制    seq_putc(m, ':');復制    cgrp = task_cgroup_from_root(tsk, root);復制    復制    if (cgroup_on_dfl(cgrp) || !(tsk->flags & PF_EXITING)) {復制      path = cgroup_path(cgrp, buf, PATH_MAX);復制      if (!path) {復制        retval = -ENAMETOOLONG;復制        goto out_unlock;復制      }復制    } else {復制      path = "/";復制    }復制    seq_puts(m, path);復制    if (cgroup_on_dfl(cgrp) && cgroup_is_dead(cgrp))復制      seq_puts(m, " (deleted)
");復制    else復制      seq_putc(m, '
');復制  }復制  retval = 0;復制out_unlock:復制  spin_unlock_bh(&css_set_lock);復制  mutex_unlock(&cgroup_mutex);復制  kfree(buf);復制out:復制  return retval;復制}


3、初始化




































































































































































































復制int __init cgroup_init_early(void)復制{復制  static struct cgroup_sb_opts __initdata opts;復制  struct cgroup_subsys *ss;復制  int i;復制    復制  init_cgroup_root(&cgrp_dfl_root, &opts);復制  cgrp_dfl_root.cgrp.self.flags |= CSS_NO_REF;復制  RCU_INIT_POINTER(init_task.cgroups, &init_css_set);復制    復制  for_each_subsys(ss, i) {復制    WARN(!ss->css_alloc || !ss->css_free || ss->name || ss->id,復制         "invalid cgroup_subsys %d:%s css_alloc=%p css_free=%p name:id=%d:%s
",復制         i, cgroup_subsys_name[i], ss->css_alloc, ss->css_free,復制         ss->id, ss->name);復制    WARN(strlen(cgroup_subsys_name[i]) > MAX_CGROUP_TYPE_NAMELEN,復制         "cgroup_subsys_name %s too long
", cgroup_subsys_name[i]);復制        復制    ss->id = i;復制    ss->name = cgroup_subsys_name[i];復制    if (!ss->legacy_name)復制      ss->legacy_name = cgroup_subsys_name[i];復制        復制    if (ss->early_init)復制      cgroup_init_subsys(ss, true);復制  }復制  return 0;復制}復制|→復制static void __init cgroup_init_subsys(struct cgroup_subsys *ss, bool early)復制{復制  struct cgroup_subsys_state *css;復制  printk(KERN_INFO "Initializing cgroup subsys %s
", ss->name);復制  mutex_lock(&cgroup_mutex);復制  idr_init(&ss->css_idr);復制  INIT_LIST_HEAD(&ss->cfts);復制  復制  ss->root = &cgrp_dfl_root;復制  復制  復制  css = ss->css_alloc(cgroup_css(&cgrp_dfl_root.cgrp, ss));復制  復制  BUG_ON(IS_ERR(css));復制  復制  復制  init_and_link_css(css, ss, &cgrp_dfl_root.cgrp);復制  復制  css->flags |= CSS_NO_REF;復制  if (early) {復制    復制    css->id = 1;復制  } else {復制    css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2, GFP_KERNEL);復制    BUG_ON(css->id < 0);復制  }復制  復制  復制  init_css_set.subsys[ss->id] = css;復制  have_fork_callback |= (bool)ss->fork << ss->id;復制  have_exit_callback |= (bool)ss->exit << ss->id;復制  have_free_callback |= (bool)ss->free << ss->id;復制  have_canfork_callback |= (bool)ss->can_fork << ss->id;復制  復制  BUG_ON(!list_empty(&init_task.tasks));復制    復制    復制  BUG_ON(online_css(css));復制  mutex_unlock(&cgroup_mutex);復制}復制int __init cgroup_init(void)復制{復制  struct cgroup_subsys *ss;復制  int ssid;復制  BUG_ON(percpu_init_rwsem(&cgroup_threadgroup_rwsem));復制  BUG_ON(cgroup_init_cftypes(NULL, cgroup_dfl_base_files));復制  BUG_ON(cgroup_init_cftypes(NULL, cgroup_legacy_base_files));復制  復制  rcu_sync_enter_start(&cgroup_threadgroup_rwsem.rss);復制  mutex_lock(&cgroup_mutex);復制  復制  hash_add(css_set_table, &init_css_set.hlist,復制     css_set_hash(init_css_set.subsys));復制  BUG_ON(cgroup_setup_root(&cgrp_dfl_root, 0));復制  mutex_unlock(&cgroup_mutex);復制  for_each_subsys(ss, ssid) {復制    if (ss->early_init) {復制      struct cgroup_subsys_state *css =復制        init_css_set.subsys[ss->id];復制      css->id = cgroup_idr_alloc(&ss->css_idr, css, 1, 2,復制               GFP_KERNEL);復制      BUG_ON(css->id < 0);復制    } else {復制      cgroup_init_subsys(ss, false);復制    }復制    list_add_tail(&init_css_set.e_cset_node[ssid],復制            &cgrp_dfl_root.cgrp.e_csets[ssid]);復制    復制    if (cgroup_disable_mask & (1 << ssid)) {復制      static_branch_disable(cgroup_subsys_enabled_key[ssid]);復制      printk(KERN_INFO "Disabling %s control group subsystem
",復制             ss->name);復制      continue;復制    }復制        復制    cgrp_dfl_root.subsys_mask |= 1 << ss->id;復制    if (!ss->dfl_cftypes)復制      cgrp_dfl_root_inhibit_ss_mask |= 1 << ss->id;復制        復制    if (ss->dfl_cftypes == ss->legacy_cftypes) {復制      WARN_ON(cgroup_add_cftypes(ss, ss->dfl_cftypes));復制    } else {復制      WARN_ON(cgroup_add_dfl_cftypes(ss, ss->dfl_cftypes));復制      WARN_ON(cgroup_add_legacy_cftypes(ss, ss->legacy_cftypes));復制    }復制    if (ss->bind)復制      ss->bind(init_css_set.subsys[ssid]);復制  }復制  復制  hash_del(&init_css_set.hlist);復制  hash_add(css_set_table, &init_css_set.hlist,復制     css_set_hash(init_css_set.subsys));復制  WARN_ON(sysfs_create_mount_point(fs_kobj, "cgroup"));復制  WARN_ON(register_filesystem(&cgroup_fs_type));復制  WARN_ON(!proc_create("cgroups", 0, NULL, &proc_cgroupstats_operations));復制  return 0;復制}


4、mount操作

創建新的root,因為ss默認都和默認root(cgrp_dfl_root)建立了關系,所以ss需要先解除舊的root鏈接,再和新root建立起鏈接。

































































































































































































































































































































































































復制static struct dentry *cgroup_mount(struct file_system_type *fs_type,復制       int flags, const char *unused_dev_name,復制       void *data)復制{復制  struct super_block *pinned_sb = NULL;復制  struct cgroup_subsys *ss;復制  struct cgroup_root *root;復制  struct cgroup_sb_opts opts;復制  struct dentry *dentry;復制  int ret;復制  int i;復制  bool new_sb;復制  復制  if (!use_task_css_set_links)復制    cgroup_enable_task_cg_lists();復制  mutex_lock(&cgroup_mutex);復制  復制  復制  ret = parse_cgroupfs_options(data, &opts);復制  if (ret)復制    goto out_unlock;復制  復制  if (opts.flags & CGRP_ROOT_SANE_BEHAVIOR) {復制    cgrp_dfl_root_visible = true;復制    root = &cgrp_dfl_root;復制    cgroup_get(&root->cgrp);復制    ret = 0;復制    goto out_unlock;復制  }復制  復制  復制  for_each_subsys(ss, i) {復制    if (!(opts.subsys_mask & (1 << i)) ||復制        ss->root == &cgrp_dfl_root)復制      continue;復制    if (!percpu_ref_tryget_live(&ss->root->cgrp.self.refcnt)) {復制      mutex_unlock(&cgroup_mutex);復制      msleep(10);復制      ret = restart_syscall();復制      goto out_free;復制    }復制    cgroup_put(&ss->root->cgrp);復制  }復制    復制  for_each_root(root) {復制    bool name_match = false;復制    if (root == &cgrp_dfl_root)復制      continue;復制    復制    if (opts.name) {復制      if (strcmp(opts.name, root->name))復制        continue;復制      name_match = true;復制    }復制    復制    if ((opts.subsys_mask || opts.none) &&復制        (opts.subsys_mask != root->subsys_mask)) {復制      if (!name_match)復制        continue;復制      ret = -EBUSY;復制      goto out_unlock;復制    }復制    if (root->flags ^ opts.flags)復制      pr_warn("new mount options do not match the existing superblock, will be ignored
");復制    復制    pinned_sb = kernfs_pin_sb(root->kf_root, NULL);復制    if (IS_ERR(pinned_sb) ||復制        !percpu_ref_tryget_live(&root->cgrp.self.refcnt)) {復制      mutex_unlock(&cgroup_mutex);復制      if (!IS_ERR_OR_NULL(pinned_sb))復制        deactivate_super(pinned_sb);復制      msleep(10);復制      ret = restart_syscall();復制      goto out_free;復制    }復制    ret = 0;復制    goto out_unlock;復制  }復制  復制  if (!opts.subsys_mask && !opts.none) {復制    ret = -EINVAL;復制    goto out_unlock;復制  }復制    復制  root = kzalloc(sizeof(*root), GFP_KERNEL);復制  if (!root) {復制    ret = -ENOMEM;復制    goto out_unlock;復制  }復制     復制  init_cgroup_root(root, &opts);復制    復制  ret = cgroup_setup_root(root, opts.subsys_mask);復制  if (ret)復制    cgroup_free_root(root);復制out_unlock:復制  mutex_unlock(&cgroup_mutex);復制out_free:復制  kfree(opts.release_agent);復制  kfree(opts.name);復制  if (ret)復制    return ERR_PTR(ret);復制    復制  dentry = kernfs_mount(fs_type, flags, root->kf_root,復制        CGROUP_SUPER_MAGIC, &new_sb);復制  if (IS_ERR(dentry) || !new_sb)復制    cgroup_put(&root->cgrp);復制  復制  if (pinned_sb) {復制    WARN_ON(new_sb);復制    deactivate_super(pinned_sb);復制  }復制  return dentry;復制}復制|→復制static int cgroup_setup_root(struct cgroup_root *root, unsigned long ss_mask)復制{復制  LIST_HEAD(tmp_links);復制  struct cgroup *root_cgrp = &root->cgrp;復制  struct css_set *cset;復制  int i, ret;復制  lockdep_assert_held(&cgroup_mutex);復制  ret = cgroup_idr_alloc(&root->cgroup_idr, root_cgrp, 1, 2, GFP_KERNEL);復制  if (ret < 0)復制    goto out;復制  root_cgrp->id = ret;復制  ret = percpu_ref_init(&root_cgrp->self.refcnt, css_release, 0,復制            GFP_KERNEL);復制  if (ret)復制    goto out;復制  復制  ret = allocate_cgrp_cset_links(css_set_count, &tmp_links);復制  if (ret)復制    goto cancel_ref;復制  ret = cgroup_init_root_id(root);復制  if (ret)復制    goto cancel_ref;復制    復制  root->kf_root = kernfs_create_root(&cgroup_kf_syscall_ops,復制             KERNFS_ROOT_CREATE_DEACTIVATED,復制             root_cgrp);復制  if (IS_ERR(root->kf_root)) {復制    ret = PTR_ERR(root->kf_root);復制    goto exit_root_id;復制  }復制  root_cgrp->kn = root->kf_root->kn;復制    復制  ret = css_populate_dir(&root_cgrp->self, NULL);復制  if (ret)復制    goto destroy_root;復制    復制  ret = rebind_subsystems(root, ss_mask);復制  if (ret)復制    goto destroy_root;復制  復制  list_add(&root->root_list, &cgroup_roots);復制  cgroup_root_count++;復制  復制  spin_lock_bh(&css_set_lock);復制  hash_for_each(css_set_table, i, cset, hlist) {復制    link_css_set(&tmp_links, cset, root_cgrp);復制    if (css_set_populated(cset))復制      cgroup_update_populated(root_cgrp, true);復制  }復制  spin_unlock_bh(&css_set_lock);復制  BUG_ON(!list_empty(&root_cgrp->self.children));復制  BUG_ON(atomic_read(&root->nr_cgrps) != 1);復制  kernfs_activate(root_cgrp->kn);復制  ret = 0;復制  goto out;復制destroy_root:復制  kernfs_destroy_root(root->kf_root);復制  root->kf_root = NULL;復制exit_root_id:復制  cgroup_exit_root_id(root);復制cancel_ref:復制  percpu_ref_exit(&root_cgrp->self.refcnt);復制out:復制  free_cgrp_cset_links(&tmp_links);復制  return ret;復制}復制||→復制static int rebind_subsystems(struct cgroup_root *dst_root,復制           unsigned long ss_mask)復制{復制  struct cgroup *dcgrp = &dst_root->cgrp;復制  struct cgroup_subsys *ss;復制  unsigned long tmp_ss_mask;復制  int ssid, i, ret;復制  lockdep_assert_held(&cgroup_mutex);復制  for_each_subsys_which(ss, ssid, &ss_mask) {復制    復制    if (css_next_child(NULL, cgroup_css(&ss->root->cgrp, ss)))復制      return -EBUSY;復制    復制    if (ss->root != &cgrp_dfl_root && dst_root != &cgrp_dfl_root)復制      return -EBUSY;復制  }復制  復制  tmp_ss_mask = ss_mask;復制  if (dst_root == &cgrp_dfl_root)復制    tmp_ss_mask &= ~cgrp_dfl_root_inhibit_ss_mask;復制  for_each_subsys_which(ss, ssid, &tmp_ss_mask) {復制    struct cgroup *scgrp = &ss->root->cgrp;復制    int tssid;復制        復制    ret = css_populate_dir(cgroup_css(scgrp, ss), dcgrp);復制    if (!ret)復制      continue;復制    復制    if (dst_root == &cgrp_dfl_root) {復制      if (cgrp_dfl_root_visible) {復制        pr_warn("failed to create files (%d) while rebinding 0x%lx to default root
",復制          ret, ss_mask);復制        pr_warn("you may retry by moving them to a different hierarchy and unbinding
");復制      }復制      continue;復制    }復制    for_each_subsys_which(ss, tssid, &tmp_ss_mask) {復制      if (tssid == ssid)復制        break;復制      css_clear_dir(cgroup_css(scgrp, ss), dcgrp);復制    }復制    return ret;復制  }復制  復制  for_each_subsys_which(ss, ssid, &ss_mask) {復制    struct cgroup_root *src_root = ss->root;復制    struct cgroup *scgrp = &src_root->cgrp;復制    struct cgroup_subsys_state *css = cgroup_css(scgrp, ss);復制    struct css_set *cset;復制    WARN_ON(!css || cgroup_css(dcgrp, ss));復制    css_clear_dir(css, NULL);復制        復制    RCU_INIT_POINTER(scgrp->subsys[ssid], NULL);復制    復制    復制    rcu_assign_pointer(dcgrp->subsys[ssid], css);復制    ss->root = dst_root;復制    css->cgroup = dcgrp;復制    spin_lock_bh(&css_set_lock);復制    hash_for_each(css_set_table, i, cset, hlist)復制      list_move_tail(&cset->e_cset_node[ss->id],復制               &dcgrp->e_csets[ss->id]);復制    spin_unlock_bh(&css_set_lock);復制    src_root->subsys_mask &= ~(1 << ssid);復制    scgrp->subtree_control &= ~(1 << ssid);復制    cgroup_refresh_child_subsys_mask(scgrp);復制    復制    dst_root->subsys_mask |= 1 << ssid;復制    if (dst_root == &cgrp_dfl_root) {復制      static_branch_enable(cgroup_subsys_on_dfl_key[ssid]);復制    } else {復制      dcgrp->subtree_control |= 1 << ssid;復制      cgroup_refresh_child_subsys_mask(dcgrp);復制      static_branch_disable(cgroup_subsys_on_dfl_key[ssid]);復制    }復制    if (ss->bind)復制      ss->bind(css);復制  }復制  kernfs_activate(dcgrp->kn);復制  return 0;復制}


5、文件操作

創建一個新文件夾,相當于創建一個新的cgroup。我們重點來看看新建文件夾的操作:














































































































































復制static struct kernfs_syscall_ops cgroup_kf_syscall_ops = {復制  .remount_fs    = cgroup_remount,復制  .show_options    = cgroup_show_options,復制  .mkdir      = cgroup_mkdir,復制  .rmdir      = cgroup_rmdir,復制  .rename      = cgroup_rename,復制};復制static int cgroup_mkdir(struct kernfs_node *parent_kn, const char *name,復制      umode_t mode)復制{復制  struct cgroup *parent, *cgrp;復制  struct cgroup_root *root;復制  struct cgroup_subsys *ss;復制  struct kernfs_node *kn;復制  int ssid, ret;復制  復制  if (strchr(name, '
'))復制    return -EINVAL;復制  parent = cgroup_kn_lock_live(parent_kn);復制  if (!parent)復制    return -ENODEV;復制  root = parent->root;復制  復制  復制  cgrp = kzalloc(sizeof(*cgrp), GFP_KERNEL);復制  if (!cgrp) {復制    ret = -ENOMEM;復制    goto out_unlock;復制  }復制  ret = percpu_ref_init(&cgrp->self.refcnt, css_release, 0, GFP_KERNEL);復制  if (ret)復制    goto out_free_cgrp;復制  復制  cgrp->id = cgroup_idr_alloc(&root->cgroup_idr, NULL, 2, 0, GFP_KERNEL);復制  if (cgrp->id < 0) {復制    ret = -ENOMEM;復制    goto out_cancel_ref;復制  }復制    復制  init_cgroup_housekeeping(cgrp);復制    復制  cgrp->self.parent = &parent->self;復制  cgrp->root = root;復制  if (notify_on_release(parent))復制    set_bit(CGRP_NOTIFY_ON_RELEASE, &cgrp->flags);復制  if (test_bit(CGRP_CPUSET_CLONE_CHILDREN, &parent->flags))復制    set_bit(CGRP_CPUSET_CLONE_CHILDREN, &cgrp->flags);復制  復制  復制  kn = kernfs_create_dir(parent->kn, name, mode, cgrp);復制  if (IS_ERR(kn)) {復制    ret = PTR_ERR(kn);復制    goto out_free_id;復制  }復制  cgrp->kn = kn;復制  復制  kernfs_get(kn);復制  cgrp->self.serial_nr = css_serial_nr_next++;復制  復制  list_add_tail_rcu(&cgrp->self.sibling, &cgroup_parent(cgrp)->self.children);復制  atomic_inc(&root->nr_cgrps);復制  cgroup_get(parent);復制  復制  cgroup_idr_replace(&root->cgroup_idr, cgrp, cgrp->id);復制  ret = cgroup_kn_set_ugid(kn);復制  if (ret)復制    goto out_destroy;復制    復制  ret = css_populate_dir(&cgrp->self, NULL);復制  if (ret)復制    goto out_destroy;復制  復制  復制  for_each_subsys(ss, ssid) {復制    if (parent->child_subsys_mask & (1 << ssid)) {復制      ret = create_css(cgrp, ss,復制           parent->subtree_control & (1 << ssid));復制      if (ret)復制        goto out_destroy;復制    }復制  }復制  復制  if (!cgroup_on_dfl(cgrp)) {復制    cgrp->subtree_control = parent->subtree_control;復制    cgroup_refresh_child_subsys_mask(cgrp);復制  }復制  kernfs_activate(kn);復制  ret = 0;復制  goto out_unlock;復制out_free_id:復制  cgroup_idr_remove(&root->cgroup_idr, cgrp->id);復制out_cancel_ref:復制  percpu_ref_exit(&cgrp->self.refcnt);復制out_free_cgrp:復制  kfree(cgrp);復制out_unlock:復制  cgroup_kn_unlock(parent_kn);復制  return ret;復制out_destroy:復制  cgroup_destroy_locked(cgrp);復制  goto out_unlock;復制}


cgroup默認文件,有一些重要的文件比如“tasks”,我們來看看具體的操作。






























































































































































復制static struct cftype cgroup_legacy_base_files[] = {復制  {復制    .name = "cgroup.procs",復制    .seq_start = cgroup_pidlist_start,復制    .seq_next = cgroup_pidlist_next,復制    .seq_stop = cgroup_pidlist_stop,復制    .seq_show = cgroup_pidlist_show,復制    .private = CGROUP_FILE_PROCS,復制    .write = cgroup_procs_write,復制  },復制  {復制    .name = "cgroup.clone_children",復制    .read_u64 = cgroup_clone_children_read,復制    .write_u64 = cgroup_clone_children_write,復制  },復制  {復制    .name = "cgroup.sane_behavior",復制    .flags = CFTYPE_ONLY_ON_ROOT,復制    .seq_show = cgroup_sane_behavior_show,復制  },復制  {復制    .name = "tasks",復制    .seq_start = cgroup_pidlist_start,復制    .seq_next = cgroup_pidlist_next,復制    .seq_stop = cgroup_pidlist_stop,復制    .seq_show = cgroup_pidlist_show,復制    .private = CGROUP_FILE_TASKS,復制    .write = cgroup_tasks_write,復制  },復制  {復制    .name = "notify_on_release",復制    .read_u64 = cgroup_read_notify_on_release,復制    .write_u64 = cgroup_write_notify_on_release,復制  },復制  {復制    .name = "release_agent",復制    .flags = CFTYPE_ONLY_ON_ROOT,復制    .seq_show = cgroup_release_agent_show,復制    .write = cgroup_release_agent_write,復制    .max_write_len = PATH_MAX - 1,復制  },復制  { }  復制}復制static ssize_t cgroup_tasks_write(struct kernfs_open_file *of,復制          char *buf, size_t nbytes, loff_t off)復制{復制  return __cgroup_procs_write(of, buf, nbytes, off, false);復制}復制|→復制static ssize_t __cgroup_procs_write(struct kernfs_open_file *of, char *buf,復制            size_t nbytes, loff_t off, bool threadgroup)復制{復制  struct task_struct *tsk;復制  struct cgroup_subsys *ss;復制  struct cgroup *cgrp;復制  pid_t pid;復制  int ssid, ret;復制  if (kstrtoint(strstrip(buf), 0, &pid) || pid < 0)復制    return -EINVAL;復制  cgrp = cgroup_kn_lock_live(of->kn);復制  if (!cgrp)復制    return -ENODEV;復制  percpu_down_write(&cgroup_threadgroup_rwsem);復制  rcu_read_lock();復制  if (pid) {復制    tsk = find_task_by_vpid(pid);復制    if (!tsk) {復制      ret = -ESRCH;復制      goto out_unlock_rcu;復制    }復制  } else {復制    tsk = current;復制  }復制  if (threadgroup)復制    tsk = tsk->group_leader;復制  復制  if (tsk == kthreadd_task || (tsk->flags & PF_NO_SETAFFINITY)) {復制    ret = -EINVAL;復制    goto out_unlock_rcu;復制  }復制  get_task_struct(tsk);復制  rcu_read_unlock();復制  ret = cgroup_procs_write_permission(tsk, cgrp, of);復制  if (!ret) {復制      復制    ret = cgroup_attach_task(cgrp, tsk, threadgroup);復制#if defined(CONFIG_CPUSETS) && !defined(CONFIG_MTK_ACAO)復制    if (cgrp->id != SS_TOP_GROUP_ID && cgrp->child_subsys_mask == CSS_CPUSET_MASK復制    && excl_task_count > 0) {復制      remove_set_exclusive_task(tsk->pid, 0);復制    }復制#endif復制  }復制  put_task_struct(tsk);復制  goto out_unlock_threadgroup;復制out_unlock_rcu:復制  rcu_read_unlock();復制out_unlock_threadgroup:復制  percpu_up_write(&cgroup_threadgroup_rwsem);復制  for_each_subsys(ss, ssid)復制    if (ss->post_attach)復制      ss->post_attach();復制  cgroup_kn_unlock(of->kn);復制  return ret ?: nbytes;復制}復制||→復制static int cgroup_attach_task(struct cgroup *dst_cgrp,復制            struct task_struct *leader, bool threadgroup)復制{復制  LIST_HEAD(preloaded_csets);復制  struct task_struct *task;復制  int ret;復制  復制  spin_lock_bh(&css_set_lock);復制  rcu_read_lock();復制  task = leader;復制  復制  復制  do {復制    cgroup_migrate_add_src(task_css_set(task), dst_cgrp,復制               &preloaded_csets);復制    if (!threadgroup)復制      break;復制  } while_each_thread(leader, task);復制  rcu_read_unlock();復制  spin_unlock_bh(&css_set_lock);復制    復制  復制  ret = cgroup_migrate_prepare_dst(dst_cgrp, &preloaded_csets);復制  if (!ret)復制    ret = cgroup_migrate(leader, threadgroup, dst_cgrp);復制  cgroup_migrate_finish(&preloaded_csets);復制  return ret;復制}


1.3、cgroup subsystem

我們關注cgroup子系統具體能提供的功能。

1.3.1、cpu

kernel/sched/core.c。會創建新的task_group,可以對cgroup對應的task_group進行cfs/rt類型的帶寬控制。



















































復制static struct cftype cpu_files[] = {復制#ifdef CONFIG_FAIR_GROUP_SCHED復制  {復制    .name = "shares",復制    .read_u64 = cpu_shares_read_u64,復制    .write_u64 = cpu_shares_write_u64,復制  },復制#endif復制#ifdef CONFIG_CFS_BANDWIDTH     // cfs 帶寬控制復制  {復制    .name = "cfs_quota_us",復制    .read_s64 = cpu_cfs_quota_read_s64,復制    .write_s64 = cpu_cfs_quota_write_s64,復制  },復制  {復制    .name = "cfs_period_us",復制    .read_u64 = cpu_cfs_period_read_u64,復制    .write_u64 = cpu_cfs_period_write_u64,復制  },復制  {復制    .name = "stat",復制    .seq_show = cpu_stats_show,復制  },復制#endif復制#ifdef CONFIG_RT_GROUP_SCHED    // rt 帶寬控制復制  {復制    .name = "rt_runtime_us",復制    .read_s64 = cpu_rt_runtime_read,復制    .write_s64 = cpu_rt_runtime_write,復制  },復制  {復制    .name = "rt_period_us",復制    .read_u64 = cpu_rt_period_read_uint,復制    .write_u64 = cpu_rt_period_write_uint,復制  },復制#endif復制  { }  復制};復制struct cgroup_subsys cpu_cgrp_subsys = {復制  .css_alloc  = cpu_cgroup_css_alloc,         // 分配新的task_group復制  .css_released  = cpu_cgroup_css_released,復制  .css_free  = cpu_cgroup_css_free,復制  .fork    = cpu_cgroup_fork,復制  .can_attach  = cpu_cgroup_can_attach,復制  .attach    = cpu_cgroup_attach,復制  .legacy_cftypes  = cpu_files,復制  .early_init  = 1,復制};

1.3.2、cpuset

kernel/cpusec.c。給cgroup分配不同的cpu和mem node節點,還可以配置一些flag。





















































































































復制static struct cftype files[] = {復制  {復制    .name = "cpus",復制    .seq_show = cpuset_common_seq_show,復制    .write = cpuset_write_resmask,復制    .max_write_len = (100U + 6 * NR_CPUS),復制    .private = FILE_CPULIST,復制  },復制  {復制    .name = "mems",復制    .seq_show = cpuset_common_seq_show,復制    .write = cpuset_write_resmask,復制    .max_write_len = (100U + 6 * MAX_NUMNODES),復制    .private = FILE_MEMLIST,復制  },復制  {復制    .name = "effective_cpus",復制    .seq_show = cpuset_common_seq_show,復制    .private = FILE_EFFECTIVE_CPULIST,復制  },復制  {復制    .name = "effective_mems",復制    .seq_show = cpuset_common_seq_show,復制    .private = FILE_EFFECTIVE_MEMLIST,復制  },復制  {復制    .name = "cpu_exclusive",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_CPU_EXCLUSIVE,復制  },復制  {復制    .name = "mem_exclusive",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_MEM_EXCLUSIVE,復制  },復制  {復制    .name = "mem_hardwall",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_MEM_HARDWALL,復制  },復制  {復制    .name = "sched_load_balance",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_SCHED_LOAD_BALANCE,復制  },復制  {復制    .name = "sched_relax_domain_level",復制    .read_s64 = cpuset_read_s64,復制    .write_s64 = cpuset_write_s64,復制    .private = FILE_SCHED_RELAX_DOMAIN_LEVEL,復制  },復制  {復制    .name = "memory_migrate",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_MEMORY_MIGRATE,復制  },復制  {復制    .name = "memory_pressure",復制    .read_u64 = cpuset_read_u64,復制  },復制  {復制    .name = "memory_spread_page",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_SPREAD_PAGE,復制  },復制  {復制    .name = "memory_spread_slab",復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_SPREAD_SLAB,復制  },復制  {復制    .name = "memory_pressure_enabled",復制    .flags = CFTYPE_ONLY_ON_ROOT,復制    .read_u64 = cpuset_read_u64,復制    .write_u64 = cpuset_write_u64,復制    .private = FILE_MEMORY_PRESSURE_ENABLED,復制  },復制  { }  復制}復制struct cgroup_subsys cpuset_cgrp_subsys = {復制  .css_alloc  = cpuset_css_alloc,復制  .css_online  = cpuset_css_online,復制  .css_offline  = cpuset_css_offline,復制  .css_free  = cpuset_css_free,復制  .can_attach  = cpuset_can_attach,復制  .cancel_attach  = cpuset_cancel_attach,復制  .attach    = cpuset_attach,復制  .post_attach  = cpuset_post_attach,復制  .bind    = cpuset_bind,復制  .fork    = cpuset_fork,復制  .legacy_cftypes  = files,復制  .early_init  = 1,復制};


1.3.3、schedtune

kernel/sched/tune.c,可以進行schedle boost操作。






















復制static struct cftype files[] = {復制  {復制    .name = "boost",復制    .read_u64 = boost_read,復制    .write_u64 = boost_write,復制  },復制  {復制    .name = "prefer_idle",復制    .read_u64 = prefer_idle_read,復制    .write_u64 = prefer_idle_write,復制  },復制  { }  復制};復制struct cgroup_subsys schedtune_cgrp_subsys = {復制  .css_alloc  = schedtune_css_alloc,復制  .css_free  = schedtune_css_free,復制  .legacy_cftypes  = files,復制  .early_init  = 1,復制};

1.3.4、cpuacct

kernel/sched/cpuacct.c,可以按照cgroup的分組來統計cpu占用率。

























復制static struct cftype files[] = {復制  {復制    .name = "usage",復制    .read_u64 = cpuusage_read,復制    .write_u64 = cpuusage_write,復制  },復制  {復制    .name = "usage_percpu",復制    .seq_show = cpuacct_percpu_seq_show,復制  },復制  {復制    .name = "stat",復制    .seq_show = cpuacct_stats_show,復制  },復制  { }  復制};復制struct cgroup_subsys cpuacct_cgrp_subsys = {復制  .css_alloc  = cpuacct_css_alloc,復制  .css_free  = cpuacct_css_free,復制  .legacy_cftypes  = files,復制  .early_init  = 1,復制};



原文標題:Linux schedule 之 Cgroup

文章出處:【微信公眾號:Linux閱碼場】歡迎添加關注!文章轉載請注明出處。

審核編輯:湯梓紅

 

下一篇: PLC、DCS、FCS三大控

上一篇: 星環科技CDH案例滿足

推薦產品

更多
主站蜘蛛池模板: 电液推杆生产厂家|电动推杆|液压推杆-扬州唯升机械有限公司 | KBX-220倾斜开关|KBW-220P/L跑偏开关|拉绳开关|DHJY-I隔爆打滑开关|溜槽堵塞开关|欠速开关|声光报警器-山东卓信有限公司 | 球磨机,节能球磨机价格,水泥球磨机厂家,粉煤灰球磨机-吉宏机械制造有限公司 | 工程管道/塑料管材/pvc排水管/ppr给水管/pe双壁波纹管等品牌管材批发厂家-河南洁尔康建材 | 干式磁选机_湿式磁选机_粉体除铁器-潍坊国铭矿山设备有限公司 | 编织人生 - 权威手工编织网站,编织爱好者学习毛衣编织的门户网站,织毛衣就上编织人生网-编织人生 | 面粉仓_储酒罐_不锈钢储酒罐厂家-泰安鑫佳机械制造有限公司 | 散热器厂家_暖气片_米德尔顿散热器| 语料库-提供经典范文,文案句子,常用文书,您的写作得力助手 | 浴室柜-浴室镜厂家-YINAISI · 意大利设计师品牌 | 咿耐斯 |-浙江台州市丰源卫浴有限公司 | 屏蔽服(500kv-超高压-特高压-电磁)-徐吉电气 | 直线模组_滚珠丝杆滑台_模组滑台厂家_万里疆科技 | LED灯杆屏_LED广告机_户外LED广告机_智慧灯杆_智慧路灯-太龙智显科技(深圳)有限公司 | 苏州同创电子有限公司 - 四探针测试仪源头厂家 | 量子管通环-自清洗过滤器-全自动反冲洗过滤器-沼河浸过滤器 | 气动绞车,山东气动绞车,气动绞车厂家-烟台博海石油机械有限公司 气动隔膜泵厂家-温州永嘉定远泵阀有限公司 | 菲希尔FISCHER测厚仪-铁素体检测仪-上海吉馨实业发展有限公司 | 上海小程序开发-上海小程序制作公司-上海网站建设-公众号开发运营-软件外包公司-咏熠科技 | 天津蒸汽/热水锅炉-电锅炉安装维修直销厂家-天津鑫淼暖通设备有限公司 | 板材品牌-中国胶合板行业十大品牌-环保板材-上海声达板材 | 老房子翻新装修,旧房墙面翻新,房屋防水补漏,厨房卫生间改造,室内装潢装修公司 - 一修房屋快修官网 | 乙炔气体报警装置|固定式氯化氢检测仪|河南驰诚电气百科 | 球盟会·(中国)官方网站| 工业机械三维动画制作 环保设备原理三维演示动画 自动化装配产线三维动画制作公司-南京燃动数字 聚合氯化铝_喷雾聚氯化铝_聚合氯化铝铁厂家_郑州亿升化工有限公司 | 活性氧化铝|无烟煤滤料|活性氧化铝厂家|锰砂滤料厂家-河南新泰净水材料有限公司 | 南京和瑞包装有限公司| 高低温试验箱-模拟高低温试验箱订制-北京普桑达仪器科技有限公司【官网】 | 成都竞价托管_抖音代运营_网站建设_成都SEM外包-成都智网创联网络科技有限公司 | 国产离子色谱仪,红外分光测油仪,自动烟尘烟气测试仪-青岛埃仑通用科技有限公司 | 固诺家居-全屋定制十大品牌_整体衣柜木门橱柜招商加盟 | 上海质量认证办理中心| 噪声治理公司-噪音治理专业隔音降噪公司 | 菲希尔FISCHER测厚仪-铁素体检测仪-上海吉馨实业发展有限公司 | 陕西华春网络科技股份有限公司 | 圣才学习网-考研考证学习平台,提供万种考研考证电子书、题库、视频课程等考试资料 | 深圳离婚律师咨询「在线免费」华荣深圳婚姻律师事务所专办离婚纠纷案件 | 耳模扫描仪-定制耳机设计软件-DLP打印机-asiga打印机-fitshape「飞特西普」 | 不锈钢管件(不锈钢弯头,不锈钢三通,不锈钢大小头),不锈钢法兰「厂家」-浙江志通管阀 | 实木家具_实木家具定制_全屋定制_美式家具_圣蒂斯堡官网 | 建筑资质代办-建筑资质转让找上海国信启航 | 密封无忧网 _ 专业的密封产品行业信息网 |