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 '\000', level = 0 '\000',---------------来自灵魂的拷问,你的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 '\000', level = 1 '\001', 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 '\002', fqs_active = 0 '\000', fqs_need_gp = 0 '\000', boost = 0 '\000', 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的嵌套问题,后面补充。
水平有限,如果有错误,请帮忙提醒我。如果您觉得本文对您有帮助,可以点击下面的 推荐 支持一下我。版权所有,需要转发请带上本文源地址,博客一直在更新,欢迎 关注 。