一、背景
在阅读rcu的代码时,会发现有些变量使用了看似冗余的包裹,如下图里的这个函数:

这个raw_spin_lock_irqsave_rcu_node函数如下图仅仅是调用了raw_spin_lock_irqsave而已,但是是多了这一层包装是为啥呢?

那是因为上图里使用了ACCESS_PRIVATE宏,这个宏是用来引用带有__private表示的结构体里的变量。
我们在第二章里给出一个使用__private来标识变量的例子,通过实验来说明其用途。
二、内核代码里使用__private标识符的例子
2.1 例子源码
测试__private标识符的实验的内核模块代码如下:
cpp
#include <linux/poll.h>
#include <linux/types.h>
#include <linux/ioctl.h>
#include <linux/errno.h>
#include <linux/stddef.h>
#include <linux/lockdep.h>
#include <linux/kthread.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/wait.h>
#include <linux/init.h>
#include <asm/atomic.h>
#include <trace/events/workqueue.h>
#include <linux/sched/clock.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/interrupt.h>
#include <linux/tracepoint.h>
#include <trace/events/osmonitor.h>
#include <trace/events/sched.h>
#include <trace/events/irq.h>
#include <trace/events/kmem.h>
#include <linux/ptrace.h>
#include <linux/uaccess.h>
#include <asm/processor.h>
#include <linux/sched/task_stack.h>
#include <linux/nmi.h>
#include <asm/apic.h>
#include <linux/version.h>
#include <linux/sched/mm.h>
#include <asm/irq_regs.h>
#include <linux/kallsyms.h>
#include <linux/kprobes.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zhaoxin");
MODULE_DESCRIPTION("Module for kernel test __private.");
MODULE_VERSION("1.0");
//#define __CHECKER__
struct testprivate {
int __private abc;
};
static int __init testprivate_init(void)
{
struct testprivate pri;
pri.abc = 1;
ACCESS_PRIVATE(&pri, abc) = 1;
return 0;
}
static void __exit testprivate_exit(void)
{
}
module_init(testprivate_init);
module_exit(testprivate_exit);
2.2 实验步骤及说明
先尝试编译上面 2.1 里的代码,无论是带__CHECKER__宏还是不带:

用普通的make都是能编过的:

事实上,要让编译的时候进行__private变量的相关检查,得依赖sparse工具,sparse工具是Linux本人编写的,要让sparse工具参与编译,则要如下进行编译。
使用下面的命令可以重新编译代码,并且使用sparse工具进行静态检查:
bash
make C=2
如果没有安装sparse,会有如下报错:

装一下sparse工具:
bash
apt-get install sparse
然后再make C=2:
可以发现有如下检查到的warning:

也能和代码上对应上:

意思就是__private的变量需要用ACCESS_PRIVATE宏来进行引用。
我们把这句话注释掉,相关的warning就没有了:

要注意,这只是一句warning,不影响编译出ko!