热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

Linux内核是如何按需动态装载和卸掉模块

Linux内核是如何按需动态装载和卸掉模块--Linux通用技术-Linux编程与内核信息,下面是详情阅读。
Linux是单内核结构,也就是说, 它是一个大程序, 其中任一函数都可以访问公共
数据结构和其它函数调用。 (作为操作系统)另外一种可能的结构是多核式的, 各
功能块自成一体, 相互之间由严格的通信机制相连。单核结构在添加新模块时,一
种方法是重新调整设置,所以非常费时。 比如,你想在内核中加一个NCR 810 SCSI
的驱动程序, 你必须重新设置, 重建内核。这也有另外一个办法, Linux 允许动
态装载和卸掉模块. Linux 模块是一段可以在机器起动后任意时间被动态连接的代
码. 在不需要时, 它们可以被从内核中卸掉. 大多数Linux 模块是设备驱动程序或
伪设备驱动程序, 如网络驱动程序, 文件系统等.

你可以使用 insmod 和 rmmod 命令来装载和卸掉 Linux 模块, 内核自己也可以调
用内核驻留程序(Kerneld) 来按需要装载和卸掉模块.

按需动态装载模块可以使内核保持最小, 并更具灵活性. 我现在的 Intel 内核由于
大量使用动态装载模块, 只有 406 K 字节. 例如, 我很少用到 VFAT 文件系统,
所以我让 Linux 内核只在我装载 VFAT 分区时, 才自动上载 VFAT 文件系统. 当我
卸掉 VFAT 分区时, 内核会检测到, 并自动卸掉 VFAT 文件系统. 当测试新程序时
, 你如果不想每次都重建内核, 动态装载模块是非常有用的. 但是, 运用模块会多
消耗一些内存, 并对速度有一定影响. 并且模块装载程序是一段代码, 它的数据将
占用一部份内存. 这样还会造成不能直接访问内核资源, 效率不高的问题.

一旦 Linux 模块被装载后, 它就和一般内核代码一样, 对其它内核代码, 享受同样
的访问权限。换句话说, Linux 内核模块可以像其它内核代码, 或驱动程序一样使
系统崩溃。

模块可以使用内核资源,但首先它需知道怎样调用. 例如, 一个模块要调用 Kmalloc()
(内核内存分配程序). 但在模块建立时, 它并不知道到哪儿去找 Kmalloc(), 所以
在它被装载时, 内核必须先设定模块中所有 Kmalloc() 调用的函数指针. 内核有一
张所有资源调用的列表, 在模块被装载时, 内核重设所有资源调用的函数指针. Linux
允许栈式模块, 即一个模块调用另一个模块的函数. 例如, 由于 VFAT 文件系统可
以看成是 FAT 文件系统的超集, 所以 VFAT 文件系统模块需要调用 FAT 文件系统
提供的服务。一个模块调用另一模块的资源与调用内核资源很相似。唯一的不同是
被调用的模块需被先载入。一个模块被载入后,内核将修改它的内核符号表(KERAEL
SYMOBOL TABLE),加入新载入模块提 供的所有资源和符号。所以另一个模块被载入
时, 它就可以调用所有已载入模块提供的服务。

当卸掉一模块时,内核先确定该模块不会再被调用,然后通过某种方式通知它。在
该模块被内核卸掉以前,该模块须释放所有占用的系统资源。例如,内存或中断,
当模块被卸掉后,内核从内核符号表中删除所有该模块提供的资源。

如果模块代码不严谨,它将使整个操作系统崩溃。另一个问题,如果你载入的是为
其它版本服务的模块,那怎么办?例如,一个模块凋用一个内函数,但提供了错误
的输入参数,这将导致运行错误。但内核可以在模块被载入时选择性地通过严格版
本检查来杜绝这种现象。

载入模块有两种方法。第一种是通过INSTALL 命令来载入;

另一种更聪明的方法是在模块被调用时自动载入,这叫所需载入(DEMAND LOADING)。


例如,当用户在装一个不在内核中的文件系统,内核会自动调用内核驻 留程序(KERNELD)
来载入对应的处理模块。

内核驻留程序是一个具有超级用户极限的普通用户程序。当它被启动时(通常在系统

动时),它将打开一个和内核之间的进程间通信管道(IPC CHANNEL)。 内核将利用这

管道来通知进程驻留程序去完成各种任务。

内核驻留程序的主要任务是载入和卸掉模块,它也能完成其她一些任务。如按需打
开和关掉一条通过串口的 DDD LINK。KERNELD 自己并不完成这些任务。它将调用如

