已知一个变量的地址时,使用container_of获取此变量所在的结构体的首指针。其定义如下:
#define container_of(ptr, type, member) ({ \
void *__mptr = (void *)(ptr); \
BUILD_BUG_ON_MSG(!__same_type(*(ptr), ((type *)0)->member) && \
!__same_type(*(ptr), void), \
"pointer type mismatch in container_of()"); \
((type *)(__mptr - offsetof(type, member))); })
看一个例子,在中断下半部处理中,process_backlog函数根据napi指针地址,获取到其所在的softnet_data结构体的地址。一定要注意的是第三个参数(member)成员变量backlog,在结构体softnet_data中为变量,而不是指针,意思就是说backlog的地址一定是在为softnet_data分配空间的时候一起分配的,才能保证由backlog的地址(参数一:napi)推导出softnet_data的地址。
struct softnet_data {
struct sk_buff_head process_queue;
struct sk_buff_head input_pkt_queue;
struct napi_struct backlog; //这里一定是变量,而非指针。
};
static int process_backlog(struct napi_struct *napi, int quota)
{
struct softnet_data *sd = container_of(napi, struct softnet_data, backlog);
}
如果backlog是一个指针,会出现什么情况?如下,假设成员backlog为指针,其初始化为全局变量ns_g的地址。此时的container_of拿ns_g的地址去做偏移,显然会得到一个非法的越界指针。
struct softnet_data {
struct napi_struct *backlog; //错误情况
} sd_test;
struct napi_struct ns_g;
sd_test.backlog = &ns_g;
其实此种情况下,也是可以得到正确的softnet_data的地址的,只不过需要用backlog指针的地址去做偏移。