rcu的学习记录

crash> p rcu_sched_state.node[0]
$13 = {
  lock = {
    raw_lock = {
      slock = 748760225
    }
  },
  gpnum = 21141468,
  completed = 21141467,
  qsmask = 1,
  expmask = 0,
  wakemask = {
    counter = 0
  },
  qsmaskinit = 1,
  grpmask = 0,
  grplo = 0,
  grphi = 4095,
  grpnum = 0 '00',
  level = 0 '00',---------------来自灵魂的拷问,你的level编号,root是0级
  parent = 0x0,
  blkd_tasks = {
    next = 0xffffffff81a28e58,
    prev = 0xffffffff81a28e58
  },
  gp_tasks = 0x0,
  exp_tasks = 0x0,
  node_kthread_task = 0x0,
  node_kthread_status = 0
}
crash> p rcu_sched_state.node[1]
$14 = {
  lock = {
    raw_lock = {
      slock = 2634718474
    }
  },
  gpnum = 21141468,
  completed = 21141467,
  qsmask = 1073741823,
  expmask = 0,
  wakemask = {
    counter = 0
  },
  qsmaskinit = 4294967295,
  grpmask = 1,-------------常量
  grplo = 0,
  grphi = 63,
  grpnum = 0 '00',
  level = 1 '01',
  parent = 0xffffffff81a28e00,------这个就是node[0]的地址
  blkd_tasks = {
    next = 0xffffffff81a28f58,
    prev = 0xffffffff81a28f58
  },
  gp_tasks = 0x0,
  exp_tasks = 0x0,
  node_kthread_task = 0x0,
  node_kthread_status = 0
}
crash> p &rcu_sched_state.node[0]
$15 = (struct rcu_node *) 0xffffffff81a28e00

 4还会记录gp的历史最大值,即gp_max,

p rcu_sched_state
rcu_sched_state = $22 = {


struct rcu_node node[65]-----省略
level = {0xffffffff81a28e00, 0xffffffff81a28f00}, levelcnt = {1, 64, 4096, 0, 0}, levelspread = "@@", rda = 0xce00, signaled = 2 '02', fqs_active = 0 '00', fqs_need_gp = 0 '00', boost = 0 '00', gpnum = 21141468, completed = 21141467, onofflock = { raw_lock = { slock = 2569574696 } }, fqslock = { raw_lock = { slock = 659040072 } }, jiffies_force_qs = 4447515504, n_force_qs = 36185678, n_force_qs_lh = 219254, n_force_qs_ngp = 7, gp_start = 4447515501, jiffies_stall = 4447530501, gp_max = 54, name = 0xffffffff8178a4e7 "rcu_sched_state" }
/*
 * Dynticks per-CPU state.
 */
struct rcu_dynticks {
    int dynticks_nesting;    /* Track irq/process nesting level. */
    int dynticks_nmi_nesting; /* Track NMI nesting level. */
    atomic_t dynticks;    /* 偶数代表处于dyntick-idle*/
};
crash> rcu_sched_data
PER-CPU DATA TYPE:
  struct rcu_data rcu_sched_data;
PER-CPU ADDRESSES:
  [0]: ffff88207fc0ce00
  [1]: ffff88207fc2ce00
  [2]: ffff88207fc4ce00
  [3]: ffff88207fc6ce00
  [4]: ffff88207fc8ce00
  [5]: ffff88207fcace00
  [6]: ffff88207fccce00
  [7]: ffff88207fcece00
  [8]: ffff88407fc0ce00
  [9]: ffff88407fc2ce00
  [10]: ffff88407fc4ce00
  [11]: ffff88407fc6ce00
  [12]: ffff88407fc8ce00
  [13]: ffff88407fcace00
  [14]: ffff88407fccce00
  [15]: ffff88407fcece00
  [16]: ffff88207fd0ce00
  [17]: ffff88207fd2ce00
  [18]: ffff88207fd4ce00
  [19]: ffff88207fd6ce00
  [20]: ffff88207fd8ce00
  [21]: ffff88207fdace00
  [22]: ffff88207fdcce00
  [23]: ffff88207fdece00
  [24]: ffff88407fd0ce00
  [25]: ffff88407fd2ce00
  [26]: ffff88407fd4ce00
  [27]: ffff88407fd6ce00
  [28]: ffff88407fd8ce00
  [29]: ffff88407fdace00
  [30]: ffff88407fdcce00
  [31]: ffff88407fdece00