INSMOD 这样的命令来完成,KERNELD 只是一个内核的代理,协调完成各项任务。


载入模块时,INSMODE 命令必须先找到要被载入的模块。可所需载入的模块通常被
放在/LIB/MODULES/KERNEL-VERSION下,这些模块与一般系统程序都是已连接好的目
标代码,不同处在于模块是可重定位的映像文件。也就是说,模块并不是从一个固
定的地址开始执行的。模块可以是 a.out, 也可以是ELF格式的目标代码。INSMODE
通过一个有系统权限的调用来找到内核中可被调用的资源。

系统(资源)符号由名和值俩部份组成。内核用MODULE_LIST 指针指向其管理的所有
模块所串成的链表。内核的输出符号表在第一个MODULE 数据结构中,并不是内核所
有的符号都能被模块调用,可调用符号必须被加入输出符号表中,而输出符号表是
与内核一起编译连接的。例如,当一驱动程序想控制某一系统中断时,她需调用”
REQUEST_IRQ”这样一个系统函数,在我机器的内核中,它现在的值是0x0010cd30,
你可以看/PROC/KSYMS文件或用KSYMS 来查询。KSYMS 命令可以显示所有内核输出符
号的值,也可以显示载入模块的输出符号的值。当INSMOD 载入模块时,它先将模块
载入虚存,根据内核输出符号,重设所有内核资源函数调用的指针。即在模块的函
数调用处写入对应符号的物理地址。

当INSMOD 重设完内核输出符号的地址后,它将调用一个系统函数,要 求内核分配
足够的空间。内存就会分配一个新的MODULE 数据结构和足够的内存来装载这个新模
块,并把这个MODULE 数据结构放在模块链表的最后, 置成未初使化(UNINITALIZED)。


表12。1显示的是内核载入FAT 和VFAT 两模块后的模块链表。链表的第一模块并没
有显示出来,那是一个伪模块,只是用来记录内核的输出符号表。你可以用ISMOD命
令来列出所有载入模块及它们之间的关系。ISMOD只是格式化的输出记录内核链表的
/PROC/MODULES文件。INSMOD 可以访问内核分配给新载入模块的内存,它先将模块
写入这块内存,然后对它进行重定位处理,使模块可以从这个地址开始执行。由于
每次模块被载入时,无论在不在同一台机器上,都不大可能分配到相同的内存地址,
所以重定位(即重设它的函数指针)是必须的。

新载入模块也可以输出符号,INSMOD 会为这些符号建一个表。另外,每一个模块必
须有自己的初始和清理(即析构)函数。这两个函数不能被输出,但它的地址将在初
使化时由INSMOD 传给内核。

当一个新模块被载入内核时,它要更新系统符号表及被它调用的模块。内核中被调
用模块都需在其符号表的最后保留一列指向调用模块的指针。图12。1显示VFAT文件
系统依赖于FAT文件系统,所以,在FAT 模块中有一个指向VFAT 的指针,这个指针
是在VFAT被载入时加入的。内核将调用模块的初使化函数,如果成功,它将继续完
成安装新模块的任务。模块的清理函数的地址将被存在它的MODULE 数据结构中。当
模块被卸掉时,它将被调用。到这里模块的状态被置为“运行“(RUNNING)。

12。2 卸掉模块

用RMMOD命令可以卸掉一个指定模块,但按需载入模块没用时,它会被内核自动卸掉,
KERNELD每次被激活时,它会调用一个系统函数将所有没用的模块从内核中卸掉。例
如,如果你装了一个ISO9660的CDROM,并且它的文件系统是一个按需载入模块,那
么当你卸掉CDROM 后不久,ISO9660文件系统也会被从内核中卸掉。你可以在起动KERNELD
时,设置其被激活的时间间隔,我的KERNELD 每180秒被激活一次。

当还在被其他模块调用时,模块是不能被卸掉的。例如,当你还在用VFAT文件系统
时,VFAT模块不会被卸掉。当你看ISMOD 命令的输出时,你会发现每个模块都带有
一个计数器。这个计 数器记录依赖于该模块的模块数。在上面的例子中, VFAT 和
MSDOS 都依赖于FAT模块,所以FAT 模块的计数器为2,VFAT 和MODOS的都为1,表示
只有文件系统依赖于它们。如果我再装入一个VFAT文件系统,VFAT模块的计数器将
变成2。模块的计数器是它映像的第一个长字(LONGWORD)。

