linux内核网络揭秘《二》“每日读书”

一  引用计数

当一段代码试图访问一个已经释放数据结构时内核并不欢迎大多用户对于内核这种反应也会感到不愉快为了避免这类讨厌问题同时垃圾回收机制更为容易而且效率数据结构都会保存引用技术reference count,每一个数据结构每一次存储释放良好的内核组建都会分别递增递减数据结构引用计数人和数据结构需要引用计数拥有数据结构的内核组建通常会提供两个函数递增递减引用计数这类函数通常分别称为xxx_holdxxx_release有时候释放函数被称为xxx_put(例如,net_device结构的释放函数就是dev_put)

虽然我们希望内核中么有不良组建但是开发人员也是人因此不可能永远写出无缺陷代码引用计数运用是一种简单有效机制可以避免释放被引用数据结构然而因其忽略了平衡递增递减

如果你是放了一个数据结构引用但是忘记了调用xxx_release函数内核永远不会让数据结构释放掉这样会导致内存逐渐耗尽

如果你引用了一个数据结构但是忘记了调用xxx_hold后来碰巧又成唯一引用持有者结果结构就会提早释放这种情况肯定比前一种具有灾难性下次试图访问结构时可能会破坏其他数据或者引起内核恐慌panic

某个数据结构因为某种原因被删除可以明确引用持有数据结构即将消失使其按规则释放引用这是通过通知实现

数据结构引用计数通常下列情况可做递增

两种数据结构类型之间密切的关系在这种情况下其中一个结构通常维持一个初始化第二个结构地址的指针

一个定时器启动定时器处理程序访问数据结构定时器启动时结构引用计数就会递增因为你最不愿意看到在定时器到期数据结构就被释放

对列表hash成功查询会反悔一个指向匹配元素指针多数情况下返回的结果调用者用来执行某种任务因此常见做法是查询函数递增匹配元素引用计数然后必要调用者予以释放

当一个数据结构最后一个引用也被释放数据结构可以被释放因为再也用不到数据结构不过不一定这么做不可

引入sysfs文件系统有助于产生内核一部分良好代码运用可以更关注引用计数一致性

二 垃圾回收

内存有限共享资源不应该浪费特别是内核因为内核不适用虚拟内存多数内核子系统会实现某种垃圾收集回收使用或者无效数据结构实例持有内存根据特定功能所需而定你会发现有两种主要垃圾收集

异步

这种垃圾收集类型特点事件无关一个定时器定期启用一个函数扫描一组数据结构然后那些适合删除数据结构释放掉数据结构符合删除条件依赖系统功能逻辑但是一个常见准则是否存在null引用计数

同步

内存不足时i请你赶快下立即触发垃圾收集而不能等待定时器触发异步垃圾手机用于选取符合删除数据结构准则不一定异步清理机制所用准则相同

函数指针虚拟函数表(VFT)

函数指针是一种方便方式可以写出简洁C代码又能利用面向对象语言某些优点在数据结构类型的定义中,你可以包含一组函数指针于是结构某些全部操作都可以通过嵌入函数完成C语言函数指针数据结构类似如下所示

struct sock {

void (*sk_state_change)(strict sock *sk);

void (*sk_data_ready)(struct sock *sk, int bytes);

};

使用函数指针最主要优点就是可以根据不同准则以及对象扮演角色进行初始化因此调用sk_state_change实际上可能会不同sock套接字调用不同函数

函数指针网络代码广为使用下面只是很少实例

入口数据封包或者出口数据封包路由子系统处理会对缓冲区数据结构两个函数初始化三十五章就会看到参考第二章所列sk_buff数据结构完整函数指针列表

数据封包准备网络硬件传输就会交给net_device数据结构hard_start_xmit 函数指针函数设备关联设备驱动程序进行初始化

L3协议传输数据封包调用一组函数指针一个这些函数指针L3协议相关联地址解析协议(address reolution protocol)

负责初始化一组函数根据函数指针初始化史记汉书可以产生透明化L3L2地址解析当不需要地址解析就会使用另一个函数

通过上述几个例子可知函数指针作为内核组件之间接口或者 作为一种通用机制根据不同子系统所做某事结果适当时机调用适当函数处理程序在其他情况下函数指针也可以作为一种简单方式使协议设备驱动程序或者任何其他功能得以某种动作个别化

看一个例子当设备驱动程序在内核注册网络设备无论任何类型设备都需要经过一系列步骤到了某一时刻就会对net_device数据结构调用一个函数指针使设备驱动程序必要时做些其他事情设备驱动程序可以函数指针初始化拥有一个函数也可以指针保持NULL因为内核默认执行步骤已经足够了

执行一个函数指针必须始终检查避免提取NULL指针指向单元事情发生,例如 register_netdevice 片段

if (dev->init && dev->init(dev) != 0)

函数指针有一个主要的缺点代码难以理解

当选择函数分配函数指针基于特定数据片段(如处理数据的协议,或者接收的给定数据封包来自的设备驱动程序)们就比较容易推导函数例如如果给定设备drivers/net/3c59x.c设备驱动程序管理就可以阅读设备驱动程序提供设备初始化函数从而导出分配net_device数据结构特定函数指针函数

函数选择基于更为复杂逻辑L3L2地址映射解析状态人和时刻所用函数都会依赖无法预测外在事件

指向一个数据结构一组函数指针通常称为虚拟函数表virtual functiotable, VFT作为两个主要子系统之间接口数据结构函数指针树木可能会膨胀包含许多不同指针适应各种各样协议或者功能这种用过头VFT变得很笨重

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值