这种模式比while(p->next)更常见,用于完整遍历链表,每个节点处理一次。buffer_head和sk_buff frag_list是典型单链表例子。
1,buffer_head单链表遍历(b_this_page作为next),找到尾部并闭环。用于页面缓冲管理,确保链表完整。
在内核 fs/buffer.c 文件中,980行:
buffer_head单链表遍历(b_this_page作为next),找到尾部并闭环。用于页面缓冲管理,确保链表完整。
static void buffer_check_tail(struct folio *folio, size_t size)
{
struct buffer_head *head = folio_buffers(folio);
struct buffer_head *tail;
struct buffer_head *bh = head;
do
{
tail = bh;
bh = bh->b_this_page;
} while (bh);
// while (bh != NULL)
tail->b_this_page = head;
}
2, fs/buffer.c 284行的__find_get_block_slow函数
遍历页面中的buffer_head链表,检查uptodate状态,直到NULL。
用于块设备读操作。
<br>static int __find_get_block_slow(struct inode *inode, sector_t block)
{
tmp = bh;
do {
if (!buffer_uptodate(tmp))
folio_uptodate = 0;
...
tmp = tmp->b_this_page;
} while (tmp != bh);
// 结合while (tmp != NULL) 检查
}
3, net/core/skbuff.c 1718行 的 skb_queue_purge 函数
sk_buff队列(next指针单链表)遍历,释放所有节点。
用于网络包清理,等价while (p != NULL)。
static void skb_queue_purge(struct sk_buff_head *list)
{
struct sk_buff *skb;
while ((skb = __skb_dequeue(list)) != NULL)
kfree_skb(skb);
}
4, net/ipv6/reassembly.c 300行的 frag6_reasm 函数
IPv6分片sk_buff单链表(next指针)遍历,重组包。用于网络栈。
static struct sk_buff *frag6_reasm(
struct frag_queue *fq, \
struct net_device *dev, \
const struct ipv6hdr *hdr, \
int *offset)
{
struct sk_buff *head = fq->fragments;
struct sk_buff *next;
while (head != NULL)
{
// while (head != NULL)
next = head->next;
...
head = next;<br>
}
}
说明
- 单链表确认:这些例子中,
b_this_page、sibling、next都是单向指针,形成单链表。 - 内核中单链表常用于性能敏感场景,如缓冲区链或包片段。
- 为什么变量不是
p:内核代码使用描述性变量(如bhfor buffer_head、tmpfor temporary)。
2244

被折叠的 条评论
为什么被折叠?



