在公开内核功能时,内核开发人员有多种选择。他们可以创建新的系统调用或通过 /sys 或 /proc 条目公开功能。
有理由选择其中一种而不是另一种吗?
内核开发人员是否会避免添加新的系统调用,除非它提供了相当大的优势,或者他们是否在需要时自由地添加调用?
编辑:我正在开发一个项目,将 netfilter 功能公开给 Linux 容器 (LXC)。功能必须以受控方式公开,例如,当容器(例如 c1)想要放置 netfilter 挂钩时,只有当数据包用于 c1 中的网络接口时才必须调用该挂钩。
我可以创建新的系统调用,或者允许容器安装模块,并在内核中提供转换层,以保护主机内核免受来宾安装的内核模块的影响。 (此翻译模块的实现或允许容器安装模块的安全影响可能是另一个讨论的主题)。
添加新的系统调用将确保更好的隔离,同时允许来宾安装模块将具有更好的性能。后者还可以公开系统调用无法公开的功能,例如,如果来宾想要使用自己的 TCP/IP 堆栈版本。
经验丰富的 Linux 内核开发人员会更喜欢什么?
答案1
很少添加新的系统调用。大多数新的内核功能可以通过一些通用机制来实现:
这些通用机制受益于现有的通用支持。例如,附加到描述符的资源会自动与子进程共享,execve
如果标记为这样做,则自动关闭,当描述符关闭时释放(进程终止时发生)等。对作为文件实现的新功能的访问控制是通过完善的文件访问控制机制(权限、SELinux 等)提供。
这些通用机制也比新的系统调用更容易使用,因为它们可以立即使用,无需等待库支持。/proc
可以直接从 shell 脚本使用新条目。新的ioctl
可以直接从应用程序使用。需要在标准库中声明一个新的系统调用。
这系统调用手册页列出添加每个系统调用的内核版本。大多数新的系统调用提供了操作某些类型文件的新方法,要么管理元数据和凭证(例如 2.6 中的扩展属性支持),要么作为以前不太可能的变体操作(例如execveat
,renameat2
)。
答案2
这Linux 文档给出了添加新系统调用的指南。
以下是与我们讨论相关的要点
- 当添加新的系统调用时,它就成为内核 API 的一部分,并且必须无限期地支持。
- 创建新的系统调用也是一项更大的责任,因为它涉及创建测试代码、手册页以及足够大的动机将其包含在主线内核中,而不是作为内核模块发布。
- 如果新功能类似于文件系统的使用交互(例如,可以通过简单读取 /proc/meminfo 来获取内存使用等运行时信息),请使用 /proc、/sys、/dev 条目。它们可以由模块创建,并且可以根据需要放入内核或从内核中取出。它们还提供了吉尔斯答案中给出的优势。
这些Linux 内核文档中另一个文件中的行解释了开发过程,强调了在公开用户空间 ABI 之前必须完成的工作。
一旦接口导出到用户空间,就必须无限期地支持它。这一事实使得用户空间界面的创建特别具有挑战性:由于它们不能以不兼容的方式进行更改,因此必须第一次就正确完成。
因此,始终需要对用户空间界面进行大量的思考、清晰的文档和广泛的审查。