crash> rcu_data ffff88407fd0ce00
struct rcu_data {
  completed = 21141467,
  gpnum = 21141468,
  passed_quiesc_completed = 21141466,
  passed_quiesc = false,
  qs_pending = true,
  beenonline = true,
  preemptible = false,
  mynode = 0xffffffff81a28f00,
  grpmask = 16777216,
  nxtlist = 0xffff8831017b1280,
  nxttail = {0xffff88407fd0ce30, 0xffff88407fd0ce30, 0xffff88055065ab48, 0xffff88055065ab48},
  qlen = 0,
  qlen_last_fqs_check = 0,
  n_cbs_invoked = 292196490,
  n_cbs_orphaned = 0,
  n_cbs_adopted = 0,
  n_force_qs_snap = 0,
  blimit = 10,
  dynticks = 0xffff88407fd0cde0,
  dynticks_snap = 834727793,
  dynticks_fqs = 1555945,
  offline_fqs = 0,
  resched_ipi = 1016,
  n_rcu_pending = 130520066,
  n_rp_qs_pending = 24570,
  n_rp_report_qs = 19693251,
  n_rp_cb_ready = 8253,
  n_rp_cpu_needs_gp = 270805,
  n_rp_gp_completed = 19229197,
  n_rp_gp_started = 124913,
  n_rp_need_fqs = 16071,
  n_rp_need_nothing = 91177576,
  cpu = 24
}
crash> struct rcu_dynticks 0xffff88407fd0cde0
struct rcu_dynticks {
  dynticks_nesting = 2,
  dynticks_nmi_nesting = 0,
  dynticks = {
    counter = 834728091--------奇数
  }
}

对于level的个数和node的个数:

crash> !grep CONFIG_RCU_FANOUT  /boot/config-3.0.101-0.47.90-default
CONFIG_RCU_FANOUT=64

CONFIG_RCU_FANOUT_LEAF没有设置,则走代码默认设置

给定由RCU_FANOUT 和RCU_FANOUT_LEAF指定的扇出的情况下,第21-24行分别计算单级(包含单个rcu_node结构),两级,三级和四级rcu_node支持的最大CPU数量这些数量的CPU分别保留在RCU_FANOUT_1, RCU_FANOUT_2, RCU_FANOUT_3和 RCU_FANOUT_4 C预处理器变量中。

心得:

在rcu的回调中,一般是引用计数为0再挂rcu,然后在执行rcu的时候,用bugon判断一下计数。

static void release_tgcred(struct cred *cred)
{
#ifdef CONFIG_KEYS
    struct thread_group_cred *tgcred = cred->tgcred;

    if (atomic_dec_and_test(&tgcred->usage))
        call_rcu(&tgcred->rcu, release_tgcred_rcu);
#endif
}

如上,可以见到 atomic_dec_and_test ,这通过将引用计数-1然后和0比较,如果相等,则返回1,否则返回0,那么其实就是原子判断引用计数是否为1,

然后在rcu的回调中,通过BUG_ON的方式,确定是可以释放的,这样可以保证资源释放的时候,不会有其他的人在用这块内存了。这是一个好的编码习惯,减少了内存踩来踩去

的风险。

static void release_tgcred_rcu(struct rcu_head *rcu)
{
    struct thread_group_cred *tgcred =
        container_of(rcu, struct thread_group_cred, rcu);

    BUG_ON(atomic_read(&tgcred->usage) != 0);

    key_put(tgcred->session_keyring);
    key_put(tgcred->process_keyring);
    kfree(tgcred);
}

rcu的嵌套问题,后面补充。

水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。
原文地址:https://www.cnblogs.com/10087622blog/p/11142849.html