无阻塞分配sk_buff的机制:Rx路径skb分配不阻塞原理咨询
Rx路径里的skb分配之所以能在软中断/ksoftirqd这类不能阻塞的上下文里安全执行,核心是内核从内存分配接口、缓存优化、预分配策略三个层面做了保障:
使用非阻塞的内存分配接口
软中断上下文里分配skb依赖__dev_alloc_skb()或netdev_alloc_skb()这类专用函数,它们底层调用内存分配器时会带上GFP_ATOMIC标志。这个标志明确告知内核:不能触发页交换、不能等待空闲内存释放,只能从当前可用的内存池(包括高端内存)直接分配,失败就立刻返回NULL,全程不会阻塞。skb专属的SLAB/SLUB缓存优化
内核为skb结构体和对应的数据包缓冲区专门维护了SLAB/SLUB缓存。这些缓存会预先批量分配好内存块,分配skb时直接从缓存里取,不用每次都去伙伴系统申请零散内存。这种预缓存的方式不仅速度快,还避免了伙伴系统分配可能带来的不确定性,确保软中断里的分配操作能快速完成,不会陷入阻塞。网卡驱动的预分配队列
多数网卡驱动会在初始化阶段或空闲时,预先分配一批skb放到接收队列里。当软中断处理网卡收包时,直接从预分配队列里拿现成的skb来填充数据,根本不需要临时分配内存。比如NAPI机制里的接收队列,就会提前备好skb,最大化减少软中断里的内存分配操作。
另外,就算真的遇到内存分配失败的极端情况,内核也不会在软中断上下文里死等,而是直接丢弃数据包或者触发网卡的流量控制,保证软中断能快速退出,不会拖慢整个系统的响应。
至于ksoftirqd,它虽然是内核进程(运行在进程上下文),但处理软中断时依然遵循上述规则——用非阻塞分配、优先用缓存,目的是保证软中断处理的高效性,避免长时间占用CPU资源。
内容的提问来源于stack exchange,提问作者user3882729

