1. kernel module
loadable kernel module (LKM) 可加载内核模块
LKM通常用于添加对新硬件(作为设备驱动程序)和/或文件系统的支持,或用于添加系统调用。
当不再需要LKM提供的功能时,可以卸载它以释放内存和其他资源。
目前大多数类Unix系统和微软的Windows都支持可装载内核模块,虽然他们可能会使用不同的名称:
- loadable kernel module (LKM) in Linux, 可加载内核模块
- kernel loadable module (kld) in FreeBSD, 内核可加载模块
- kernel extension (kext) in macOS, 内核扩展(Apple)
- kernel extension module in AIX, 内核扩展模块(IBM)
- kernel-mode driver in Windows NT, 内核模式驱动(Microsoft)
- downloadable kernel module (DKM) in VxWorks, 可下载内核模块
- kernel loadable modules (or KLM), 内核可加载模块
- and simply as kernel modules (KMOD). 内核模块
2. Linux kernel module
Linux内核是一个自由和开放源码,单片,类Unix 操作系统 内核。负责管理计算机硬件资源。
操作系统中的实现
Linux中的可加载内核模块由modprobe命令加载(和卸载)。
内核模块文件位于/lib/modules中,从2.6版开始使用扩展名.ko(“内核对象”)(以前的版本使用.o扩展名)。
$ ls -Rl /lib/modules/5.1.15-arch1-1-ARCH //列出所有内核模块
在紧急情况下,当系统由于模块损坏而无法启动时,可以通过修改内核启动参数列表来启用或禁用特定模块
(例如,如果使用GRUB,则通过在GRUB开始菜单中按“e”,然后编辑内核参数行)。
2.1 管理模块的实用程序。
- insmod 加载内核模块的简单程序。建议使用modprobe (8), 这更聪明,可以处理模块依赖。
- rmmod 卸载(可卸载内核模块)的简单程序。建议使用(modprobe -r)。
-
lsmod 列出当前加载的内核模块,(地格式化/proc/modules的内容).
- $ lsmod
- $ cat /proc/modules
-
depmod 输出适合modprobe实用程序的依赖项列表。(生成modules.dep和映射文件)
- $ cat /lib/modules/‘uname -r‘/modules.dep
- $ cat /lib/modules/5.1.15-arch1-1-ARCH/modules.dep
- modprobe 在Linux内核中加载/卸载模块, 可自动加载依赖模块。
- modinfo 显示有关Linux内核模块的信息
modinfo(8)可用于从模块本身提取模块的依赖关系,但不知道别名或安装命令。
仅报告最常见的错误消息:由于尝试链接模块的工作现在在内核中完成,因此dmesg通常会提供有关错误的更多信息。
2.1.1 depmod 选项
depmod将输出适合modprobe实用程序的依赖项列表。
-a, | --all | Probe all modules | 探测所有模块 (默认选项) |
-A, | --quick | Only does the work if there‘s a new module | 只有在有新模块时才能工作 |
-e, | --errsyms | Report not supplied symbols | 报告未提供符号 |
-n, | --show | Write the dependency file on stdout only | 仅在stdout上写入依赖文件 |
-P, | --symbol-prefix | Architecture symbol prefix | 建筑符号前缀. 指定要忽略的前缀字符 (例如"_")。 |
-C, | --config=PATH | Read configuration from PATH | 从PATH中读取配置 |
-v, | --verbose | Enable verbose mode | 启用详细模式. 打印(stdout)每个模块所依赖的所有符号以及提供该符号的模块文件名。 |
-w, | --warn | Warn on duplicates | 警告重复的依赖项,别名,符号版本等。 |
-V, | --version | show version | 显示版本 |
-h, | --help | show this help | 显示这个帮助 |
以下选项对于管理分发的人员非常有用:
-b, | --basedir=DIR | If your modules are not currently in the (normal) directory /lib/modules/version, but in a staging area, you can specify a basedir which is prepended to the directory name. This basedir is stripped from the resulting modules.dep file, so it is ready to be moved into the normal location. Use this option if you are a distribution vendor who needs to pre-generate the meta-data files rather than running depmod again later. |
使用模块树的图像。 如果您的模块当前不在(普通)目录/lib/modules/version中,而是在暂存区域中,则可以指定一个基于目录名称的b??asedir。从生成的modules.dep文件中删除此basedir,因此可以将其移动到正常位置。如果您是需要预生成元数据文件而不是稍后再次运行depmod的分发供应商,请使用此选项。 |
-e, | --errsyms | When combined with the -F option, this reports any symbols which a module needs which are not supplied by other modules or the kernel. Normally, any symbols not provided by modules are assumed to be provided by the kernel (which should be true in a perfect world), but this assumption can break especially when additionally updated third party drivers are not correctly installed or were built incorrectly. |
报告未提供符号 与-F选项结合使用时,会报告模块需要的任何符号,这些符号不是由其他模块或内核提供的。通常,模块未提供的任何符号都假定由内核提供(在完美的世界中应该是真的),但是当额外更新的第三方驱动程序未正确安装或构建不正确时,此假设可能会中断。 |
-F, | --filesyms=FILE | Supplied with the System.map produced when the kernel was built, this allows the -e option to report unresolved symbols. This option is mutually incompatible with -E. |
使用该文件而不是当前的内核符号。 随内核生成时生成的System.map一起提供,这允许-e选项报告未解析的符号。此选项与-E互不兼容。 |
-E, | --symvers=FILE | When combined with the -e option, this reports any symbol versions supplied by modules that do not match with the symbol versions provided by the kernel in its Module.symvers. This option is mutually incompatible with -F. |
使用Module.symvers文件检查符号版本。 与-e选项结合使用时,会报告模块提供的任何符号版本,这些符号版本与其Module.symvers中内核提供的符号版本不匹配。此选项与-F互不兼容。 |
2.1.2 modprobe 选项
Management Options:
-a, | --all | Consider every non-argument to be a module name to be inserted or removed (-r) | 载入全部的模块。将每个非参数视为要插入或删除的模块名称(-r) |
-r, | --remove | Remove modules instead of inserting | 删除模块而不是插入 |
--remove-dependencies | Also remove modules depending on it | 此外,根据它删除模块 | |
-R, | --resolve-alias | Only lookup and print alias and exit | 打印与别名匹配的所有模块名称。 |
--first-time | Fail if module already inserted or removed | 如果已插入或删除模块,则失败 | |
-i, | --ignore-install | Ignore install commands | 忽略安装命令 |
-i, | --ignore-remove | Ignore remove commands | 忽略删除命令 |
-b, | --use-blacklist | Apply blacklist to resolved alias. | 将黑名单应用于已解决的别名。通常由udev(7)使用。 |
-f, | --force | Force module insertion or removal. Implies --force-modversions and –force-vermagic |
强制模块插入或移除。 (保护机制 谨慎使用) 暗示--force-modversions和-force-vermagic |
--force-modversion | Ignore module‘s version | 忽略模块的版本 (保护机制 谨慎使用) | |
--force-vermagic | Ignore module‘s version magic | 忽略模块的版本魔力(保护机制 谨慎使用) |
Query Options:
-D, | --show-depends | Only print module dependencies and exit | 打印模块依赖项. 以“insmod”开头,通常由分发使用,以确定生成initrd/initramfs映像时要包含哪些模块。 |
-c, | --showconfig | Print out known configuration and exit | 打印已知配置并退出 arch:(wc -l 43700) |
--show-modversions | Dump module symbol version and exit | 转储模块符号版本并退出 ( --dump-modversions) | |
--show-exports | Only print module exported symbol versions and exit | 仅打印模块导出符号版本并退出 |
General Options:
-n, | --dry-run --show | Do not execute operations, just print out | 不要执行操作,只需打印出来。与-v结合使用,可用于调试问题。 |
-C, | --config=FILE | Use FILE instead of default search paths | 使用FILE而不是默认搜索路径。会覆盖缺省配置目录(/etc/modprobe.d)。 |
-d, | --dirname=DIR | Use DIR as filesystem root for /lib/modules | 使用DIR作为/lib/modules的文件系统根目录 |
-S, | --set-version=VERSION | Use VERSION instead of `uname -r` | 使用VERSION而不是`uname -r` (它决定了在哪里找到模块) |
-s, | --syslog | print to syslog, not stderr | 打印到syslog,而不是stderr。当stderr不可用时,也会自动启用此功能。 |
-q, | --quiet | disable messages | 禁用消息 但仍将以非零退出状态返回。内核使用它来机会性地探测使用request_module可能存在的模块。 |
-v, | --verbose | enables more messages | 启用更多消息 |
-V, | --version | show version | 显示版本 |
-h, | --help | show this help | 显示这个帮助 |
2.1.3 modinfo 选项
-a, | --author | Print only ‘author‘ | 仅打印‘作者‘ |
-d, | --description | Print only ‘description‘ | 仅打印‘描述‘ |
-l, | --license | Print only ‘license‘ | 仅打印‘许可‘ |
-p, | --parameters | Print only ‘parm‘ | 仅打印‘参数‘ |
-n, | --filename | Print only ‘filename‘ | 仅打印‘文件名‘ |
-0, | --null | Use \0 instead of \n | 使用\0(ASCII零字符)分隔字段,而不是\n换行. |
-F, | --field=FIELD | Print only provided FIELD | 仅打印提供FIELD, (author, description, license, parm, depends, alias) |
-k, | --set-version=VERSION | Use VERSION instead of ‘uname -r‘ | 使用VERSION而不是‘uname -r‘ |
-b, | --basedir=DIR | Use DIR as filesystem root for /lib/modules | 使用DIR作为/lib/modules的文件系统根目录 |
-V, | --version | Show version | 显示版本 |
-h, | --help | Show this help | 显示此帮助 |
2.2 内核目录
/lib/modules/‘uname -r‘/
$ ls -Rl /lib/modules/5.1.15-arch1-1-ARCH/ |grep ko.xz |wc -l //列出所有内核模块,这里的arch里有 5474个
$ lsmod |wc -l //当前arch系统加载的有96个。
$ ls -l /lib/modules/‘uname -r‘/
$ ls -l /lib/modules/5.1.15-arch1-1-ARCH/
size | /lib/modules/’uname -r’/ | 描述 n/示例内容 | wc -l |
213.9 kb | modules.order | (.ko) 模块 [清单] kernel/drivers/gpu/drm/i915/i915.ko |
5474 |
685.4 kb | modules.dep | (.ko.xz) 所有模块路径及 [依赖] 关系 kernel/drivers/gpu/drm/i915/i915.ko.xz: kernel/drivers/gpu/drm/drm.ko.xz ...(9个文件) |
5474 |
919.6 kb | modules.dep.bin | ||
1.4 Mb | modules.alias | 从模块本身提取的 [别名]. modinfo -F alias alias pci:v00008086d00008A70sv*sd*bc03sc*i* i915 (...239行) |
30142 (3850) |
1.4 Mb | modules.alias.bin | ||
576.8 kb | modules.symbols | [符号] 别名,由symbol_request()使用。 alias symbol:i915_gpu_raise i915 (...7行) |
13526 (1207) |
705 kb | modules.symbols.bin | ||
5.2 kb | modules.builtin | (.ko) [内置] kernel/kernel/configs.ko |
161 |
6.9 kb | modules.builtin.bin | ||
0.4 kb | modules.devname | 触发按需加载模块的 [设备节点]。 fuse fuse c10:229 |
17 |
0.8 kb | modules.softdep | 从模块本身提取的 [软依赖项]。 softdep ext4 pre: crc32c |
26 |
2.3 查看linux内核模块依赖关系的n种方法
2.3.1 lsmod 命令 (仅载入的部分)
$ lsmod |grep i915
i915 2166784 11
i2c_algo_bit 16384 1 i915
drm_kms_helper 212992 1 i915
drm 495616 8 drm_kms_helper,i915
intel_gtt 24576 2 intel_agp,i915
2.3.2 modinfo -F depends 命令 (仅载入的部分)
$ sudo modinfo i915 -F depends
drm,drm_kms_helper,intel-gtt,i2c-algo-bit
2.3.3 cat modules.dep 文件
$ cat /lib/modules/5.1.15-arch1-1-ARCH/modules.dep |grep i915
kernel/drivers/gpu/drm/i915/i915.ko.xz:
kernel/drivers/i2c/algos/i2c-algo-bit.ko.xz
kernel/drivers/gpu/drm/drm_kms_helper.ko.xz
kernel/drivers/gpu/drm/drm.ko.xz
kernel/drivers/char/agp/intel-gtt.ko.xz
kernel/drivers/char/agp/agpgart.ko.xz
kernel/drivers/video/fbdev/core/syscopyarea.ko.xz
kernel/drivers/video/fbdev/core/sysfillrect.ko.xz
kernel/drivers/video/fbdev/core/sysimgblt.ko.xz
kernel/drivers/video/fbdev/core/fb_sys_fops.ko.xz
2.3.4 modprobe -D 命令
$ sudo modprobe -D i915
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/video/fbdev/core/fb_sys_fops.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/video/fbdev/core/sysimgblt.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/video/fbdev/core/sysfillrect.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/video/fbdev/core/syscopyarea.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/char/agp/agpgart.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/char/agp/intel-gtt.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/gpu/drm/drm.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/gpu/drm/drm_kms_helper.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/i2c/algos/i2c-algo-bit.ko.xz
insmod /lib/modules/5.1.15-arch1-1-ARCH/kernel/drivers/gpu/drm/i915/i915.ko.xz
2.4 查看其他信息
2.4.1 符号信息
$ cat /lib/modules/5.1.15-arch1-1-ARCH/modules.symbols |grep i915
alias symbol:i915_gpu_lower i915
alias symbol:i915_gpu_raise i915
alias symbol:i915_gpu_busy i915
alias symbol:i915_gpu_turbo_disable i915
alias symbol:i915_read_mch_val i915
alias symbol:intel_gvt_register_hypervisor i915
alias symbol:intel_gvt_unregister_hypervisor i915
alias symbol:snd_hdac_i915_set_bclk snd_hda_core
alias symbol:snd_hdac_i915_init snd_hda_core
alias symbol:ips_link_to_i915_driver intel_ips
2.4.2 别名
sudo modinfo i915 -F alias |wc -l
239
cat /lib/modules/5.1.15-arch1-1-ARCH/modules.alias |grep i915 |wc -l
239
2.4.3 模块配置信息
$ sudo modprobe -c |grep i915 |wc -l249
看起来,配置信息就是别名和符号信息了。
$ cat /lib/modules/5.1.15-arch1-1-ARCH/modules.alias |grep i915 |wc -l
239
$ cat /lib/modules/5.1.15-arch1-1-ARCH/modules.symbols |grep i915 |wc -l
10
所有模块配置信息
$ modprobe -c | less
2.4.4 显示一个装入模块使用的选项
$ sudo systool -v -m i915Module = "i915"
Attributes:
coresize = "2166784"
initsize = "0"
initstate = "live"
refcnt = "11"
srcversion = "8352F0188F789229AD1F3A8"
taint = ""
uevent = <store method only>
Parameters:
alpha_support = "Y"
...
Sections:
.altinstr_aux = "0xffffffffc0bf6ad5"
...
2.4.5 配置文件目录及文件
以下是当前的arch linux/etc/modprobe.d/
/etc/modules-load.d/
/etc/mkinitcpio.d/
/etc/mkinitcpio.d/linux.preset
/etc/mkinitcpio.conf
2.5 加载模块
2.5.1 自动处理
目前,所有必要模块的加载均由 udev 自动完成。所以,如果不需要使用任何额外的模块,就没有必要在任何配置文件中添加启动时加载的模块。
但是,有些情况下可能需要在系统启动时加载某个额外的模块,或者将某个模块列入黑名单以便使系统正常运行。
systemd 读取 /etc/modules-load.d/ 中的配置加载额外的内核模块。
配置文件名称通常为 /etc/modules-load.d/<program>.conf。
格式很简单,一行一个要读取的模块名,而空行以及第一个非空格字符为#或;的行会被忽略,如:
/etc/modules-load.d/virtio-net.conf
# Load virtio-net.ko at boot
virtio-net
2.5.2 手动加载卸载
控制内核模块载入/移除的命令是kmod 软件包提供的, 要手动装入模块的话,执行:# modprobe module_name
如果要移除一个模块:
# modprobe -r module_name
2.6 配置模块参数
要将参数传递给内核模块,可以使用modprobe手动传递它们,或者确保始终使用modprobe配置文件或使用内核命令行应用某些参数。2.6.1 使用modprobe手动加载时设置
传递参数的基本方式是使用 modprobe 选项,格式是 key=value:# modprobe module_name parameter_name=parameter_value
2.6.2 使用 /etc/modprobe.d/中的文件
/etc/modprobe.d/目录中的文件可用于将模块设置传递给udev,udev将用于modprobe管理系统引导期间模块的加载。此目录中的配置文件可以具有任何名称,前提是它们以.conf扩展名结尾。比如:/etc/modprobe.d/thinkfan.conf
# On thinkpads, this lets the thinkfan daemon control fan speed
options thinkpad_acpi fan_control=1
注意:如果从initramfs加载了任何受影响的模块,那么您需要在mkinitcpio.conf中添加相应的.conf文件或使用钩子,以便它将包含在initramfs中。
要查看默认initramfs的内容使用。FILES modconf lsinitcpio /boot/initramfs-linux.img
2.6.3 使用内核命令行
如果模块直接编译进内核,也可以通过启动管理器(GRUB, LILO 或 Syslinux)的内核行加入参数:例如:
thinkpad_acpi.fan_control=1
2.7 别名的操作
别名是模块的备用名称。例如:alias my-mod really_long_modulename意味着您可以使用modprobe my-mod而不是modprobe really_long_modulename。您也可以使用shell样式的通配符,因此alias my-mod* really_long_modulename意味着modprobe my-mod-something具有相同的效果。创建别名:/etc/modprobe.d/myalias.conf
alias mymod really_long_module_name
有些模块具有别名,以方便其它程序自动加载模块。禁用这些别名可以阻止自动加载,但是仍然可以手动加载。
/etc/modprobe.d/modprobe.conf
# Prevent autoload of bluetooth
alias net-pf-31 off
# Prevent autoload of ipv6
alias net-pf-10 off
2.8 黑名单
在内核模块的上下文中,黑名单是一种阻止内核模块加载的机制。例如,如果不需要关联的硬件,或者加载该模块会导致问题,这可能很有用:例如,可能有两个内核模块尝试控制同一块硬件,并将它们加载到一起会导致冲突。一些模块作为initramfs的一部分加载。
mkinitcpio -M 将打印出所有自动检测到的模块.
为防止initramfs加载其中一些模块,将它们列入“/etc/modprobe.d”下的“.conf”文件中(例如/etc/modprobe.d/modprobe.conf),并在 image 生成过程中通过“modconf”挂钩添加。
mkinitcpio -v 将列出由各种钩子(例如filesystems钩子,block钩子等)拉入的所有模块。
如果您的“HOOKS”数组中没有“modconf”挂钩(例如,您偏离了默认配置),请记住将“.conf”文件添加到“/etc/mkinitcpio.conf”中的“FILES”数组中 ),一旦你列入黑名单,模块就会重新生成initramfs,然后重新启动。
https://wiki.archlinux.org/index.php/Regenerate_the_initramfs
2.8.1 使用/etc/modprobe.d/中的文件
.conf在里面创建一个文件,/etc/modprobe.d/并使用blacklist关键字为要列入黑名单的每个模块添加一行。例如,如果要阻止pcspkr模块加载:/etc/modprobe.d/nobeep.conf
# Do not load the pcspkr module on boot
blacklist pcspkr
注意: blacklist 命令将屏蔽一个模板,所以不会自动加载,但是如果其它非屏蔽模块需要这个模块,系统依然会加载它。
要避免这个行为,可以让 modprobe 使用自定义的 install 命令,直接返回导入失败:
/etc/modprobe.d/blacklist.conf
...
install MODULE /bin/false
...
这样就可以 "屏蔽" 模块及所有依赖它的模块。
2.8.2 使用内核命令行
提示:如果损坏的模块无法启动系统,这将非常有用。在引导加载程序中(位于 GRUB、LILO 或 Syslinux)将模块列入黑名单。
只需添加module_blacklist=modname1,modname2,modname3到引导加载程序的内核行,如内核参数中所述。
https://wiki.archlinux.org/index.php/Kernel_parameters
注意:当您将多个模块列入黑名单时,请注意它们仅以逗号分隔。[空格]或其他任何东西都可能会破坏语法。
2.8.3 常用参数
parameter | Description | 描述 |
root= | Root filesystem. See init/do_mounts.c for supported device name formats. | 根文件系统。有关支持的设备名称格式,请参阅init/do_mounts.c。 |
rootflags= | Root filesystem mount options. | 根文件系统挂载选项。 |
ro | Mount root device read-only on boot (default1). | 在启动时将根设备设置为只读(默认值为1)。 |
rw | Mount root device read-write on boot. | 在启动时挂载根设备读写。 |
initrd= | Specify the location of the initial ramdisk. | 指定初始ramdisk的位置。 |
init= | Run specified binary instead of /sbin/init as init process. The systemd-sysvcompat package symlinks /sbin/init to /usr/lib/systemd/systemd to use systemd. |
运行指定的二进制文件而不是/sbin/initinit进程。 该systemd-sysvcompat包符号连接/sbin/init到/usr/lib/systemd/systemd使用systemd。 |
init=/bin/sh | Boot to shell. | 引导到shell。 |
systemd.unit= | Boot to a specified target. | 引导到指定目标。 |
resume= | Specify a swap device to use when waking from hibernation. | 指定从休眠状态唤醒时要使用的交换设备。 |
nomodeset | Disable Kernel mode setting. | 禁用内核模式设置。 |
zswap.enabled | Enable Zswap. | 启用Zswap。 |
panic= | Time before automatic reboot on kernel panic. | 在内核崩溃上自动重启之前的时间。 |
debug | Enable kernel debugging (events log level). | 启用内核调试(事件日志级别)。 |
mem= | Force usage of a specific amount of memory to be used. | 强制使用特定数量的内存。 |
maxcpus= | Maximum number of processors that an SMP kernel will bring up during bootup. | 启动期间SMP内核将提供的最大处理器数。 |
selinux= | Disable or enable SELinux at boot time. | 在引导时禁用或启用SELinux。 |
netdev= | Network devices parameters. | 网络设备参数。 |
video= | Override framebuffer video defaults. | 覆盖帧缓冲视频默认值。 |
完整的内核参数
https://www.kernel.org/doc/Documentation/admin-guide/kernel-parameters.txt
module_blacklist= [KNL] Do not load a comma-separated list of modules. Useful for debugging problem modules.
2.9 故障排除
模块无法加载如果某个特定模块未加载且启动日志(可访问journalctl -b)表示该模块已列入黑名单,但该目录/etc/modprobe.d/未显示相应的条目,请检查另一个modprobe源文件夹以/usr/lib/modprobe.d/查找列入黑名单的条目。
如果内核模块中包含的“vermagic”字符串与当前运行的内核的值不匹配,则不会加载模块。如果已知模块与当前运行的内核兼容,则可以忽略“vermagic”检查modprobe --force-vermagic。
警告:忽略内核模块的版本检查可能会导致内核崩溃或系统因不兼容而出现未定义的行为。请务必--force-vermagic谨慎使用。
3. 内核模块与应用程序的区别
3.1 模块代码
传统计算机程序的运行生命周期相当简单。加载器为程序分配内存,然后加载程序和所需要的动态链接库。指令从一些入口开始执行(传统 C/C++ 程序以 main() 函数作为入口),语句被执行,异常被抛出,动态内存被分配和释放,程序最终运行完成。当程序退出时,操作系统识别任何内存泄露,并释放到内存池。
3.2 内核模块和普通应用程序的区别有:
> 内核模块不是应用程序,从一开始就没有 main() 函数。
> 非顺序执行:内核模块使用初始化函数将自身注册并处理请求,初始化函数运行后就结束了。内核模块处理的请求在模块代码中定义。这和常用于图形用户界面(graphical-user interface,GUI)应用的事件驱动编程模型比较类似。
> 没有自动清理:任何由内核模块申请的内存,必须要模块卸载时手动释放,否则这些内存将无法使用,直到系统重启。
> 不要使用 printf() 函数:内核代码无法访问为 Linux 用户空间编写的库。内核模块运行在内核空间,它有自己独立的地址空间。内核空间和用户空间的接口被清晰的定义和控制。内核模块可以通过 printk() 函数输出信息,这些输出可以在用户空间查看到。
> 会被中断:内核模块一个概念上困难的地方在于他们可能会同时被多个程序 / 进程使用。构建内核模块时需要小心,以确保在发生中断的时候行为一致和正确。BeagleBone 有一个单核处理器(目前为止),但是我们仍然需要考虑多进程同时访问对模块的影响。
> 更高级的执行特权:通常内核模块会比用户空间程序分配更多的 CPU 周期。这看上去是一个优势,然而需要特别注意内核模块不会影响到系统的综合性能。
> 无浮点支持:对用户空间应用,内核代码使用陷阱(trap)来实现整数到浮点模式的转换。然而在内核空间中这些陷阱难以使用。替代方案是手工保存和恢复浮点运算,这是最好的避免方式,并将处理留给用户空间代码。
更多信息: