【问题标题】:What would you write kernel module for?你会写内核模块做什么?
【发布时间】:2014-10-08 12:11:52
【问题描述】:

更多的是概述问题而不是技术问题。我可以看到周围的 linux 内核开发人员职位,我想知道你想成为一个内核模块吗?与使用系统调用和做事相比,什么样的任务最好作为内核模块完成?

less /proc/modules 在我的系统上显示 dm_log,一个设备映射器的记录器。为什么要从内核进行日志记录,而不是在用户空间进行?

【问题讨论】:

  • 请注意,设备映射器是一个内核组件。因此,如果我们要从中导出日志消息,我们必须在内核中进行(因为内核是产生日志消息的东西)

标签: linux linux-kernel kernel-module


【解决方案1】:

你想成为一个内核模块是什么?

虽然大多数人(仅)将内核模块与设备驱动程序相关联,但文件系统和网络协议处理程序等其他内核服务也可以构建为模块。
内核模块与静态链接(即内置在内核中)的主要理由是运行时可配置性(这反过来又提高了内存效率)。可选功能、服务和驱动程序可以不包含在引导的内核中,但仍然可以在以后需要时加载。
加载模块的开销、模块所需的存储空间(内核通常以压缩形式存储而模块未压缩)以及每个模块浪费的内存页面片段通常被认为是可接受的权衡。

与使用系统调用和做事相比,什么样的任务最好作为内核模块完成?

这是一个单独的问题,与前面的问题没有真正的关系。您实际上应该比较用户模式与内核模式。内核模式是使用模块(必须加载)还是静态链接代码(始终可用)并不是实际问题的重要方面。 (另一个提到“由于虚拟内存开销而导致运行模块代码时性能下降”的答案是不正确的。)

用户模式服务或驱动程序具有以下优点:

  • 通常更容易和更快地实现(无需构建和安装内核)。大多数 C 程序员(仅)学习 C 运行时库,因此内核环境而不是用户模式可能是一种学习体验。

  • 更容易控制专有源代码。可能不受 GNU GPL 约束。

  • 受限制的权限不太可能无意中关闭系统或造成安全漏洞。

内核模式服务或驱动程序具有以下优点:

  • 系统中的多个程序都可用,而没有混乱的排除锁。

  • 可以通过文件权限控制设备的可访问性。

  • 只要系统正在运行,设备或服务的状态就会持续且可用。每次程序启动时,用户模式驱动程序都必须将设备重置为已知的静止状态。

  • 更一致/准确的计时器和减少的事件延迟。

用户模式与内核模式的一个例子是Reliable Datagram Sockets,它在版本 2.6.30 中添加到 Linux 内核。以前 RDS 是基于 UDP 的用户模式协议,但通过“acking / windowing / fragmenting / re-ordering, etc”进行了增强。在重负载下,用户模式协议的计时器不准确,因此额外的重传和丢弃的消息会导致稳定性和性能问题。切换到内核模式网络协议旨在改进/解决此类问题。

但是,内核模式存在缺陷(或责任)。内核代码负责确保系统的完整性和安全性。发现 RDS 在内核中引入了security hole

为什么要从内核进行日志记录,而不是在用户空间进行?

可能有几个原因,但对于这个例子来说,日志请求者很可能处于内核模式而不是用户模式,因此这将避免尴尬的模式切换。

【讨论】:

    【解决方案2】:

    系统调用、设备驱动程序、/sys/procmmap 用户 API 只允许用户空间程序对内核中的符号和数据进行有限的、高度受控的接口。这些接口不允许访问您希望使用驱动程序(例如dm_log)记录的大部分数据和事件。要将这些数据导出到用户空间,您需要一个内核模式驱动程序,可以是已编译的或可加载的内核模块。

    在中断处理、系统调用、设备文件、/proc/sys文件系统,也就是用户空间API方面,内核代码和模块代码没有区别。

    以下是使用 Linux 内核模块技术的一些原因:

    1. 将代码从内核移动到模块会减小内核的大小
    2. 减小内核大小可缩短内核启动时间 - 模块在用户空间启动期间加载,或者在需要时加载
    3. 模块代码使用vmalloc 加载到内核空间虚拟内存中,因此可以更有效地利用内核空间内存,因为如果卸载模块,分配的内存将被释放,而编译到内核中的未使用驱动程序的内存则不能被释放
    4. 模块允许添加内核功能而无需重新编译、重新安装甚至重新启动内核。这通常会缩短开发时间。
    5. 模块允许在以后任意时间添加功能
    6. 将功能从内核移至模块允许灵活配置 - 同一内核可用于更多类型的系统,或用于因外围设备更改而随时间变化的同一系统,每个系统的不必要代码更少
    7. 新功能可以作为模块文件分发,更易于传输和安装

    使用模块的缺点是:

    1. 如果您需要编写在不同处理器模式下执行的代码,例如 ARM FIQ 模式,则需要使用“裸机”工具链单独编译代码并将编译后的代码嵌入到模块中。该裸机代码将无法访问内核符号,因为它在vmalloced 内存中执行,其基地址当时不可知。 OTOH,您可以在常规内核构建期间编写 FIQ 模式代码并将其编译到内核中,并且该代码在 FIQ 模式下运行时可以访问内核符号,因为基本内核中的虚拟地址和真实地址是相同的。
    2. 由于虚拟内存开销,在运行模块代码时会出现小幅性能损失

    关于用户空间驱动程序,如果这真的是 OP 的意图 - 用户空间驱动程序就是这样,仅在用户空间中运行的程序。因此,它们对内核符号或内存的访问权限并不比任何其他用户空间应用程序多,也就是说,不多。

    【讨论】:

    • 这解决了使用模块与静态链接到内核的原因,但我认为最初的问题是询问使用模块与用户空间设备驱动程序的原因(“系统调用和做事”)
    • @AdrianCox:OP 的原始措辞并未向我表明对用户空间驱动程序概念的认识。无论如何,我添加了对关于dm_log 的 OP 问题最后一部分的具体参考。
    • "3. 模块代码被加载到虚拟内存中" -- 整个内核在虚拟内存中。你在写什么?
    • @sawdust:我在回答中添加了一些说明。请查阅。其意图是说模块加载在vmalloced 的空间中,而不是实际地址和虚拟地址相同的编译驱动程序。基本内核实际地址和虚拟地址相同的事实允许编译到基本内核中的 FIQ 模式代码访问内核符号,而无需在从vmalloced 内存执行 FIQ 代码时进行复杂的运行时修复。对于主要在内核空间工作的人来说,“虚拟内存”意味着vmalloced 内存。很抱歉混淆了。
    • 您的回答仍然几乎完全是关于一些没有被问到的问题,对实际问题主题的覆盖范围极小。
    【解决方案3】:

    内核模块通常是为您的平台上可能没有的外围设备驱动程序实现的。这样,如果外设在平台上不可用,您就不会因为添加未使用的代码而消耗内存和 CPU 时间。

    【讨论】:

    • 这个问题不涉及内置驱动程序与模块,它涉及内核模块与用户空间。
    猜你喜欢
    • 2018-05-29
    • 2019-07-21
    • 2011-12-02
    • 2012-01-27
    • 1970-01-01
    • 1970-01-01
    • 2013-04-21
    • 1970-01-01
    • 2014-07-06
    相关资源
    最近更新 更多