浅析linux内核__sysctl_head_next()函数内部实现
对于__sysctl_head_next的使用感觉很巧妙,因为你会发现很多东西都是使用static定义的,
而却又都能够一一引用到static定义的他们,实现数据很好的隐藏的同时,又不乏可操作性,
linux系统中/proc/sys/目录下的所有内容,就是使用这项技术生成的.[luther.gliethttp]
luther@gliethttp:~$ ls /proc/sys/
debug dev fs kernel net vm
static struct ctl_table_root sysctl_table_root;
static struct ctl_table_header root_table_header = {
.ctl_table = root_table,
.ctl_entry = LIST_HEAD_INIT(sysctl_table_root.header_list), // ctl_entry为添加到root所在header_list链表上的指针[luther.gliethttp]
.root = &sysctl_table_root, // 该header所归属的ctl_table_root,这里为sysctl_table_root
};
static struct ctl_table_root sysctl_table_root = { // sys控制table,该单元包含链接所有header的双向链表[luther.gliethttp]
.root_list = LIST_HEAD_INIT(sysctl_table_root.root_list),
.header_list = LIST_HEAD_INIT(root_table_header.ctl_entry),
// header_list链接着所有ctl_table_header类型内存中ctl_entry空间,它的初始值链接到root_table_header,
// 这样header_list将始终至少有1个有效值root_table_header.[luther.gliethttp]
};
struct ctl_table_header *__sysctl_head_next(struct nsproxy *namespaces,
struct ctl_table_header *prev)
{
struct ctl_table_root *root;
struct list_head *header_list;
struct ctl_table_header *head;
struct list_head *tmp;
spin_lock(&sysctl_lock);
if (prev) { // 是否接续前一个继续查找
head = prev;
tmp = &prev->ctl_entry;
unuse_table(prev);
goto next;
}
tmp = &root_table_header.ctl_entry; // 取出root_table内容[luther.gliethttp]
for (;;) {
head = list_entry(tmp, struct ctl_table_header, ctl_entry);
if (!use_table(head)) // 该head是否仍然可用,如果可用那么返回该head,否则从该head所属root继续取下一个head.
goto next;
spin_unlock(&sysctl_lock);
return head;
next:
root = head->root; // 该header所归属的ctl_table_root.[luther.gliethttp]
tmp = tmp->next;
header_list = lookup_header_list(root, namespaces);
if (tmp != header_list)
// header_list为该root管理的链表头,如果tmp等于链表头,说明链表已经遍历完毕,否则continue[luther.gliethttp].
continue;
do {
root = list_entry(root->root_list.next, // 从root->root_list链表中取出下一个root,该root也管理着它
// 自己所要管理的header_list链表[luther.gliethttp].
// 每一个创建的ctl_table_root都有一个它管理的相应的ctl_table_header,该ctl_table_header的.root指向
// 该ctl_table_root
struct ctl_table_root, root_list);
if (root == &sysctl_table_root) // root是否已经到了链表头sysctl_table_root了,如果到了,说明root已经空了[luther.gliethttp]
goto out;
header_list = lookup_header_list(root, namespaces); //取出该root管理的header_list.[luther.gliethttp]
} while (list_empty(header_list));
// 如果该root管理的header_list不存在内容,那么回到上面继续从root->root_list链表中取出下一个root
tmp = header_list->next; // 好了,该root的header_list管理内容非空.[luther.gliethttp]
}
out:
spin_unlock(&sysctl_lock);
return NULL;
}
|