1、klist链表相关结构
内核源码中,klist相关的头文件是include/linux/klist.h,实现的文件是lib/klist.c中,接下来分析klist链表头和klist链表节点的定义:
首先是klist链表头的定义,如下:
struct klist {
spinlock_t k_lock;
struct list_head k_list;
void (*get)(struct klist_node *);
void (*put)(struct klist_node *);
} __attribute__ ((aligned (sizeof(void *))));
成员分析:
k_lock:链接节点操作所需要的自旋锁;
k_list:嵌入的双向链表list;
get:函数指针,用于链表内的节点增加引用计数;
put:函数指针,用于链表内的节点减少引用计数。
需要注意的是,该struct klist结构体是sizeof(void *)字节对齐,假如是4字节对齐的话,说明klist链表的实例地址的最低位是0,并且在klist实例中,地址的最低位具有其它用处。
接下来是klist链表中的节点结构定义,结构体名为struct klist_node,该定义如下:
struct klist_node {
void *n_klist; /* never access directly */
struct list_head n_node;
struct kref n_ref;
};
成员分析:
n_klist:用于指向klist链表头;
n_node:嵌入的双向链表list;
n_ref:klist链表节点的引用计数器。
需要注意的是,n_klist指针是用来指向链表头的,它的最低位用来表示该节点是否已被请求删除,如果已经被请求删除的话,在klist链表中遍历是看不到该节点的。
这两个结构体形成的一个简单链表结构如下所示:
2、klist链表实现
接下来对klist链表的相关操作进行简单分析:
#define KLIST_INIT(_name, _get, _put) \
{ .k_lock = __SPIN_LOCK_UNLOCKED(_name.k_lock), \
.k_list = LIST_HEAD_INIT(_name.k_list), \
.get = _get, \
.put = _put, }
#define DEFINE_KLIST(_name, _get, _put) \
struct klist _name = KLIST_INIT(_name, _get, _put)
/**
* klist_init - Initialize a klist structure.
* @k: The klist we're initializing.
* @get: The get function for the embedding object (NULL if none)
* @put: The put function for the embedding object (NULL if none)
*
* Initialises the klist structure. If the klist_node structures are
* going to be embedded in refcounted objects (necessary for safe
* deletion) then the get/put arguments are used to initialise
* functions that take and release references on the embedding
* objects.
*/
void klist_init(struct klist *k, void (*get)(struct klist_node *),
void (*put)(struct klist_node *))
{
INIT_LIST_HEAD(&k->k_list); //双向链表初始化
spin_lock_init(&k->k_lock); //自旋锁初始化
k->get = get;
k->put = put;
}
KLIST_INIT()宏用于对klist的链表头进行初始化,包括自旋锁以及嵌入的双向链表初始化,DEFINE_KLIST()宏则是用来定义一个klist,并调用KLIST_INIT()宏进行初始化,klist_init()则是使用函数的方式对klist进行初始化。
/*
* Use the lowest bit of n_klist to mark deleted nodes and exclude
* dead ones from iteration.
*/
#define KNODE_DEAD 1LU
#define KNODE_KLIST_MASK ~KNODE_DEAD
static struct klist *knode_klist(struct klist_node *knode)
{
return (struct klist *)
((unsigned long)knode->n_klist & KNODE_KLIST_MASK);//将指针的最低位清0,并返回指针
}
static bool knode_dead(struct klist_node *knode)
{
return (unsigned long)knode->n_klist & KNODE_DEAD;//判断最低位
}