这个长字同时也记录了AUTOCLEAN 和 VISITED 两个标志,只有按需载入模块才用到
这两个标志。AUTOCLEAN用来使系统识别哪一个模块需被自动卸掉。VISITED 标志表
示该模块是否还在被其它模块调用。每次KERNELD 试图卸掉已没用的按需载入模块
时,系统检查所有模块。它只注意标为AUTOCLEAN并正在运行的模块,如果这个模块
没有设置VISTIED 标志,它将被卸掉。否则,系统就清掉VISTIED标志,并继续检查
下一模块。

当一个模块可以被卸掉时,系统会调用它的清理函数来释放它所占用的所有系统资
源。

该模块的MODULE数据结构将被标为DELEDTED,并从模块链表中去除,所有它依赖的
模块会修改它们的指针,表示该模块已不再依赖它们了。所有该模块占用的内存将
被释放掉。
推荐阅读
  • 本文比较了eBPF和WebAssembly作为云原生VM的特点和应用领域。eBPF作为运行在Linux内核中的轻量级代码执行沙箱,适用于网络或安全相关的任务;而WebAssembly作为图灵完备的语言,在商业应用中具有优势。同时,介绍了WebAssembly在Linux内核中运行的尝试以及基于LLVM的云原生WebAssembly编译器WasmEdge Runtime的案例,展示了WebAssembly作为原生应用程序的潜力。 ... [详细]
  • Nginx使用AWStats日志分析的步骤及注意事项
    本文介绍了在Centos7操作系统上使用Nginx和AWStats进行日志分析的步骤和注意事项。通过AWStats可以统计网站的访问量、IP地址、操作系统、浏览器等信息,并提供精确到每月、每日、每小时的数据。在部署AWStats之前需要确认服务器上已经安装了Perl环境,并进行DNS解析。 ... [详细]
  • 本文介绍了在rhel5.5操作系统下搭建网关+LAMP+postfix+dhcp的步骤和配置方法。通过配置dhcp自动分配ip、实现外网访问公司网站、内网收发邮件、内网上网以及SNAT转换等功能。详细介绍了安装dhcp和配置相关文件的步骤,并提供了相关的命令和配置示例。 ... [详细]
  • 近年来,大数据成为互联网世界的新宠儿,被列入阿里巴巴、谷歌等公司的战略规划中,也在政府报告中频繁提及。据《大数据人才报告》显示,目前全国大数据人才仅46万,未来3-5年将出现高达150万的人才缺口。根据领英报告,数据剖析人才供应指数最低,且跳槽速度最快。中国商业结合会数据剖析专业委员会统计显示,未来中国基础性数据剖析人才缺口将高达1400万。目前BAT企业中,60%以上的招聘职位都是针对大数据人才的。 ... [详细]
  • 本文介绍了数据库的存储结构及其重要性,强调了关系数据库范例中将逻辑存储与物理存储分开的必要性。通过逻辑结构和物理结构的分离,可以实现对物理存储的重新组织和数据库的迁移,而应用程序不会察觉到任何更改。文章还展示了Oracle数据库的逻辑结构和物理结构,并介绍了表空间的概念和作用。 ... [详细]
  • Linux重启网络命令实例及关机和重启示例教程
    本文介绍了Linux系统中重启网络命令的实例,以及使用不同方式关机和重启系统的示例教程。包括使用图形界面和控制台访问系统的方法,以及使用shutdown命令进行系统关机和重启的句法和用法。 ... [详细]
  • 本文主要讨论了在xps15上安装双系统win10和MacOS后,win10无法正常更新的问题。分析了可能的引导问题,并提供了解决方法。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • 树莓派Linux基础(一):查看文件系统的命令行操作
    本文介绍了在树莓派上通过SSH服务使用命令行查看文件系统的操作,包括cd命令用于变更目录、pwd命令用于显示当前目录位置、ls命令用于显示文件和目录列表。详细讲解了这些命令的使用方法和注意事项。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • Python语法上的区别及注意事项
    本文介绍了Python2x和Python3x在语法上的区别,包括print语句的变化、除法运算结果的不同、raw_input函数的替代、class写法的变化等。同时还介绍了Python脚本的解释程序的指定方法,以及在不同版本的Python中如何执行脚本。对于想要学习Python的人来说,本文提供了一些注意事项和技巧。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 图解redis的持久化存储机制RDB和AOF的原理和优缺点
    本文通过图解的方式介绍了redis的持久化存储机制RDB和AOF的原理和优缺点。RDB是将redis内存中的数据保存为快照文件,恢复速度较快但不支持拉链式快照。AOF是将操作日志保存到磁盘,实时存储数据但恢复速度较慢。文章详细分析了两种机制的优缺点,帮助读者更好地理解redis的持久化存储策略。 ... [详细]
author-avatar
ZhuJiongJiongnu_441
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有