《费翔林Linux实验教程全套配套课件 第12章 内核模块》由会员分享,可在线阅读,更多相关《费翔林Linux实验教程全套配套课件 第12章 内核模块(56页珍藏版)》请在金锄头文库上搜索。
1、第第第第1212章章 内核模块内核模块章章 内核模块内核模块实验目的实验目的实验目的实验目的?了解内核模块的概念和特点了解内核模块的概念和特点了解内核模块的概念和特点了解内核模块的概念和特点实验目的实验目的实验目的实验目的了解内核模块的概念和特点了解内核模块的概念和特点了解内核模块的概念和特点了解内核模块的概念和特点?学习如何编写一个内核模块学习如何编写一个内核模块学习如何编写一个内核模块学习如何编写一个内核模块?掌握内核模块的实现机制掌握内核模块的实现机制,学会模块的加载和卸学会模块的加载和卸掌握内核模块的实现机制掌握内核模块的实现机制,学会模块的加载和卸学会模块的加载和卸?掌握内核模块的实
2、现机制掌握内核模块的实现机制,学会模块的加载和卸学会模块的加载和卸掌握内核模块的实现机制掌握内核模块的实现机制,学会模块的加载和卸学会模块的加载和卸载载载载主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识? ?内核模块概述内核模块概述内核模块概述内核模块概述? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?实验内容实验内容实验内容实验内容? ?通过内核模块显示进程控制块信息通
3、过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?内核模块内核模块内核模块内核模块内核模块内核模块内核模块内核模块? ?是在核心空间运行的一种目标文件,不能单独执行但其是在核心空间运行的一种目标文件,不能单独执行但其是在核心空间运行的一种目标文件,不能单独执行但其是在核心空间运行的一种目标文件,不能单独执行但其代码可在运行时链接到系统中
4、作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或代码可在运行时链接到系统中作为内核的一部分执行或卸载。卸载。卸载。卸载。LinuxLinux内核模块是一种特有的机制,它由一组函数内核模块是一种特有的机制,它由一组函数和数据结构组成,可作为独立程序来编译。和数据结构组成,可作为独立程序来编译。内核模块是一种特有的机制,它由一组函数内核模块
5、是一种特有的机制,它由一组函数和数据结构组成,可作为独立程序来编译。和数据结构组成,可作为独立程序来编译。? ?当模块被安装时,它被链接到内核中,可在系统启动时当模块被安装时,它被链接到内核中,可在系统启动时进行模块安装,称静态加载;也可在系统运行时进行模进行模块安装,称静态加载;也可在系统运行时进行模当模块被安装时,它被链接到内核中,可在系统启动时当模块被安装时,它被链接到内核中,可在系统启动时进行模块安装,称静态加载;也可在系统运行时进行模进行模块安装,称静态加载;也可在系统运行时进行模块安装块安装,称动态加载称动态加载。块安装块安装,称动态加载称动态加载。块安装块安装,称动态加载称动态加
6、载。块安装块安装,称动态加载称动态加载。内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?内核模块的主要作用内核模块的主要作用内核模块的主要作用内核模块的主要作用? ?是动态地增加或减少内核功能,许多情况下用户需要增是动态地增加或减少内核功能,许多情况下用户需要增加内核态程序。加内核态程序。是动态地增加或减少内核功能,许多情况下用户需要增是动态地增加或减少内核功能,许多情况下用户需要增加内核态程序。加内核态程序。?例如,添加一个文件系统或设备驱动程序,而这类程序运行在内核态,工作在核心空间,由于它们种类繁例如,添加一个文件系统或设备驱动程序,而这
7、类程序运行在内核态,工作在核心空间,由于它们种类繁多多、体积庞大体积庞大,要求内核全部包含进去是十分困难的要求内核全部包含进去是十分困难的多多、体积庞大体积庞大,要求内核全部包含进去是十分困难的要求内核全部包含进去是十分困难的,于是Linux提供了一种称为可动态加载和卸载的内核,于是Linux提供了一种称为可动态加载和卸载的内核模块模块(Loadable Kernel ModulesLoadable Kernel Modules,LKMLKM)机制机制,通过通过模块模块(LoadableLoadable KernelKernel ModulesModules,LKMLKM)机制机制,通过通过模
8、块机制来实现系统运行时对内核功能的动态扩充,模块机制来实现系统运行时对内核功能的动态扩充,就能大大提高单内核操作系统的灵活性与可扩展性就能大大提高单内核操作系统的灵活性与可扩展性。就能大大提高单内核操作系统的灵活性与可扩展性就能大大提高单内核操作系统的灵活性与可扩展性。内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?LinuxLinux内核模块内核模块LinuxLinux内核模块内核模块?是一个编译好的、具有特定格式的独立目标文件,用户可通过系统提供的一组与模块相关的命令将内核模块加是一个编译好的、具有特定格式的独立目标文件,用户可通过系统提供
9、的一组与模块相关的命令将内核模块加载进内核,当内核模块被加载后,它有以下特点:载进内核,当内核模块被加载后,它有以下特点:?1)与内核一起运行在相同的内核态和内核地址空间;1)与内核一起运行在相同的内核态和内核地址空间;?2)运行时具有与内核同样的特权级;2)运行时具有与内核同样的特权级;?3)可方便地访问内核中的各种数据结构。3)可方便地访问内核中的各种数据结构。内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?LinuxLinux内核模块内核模块LinuxLinux内核模块内核模块?被载入内核的内核模块代码与静态编译进内核的代码没有区别,内核
10、模块与内核中的其他模块交互只需采用函被载入内核的内核模块代码与静态编译进内核的代码没有区别,内核模块与内核中的其他模块交互只需采用函数调用,此外,内核模块还可以很容易地被移出内核,当用户不再需要某功能模块时,可以自动地将它从内核数调用,此外,内核模块还可以很容易地被移出内核,当用户不再需要某功能模块时,可以自动地将它从内核卸载以节省系统主存开销卸载以节省系统主存开销,配置十分灵活配置十分灵活。卸载以节省系统主存开销卸载以节省系统主存开销,配置十分灵活配置十分灵活。内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?LinuxLinux内核模块内核模
11、块LinuxLinux内核模块内核模块?Linux内核需要对载入的内核模块进行管理,管理内核模块主要有两项任务:Linux内核需要对载入的内核模块进行管理,管理内核模块主要有两项任务:?一是内核符号表管理;一是内核符号表管理;?二是维护内核模块的引用计数。二是维护内核模块的引用计数。?内核将资源登记在符号表中,当内核模块被加载后,模块可以通过符号表使用内核中的资源,内核将资源登记在符号表中,当内核模块被加载后,模块可以通过符号表使用内核中的资源,?新模块载入内核时,系统把新模块提供的符号加进符号表中,这样新载入模块就可访问已装载模块提供的新模块载入内核时,系统把新模块提供的符号加进符号表中,这
12、样新载入模块就可访问已装载模块提供的资源资源资源资源;?在卸载一个模块时,系统释放分配给该模块的所有系在卸载一个模块时,系统释放分配给该模块的所有系统资源统资源如内核主存区等如内核主存区等同时将该模块提供的符号同时将该模块提供的符号统资源统资源,如内核主存区等如内核主存区等,同时将该模块提供的符号同时将该模块提供的符号从符号表中删除。从符号表中删除。内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述内核模块概述?LinuxLinux内核模块内核模块LinuxLinux内核模块内核模块?由于所有内核模块在加载后都在同一地址空间中,内核模块之间可相互引用各自导出的
13、符号,因此内核模块之由于所有内核模块在加载后都在同一地址空间中,内核模块之间可相互引用各自导出的符号,因此内核模块之间会产生依赖性:间会产生依赖性:?如果A模块需要用到B模块导出的符号,而B模块没有被如果A模块需要用到B模块导出的符号,而B模块没有被载内核载内核A A块载会块载会载载入入内核内核的话,的话,A A模模块块的加的加载载就就会会出错;出错;?同样,一个内核模块如果有其他内核模块引用它导出同样,一个内核模块如果有其他内核模块引用它导出的符号的符号内核也不允许该内核模块被卸载内核也不允许该内核模块被卸载内核模块内核模块的符号的符号,内核也不允许该内核模块被卸载内核也不允许该内核模块被卸
14、载,内核模块内核模块的引用计数器便用来管理内核模块之间的依赖性。的引用计数器便用来管理内核模块之间的依赖性。?如果一个内核模块被依赖如果一个内核模块被依赖它的引用计数就会增加它的引用计数就会增加;?如果一个内核模块被依赖如果一个内核模块被依赖,它的引用计数就会增加它的引用计数就会增加;当依赖减少时,相应的引用计数也会减少;一个内核当依赖减少时,相应的引用计数也会减少;一个内核模块模块只只有在引用计数为有在引用计数为0 0时候才允许被卸载时候才允许被卸载。模块有在引用计数为模块有在引用计数为0 0时候才允许被卸载时候才允许被卸载主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识主
15、要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识? ?内核模块概述内核模块概述内核模块概述内核模块概述? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?实验内容实验内容实验内容实验内容? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息内核模块编
16、程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?内核模块的结构内核模块的结构?编写“Hello,world!编写“Hello,world!”内核模块内核模块内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?内核模块的结构内核模块的结构?编写“Hello,world!编写“Hello,world!”内核模块内核模块内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?编译与加载编译与加载?在在v2.6中,编译、链接后生成的内核模块后缀为中,编译、链接后生成的内核模块
17、后缀为.ko,编译过程中首先会到内核源代码目录下,读取顶层,编译过程中首先会到内核源代码目录下,读取顶层k fil 文件文件,然后返回模块源代码所在的目录继续编然后返回模块源代码所在的目录继续编makefile文件文件,然后返回模块源代码所在的目录继续编然后返回模块源代码所在的目录继续编译。译。?编译内核模块的编译内核模块的k fil ,只需要下面一行只需要下面一行:?编译内核模块的编译内核模块的makefile,只需要下面一行只需要下面一行:?obj-m:=hello.oobj-m:=hello.o?生成的内核模块为生成的内核模块为hello ko。?生成的内核模块为生成的内核模块为hell
18、o.ko。?如果需要生成一个名为如果需要生成一个名为mymodule.ko的内核模块,并且的内核模块,并且该内核模块的源代码来源于该内核模块的源代码来源于modulesrc1.c和和该内核模块的源代码来源于该内核模块的源代码来源于modulesrc1.c和和modulesrc2.c两个文件,两个文件,makefile应该写成如下形式:应该写成如下形式:?obj-m:=mymodule.oobj-m:=mymodule.o?module-objs:=modulesrc1.o modulesrc2.omodule-objs:=modulesrc1.o modulesrc2.o内核模块编程内核模块编
19、程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?编译与加载编译与加载?如果用户采用这种makefile,在调用make命令时,需要将内核源代码所在目录作为一个参数传递给make命令。如果用户采用这种makefile,在调用make命令时,需要将内核源代码所在目录作为一个参数传递给make命令。?例如,如果v2.6的内核源代码位于/usr/src/linux-2.6下,用户模块源代码所在目录应该使用的make命令为:例如,如果v2.6的内核源代码位于/usr/src/linux-2.6下,用户模块源代码所在目录应该使用的make命令为:makemake- -C/usr
20、/src/linuxC/usr/src/linux- -2.6 M=pwdmodules2.6 M=pwdmodules?makemake- -C/usr/src/linuxC/usr/src/linux- -2.62.6 M=pwdmodulesM=pwdmodules内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?编译与加载编译与加载makefilemakefile还提供另一种形式还提供另一种形式,用户可指定内核源代码所在用户可指定内核源代码所在?makefilemakefile还提供另一种形式还提供另一种形式,用户可指定内核源代码所在用户
21、可指定内核源代码所在的目录。的目录。?对于对于“hellohello world!world!”例子例子,在在makefilemakefile中指定内核源代中指定内核源代对于对于“hello world!hello world! 例子例子,在在makefilemakefile中指定内核源代中指定内核源代码的方式为码的方式为:/*如果定义了KERNELRELEASE宏,则可直接通过配置内核的内核源代/*如果定义了KERNELRELEASE宏,则可直接通过配置内核的内核源代码目录编译文件码目录编译文件* */ /码目录编译文件码目录编译文件* */ /ifneq($(KERNELRELEASE),
22、)obj-m:= hello.o ifneq($(KERNELRELEASE),)obj-m:= hello.o elseelseelseelse/*否则,需要从命令行获取配置内核的内核源代码目录信息,并编译文件*/*否则,需要从命令行获取配置内核的内核源代码目录信息,并编译文件*/KERNELDIR ?= /lib/modules/$(shell unameKERNELDIR ?= /lib/modules/$(shell uname - -r)/buildr)/buildKERNELDIRKERNELDIR ?=?= /lib/modules/$(shell/lib/modules/$(s
23、hell unameuname - -r)/buildr)/buildPWD:= $(shell pwd) default:PWD:= $(shell pwd) default:$(MAKE)$(MAKE)- -C$(KERNELDIR) M=$(PWD) modulesC$(KERNELDIR) M=$(PWD) modules$(MAKE)$(MAKE)- -C$(KERNELDIR)C$(KERNELDIR) M=$(PWD)M=$(PWD) modulesmodulesendif endif 内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编
24、程?编译与加载编译与加载编译与加载编译与加载?在这个makefile中,KERNELDIR指定内核的源代码目录,该目录通过当前运行内核使用的模块目录中的build符号在这个makefile中,KERNELDIR指定内核的源代码目录,该目录通过当前运行内核使用的模块目录中的build符号链接指定。链接指定。?当编译好内核模块后,用户以超级用户身份就可将内核模当编译好内核模块后,用户以超级用户身份就可将内核模块加载到内核中块加载到内核中。块加载到内核中块加载到内核中。?内核提供modutils软件包供用户对内核模块进行管理,该内核提供modutils软件包供用户对内核模块进行管理,该软件包安装后会
25、在软件包安装后会在/sbin/sbin目录下安装目录下安装insmodinsmod、rmmodrmmod、软件包安装后会在软件包安装后会在/sbin/sbin目录下安装目录下安装insmodinsmod、rmmodrmmod、ksyms、lsmod、modprobe等实用程序ksyms、lsmod、modprobe等实用程序内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?编译与加载编译与加载?insmod命令insmod命令?把需要载入的模块以目标代码形式加载进内核中,把需要载入的模块以目标代码形式加载进内核中,insmod自动调用module
26、s_init( )函数中定义的过程运行,超级用户使用这个命令,其格式为:insmod自动调用modules_init( )函数中定义的过程运行,超级用户使用这个命令,其格式为:# insmod pathmodulename# insmod pathmodulename# # insmodinsmod pathmodulenamepathmodulename?rmmod命令rmmod命令rmmodrmmod?将已经载入内核的模块从内核中卸载,将已经载入内核的模块从内核中卸载,rmmodrmmod自动调用modules_exit( )函数中定义的过程运行,命令格式为自动调用modules_exit
27、( )函数中定义的过程运行,命令格式为# rmmod pathmodulename# rmmod pathmodulename# # rmmodrmmod pathmodulenamepathmodulename内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?编译与加载编译与加载编译与加载编译与加载?ksyms命令ksyms命令?用用来来显示内核显示内核符符号和模块号和模块符符号信号信息息。来符符息来符符息?lsmod命令lsmod命令?显示已经显示已经载载入入内内核核的所有模块的所有模块信信息息,包包括括被载被载入入模块的模块的载内的所有模块
28、息载内的所有模块息包被载模块的包被载模块的模块名、大小和引用计数等,命令格式为:模块名、大小和引用计数等,命令格式为:# lsmod# lsmod?对于本节中的hello模块,超级用户可用以下命令加载模块:对于本节中的hello模块,超级用户可用以下命令加载模块:#insmod hello.ko#insmod hello.ko内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?内核符号表内核符号表?是一个用来存放所有模块可以访问的符号,以及对应地址的特殊数据结构,模块的链接是将模块插入到内核的过程是一个用来存放所有模块可以访问的符号,以及对应地址的
29、特殊数据结构,模块的链接是将模块插入到内核的过程,模块所导出的符号都将成为内核符号表的一部分模块所导出的符号都将成为内核符号表的一部分。模块模块,模块所导出的符号都将成为内核符号表的一部分模块所导出的符号都将成为内核符号表的一部分。模块模块根据符号表从核心空间获取主存地址,从而确保在核心空根据符号表从核心空间获取主存地址,从而确保在核心空间中正确地运行间中正确地运行,对于从模块中导出的符号对于从模块中导出的符号,在符号表中在符号表中间中正确地运行间中正确地运行,对于从模块中导出的符号对于从模块中导出的符号,在符号表中在符号表中会包含第3列“所属模块”,在v2.6内核中,用户可从会包含第3列“所
30、属模块”,在v2.6内核中,用户可从/proc/kallsyms/proc/kallsyms中以文本方式读取内核符号表中以文本方式读取内核符号表。/proc/kallsyms/proc/kallsyms中以文本方式读取内核符号表中以文本方式读取内核符号表。内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?内核符号表内核符号表?在v2.4内核中,缺省情况下,模块中的非静态全局变量及函数在模块加载后会输出到内核符号表,而在v2.6内核中在v2.4内核中,缺省情况下,模块中的非静态全局变量及函数在模块加载后会输出到内核符号表,而在v2.6内核中,缺省情
31、况下缺省情况下,这些符号不会被输出到内核符号表中这些符号不会被输出到内核符号表中。如如,缺省情况下缺省情况下,这些符号不会被输出到内核符号表中这些符号不会被输出到内核符号表中。如如果模块需要导出符号供其他模块使用,应该使用下面定义果模块需要导出符号供其他模块使用,应该使用下面定义的两个宏的两个宏:的两个宏的两个宏:?EXPORT_SYMBOL(name)EXPORT_SYMBOL(name)?EXPORT_SYMBOL_GPL(name)EXPORT_SYMBOL_GPL(name)?EXPORT_SYMBOL_GPL(name)EXPORT_SYMBOL_GPL(name)内核模块编程内核模
32、块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?初始化与清理函数初始化与清理函数?内核模块必须调用宏module_init与module_exit去注册初始化与清理函数。初始化函数通常定义为:内核模块必须调用宏module_init与module_exit去注册初始化与清理函数。初始化函数通常定义为:static int _init init_func (void) static int _init init_func (void) /* 初始化代码*/* 初始化代码*/module_init(init_func);module_init(init_func);
33、内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?初始化与清理函数初始化与清理函数?与初始化函数相对应的是清理函数,大部分模块都需要设置清理函数,该函数在模块卸载时被调用;如果一个模块与初始化函数相对应的是清理函数,大部分模块都需要设置清理函数,该函数在模块卸载时被调用;如果一个模块没有定义清理函数没有定义清理函数,内核将不会允许它被卸载内核将不会允许它被卸载,模块在清模块在清没有定义清理函数没有定义清理函数,内核将不会允许它被卸载内核将不会允许它被卸载,模块在清模块在清理函数中需要将已申请的资源归还给系统。清理函数的定理函数中需要将已申请的资源
34、归还给系统。清理函数的定义为义为:义为义为:static void_exit exit_func(void) static void_exit exit_func(void) /* 清理代码 */* 清理代码 */ module_exit(exit_func);module_exit(exit_func);内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?用户在加载内核模块之前,可能需要传递参数给内核模块,与内核模块进行简单的交互,用户和内核模块能有多种用户在加载内核模块之前,可能需要传递参数给内核模块,与内核模块进行简单的交互
35、,用户和内核模块能有多种交互方式交互方式,例如通过例如通过/proc/proc文件系统或内核模块参数文件系统或内核模块参数。如如交互方式交互方式,例如通过例如通过/proc/proc文件系统或内核模块参数文件系统或内核模块参数。如如果用户只需要在模块加载时与模块发生交互,则采用内核果用户只需要在模块加载时与模块发生交互,则采用内核模块参数方法较好模块参数方法较好。模块参数方法较好模块参数方法较好。?用户在insmod、modprobe命令中直接制定参数,命令形式用户在insmod、modprobe命令中直接制定参数,命令形式为为:为为:?#modprobe modname var=value#
36、modprobe modname var=valuemodnamemodname是要加载的模块名是要加载的模块名,varvar是要传递的变量名是要传递的变量名,modnamemodname是要加载的模块名是要加载的模块名,varvar是要传递的变量名是要传递的变量名,value是传递的参数值。value是传递的参数值。内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?如果用户每次加载模块时传递的参数都相同,每次在命令行中输入参数比较繁琐,可以在/etc/modprobe.conf配置如果用户每次加载模块时传递的参数都相同,每次在
37、命令行中输入参数比较繁琐,可以在/etc/modprobe.conf配置文件中预先写入参数文件中预先写入参数,每次当模块被加载时每次当模块被加载时,该配置文件该配置文件文件中预先写入参数文件中预先写入参数,每次当模块被加载时每次当模块被加载时,该配置文件该配置文件中的参数就会被自动传递给模块。中的参数就会被自动传递给模块。?模块要使用用户传递的参数模块要使用用户传递的参数,应该采用以下定义的宏应该采用以下定义的宏:?模块要使用用户传递的参数模块要使用用户传递的参数,应该采用以下定义的宏应该采用以下定义的宏:?module_param(name,type,perm)module_param(na
38、me,type,perm)module_param_array(name,type,nump,perm)module_param_array(name,type,nump,perm)?module_param_array(name,type,nump,perm)module_param_array(name,type,nump,perm)内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?type指明参数类型,模块直接支持的参数类型有:指明参数类型,模块直接支持的参数类型有:?bool、invbool。bool为布尔型,为布尔型,
39、invbool类型是颠倒的布类型是颠倒的布尔类型,真值为尔类型,真值为false,假值为,假值为true。?charp。字符串指针,指针指向用户传入的字符串。字符串指针,指针指向用户传入的字符串。?int、long、short、uint、ulong、ushort。基本变长整型值,以。基本变长整型值,以u开头的是无符号值。开头的是无符号值。内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?perm为参数在为参数在sysfs文件系统中所对应的文件节点的属性。文件系统中所对应的文件节点的属性。?在在v2.6内核中,系统使用内核中,系统
40、使用sysfs文件系统,该文件系统可文件系统,该文件系统可以动态、实时,有组织有层次地反映当前系统中的硬件、驱动程序等情况。以动态、实时,有组织有层次地反映当前系统中的硬件、驱动程序等情况。块被载块被载在在此块此块?模模块被块被加加载载后,后,在在/sys/module/目录下将出现以目录下将出现以此此模模块块名命名的目录,如果此模块存在名命名的目录,如果此模块存在perm不为不为0的命令行参的命令行参数数则在此模块的目录下将出现则在此模块的目录下将出现parameters目录目录包含包含数数,则在此模块的目录下将出现则在此模块的目录下将出现parameters目录目录,包含包含一系列以参数名
41、命名的文件节点,这些文件的权限值等于一系列以参数名命名的文件节点,这些文件的权限值等于perm,文件的内容为,文件的内容为参参数的值。数的值。p参参内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?nump为一个指针。为一个指针。?该指针所指的变量保存输入的数组元素个数,当不需保该指针所指的变量保存输入的数组元素个数,当不需保存实际输入的数组元素个数时,该指针可设置为存实际输入的数组元素个数时,该指针可设置为NULL。用户传递数组参数给模块时,使用逗号分隔输入的数。用户传递数组参数给模块时,使用逗号分隔输入的数组元素组元素设定好
42、设定好nump后后如果用户传递的数组大小大如果用户传递的数组大小大组元素组元素。设定好设定好nump后后,如果用户传递的数组大小大如果用户传递的数组大小大于指定的于指定的nump,模块加载者会拒绝加载更多的数组元,模块加载者会拒绝加载更多的数组元素素。素素。?需要注意,所有模块参数应当给定一个缺省值,如果用户没有传递参数给模块,参数会使用预先设定好的缺省需要注意,所有模块参数应当给定一个缺省值,如果用户没有传递参数给模块,参数会使用预先设定好的缺省值。值。内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?以本章的“以本章的“he
43、llo world!”模块(称为模块(称为hellop)为例,说明模块参数的使用方法,模块使用)为例,说明模块参数的使用方法,模块使用2个参数:一个是名为个参数:一个是名为h的整型值的整型值;一个称为一个称为 h的字符串的字符串。当模块加当模块加howmany的整型值的整型值;一个称为一个称为whom的字符串的字符串。当模块加当模块加载时,将对载时,将对whom说说hello不止一次,而是不止一次,而是howmany次。用次。用户可采用以下命令行加载户可采用以下命令行加载:户可采用以下命令行加载户可采用以下命令行加载:?#insmod hellop howmany=10 whom=Mom内核模
44、块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程内核模块编程?模块参数模块参数?当模块以这样的方式加载后,模块会显示“当模块以这样的方式加载后,模块会显示“hello,Mom”10次。为了使用次。为了使用howmany和和whom两个参数,在模块源代码两个参数,在模块源代码中中,应该插入如下代码应该插入如下代码:中中,应该插入如下代码应该插入如下代码:static char *whom=world;static int howmany=1;module_param(howmany, int,S_IRUGO);module_param(whom, charp,S_I
45、RUGO);?module_param定义两个参数,一个是整型的定义两个参数,一个是整型的howmany,另一个参数是字符串类型的另一个参数是字符串类型的 h,两个参数在两个参数在f 中均中均另一个参数是字符串类型的另一个参数是字符串类型的whom,两个参数在两个参数在sysfs中均中均是只读的。是只读的。主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识? ?内核模块概述内核模块概述内核模块概述内核模块概述? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块编程内核模块编程内核模块编程内核模块编
46、程? ?内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?实验内容实验内容实验内容实验内容? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块在内核中的表示模块在内核中的表示?内核在管理模块时使用的管理数据结构为struct
47、module,每一个内核模块被载入时,都要为其分配一个module对内核在管理模块时使用的管理数据结构为struct module,每一个内核模块被载入时,都要为其分配一个module对象象,用一个双向链表把所有用一个双向链表把所有modulemodule对象组织起来对象组织起来,该链表该链表象象,用一个双向链表把所有用一个双向链表把所有modulemodule对象组织起来对象组织起来,该链表该链表的第1个元素为modules,开发者能够通过该元素依次访问的第1个元素为modules,开发者能够通过该元素依次访问内核中所有的内核中所有的modulemodule对象对象。内核中所有的内核中所有的
48、modulemodule对象对象。?内核通过module对象主要是为了记录模块的依赖,并进行内核通过module对象主要是为了记录模块的依赖,并进行模块导出符号的管理模块导出符号的管理。模块导出符号的管理模块导出符号的管理。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块在内核中的表示模块在内核中的表示?stat成员表明当前模块的状态:成员表明当前模块的状态:MODULE_STATE_LIVE(处于激活状态处于激活状态), MODULE STATE COMING(正在正在(处于激活状态处于激活
49、状态),_(正在正在被初始化状态)被初始化状态),MODULE_STATE_GOING(正在被卸载状态)。(正在被卸载状态)。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块在内核中的表示模块在内核中的表示?每个每个module对象都包含有多个引用计数,每个对象都包含有多个引用计数,每个CPU都有一个引用计数。都有一个引用计数。?每次当模块被使用时,模块的引用计数都会加每次当模块被使用时,模块的引用计数都会加1;?相反,当模块不被使用时,模块的引用计数就会相应减相反,当模块不被使用时,模块的引
50、用计数就会相应减少少为为 时时该块才被内核卸载该块才被内核卸载少少,仅当引用计数,仅当引用计数为为0时时,该该模模块才块才能能被内核卸载被内核卸载。?例如,假设一个例如,假设一个MS-DOS的文件系统被编译成为模块,的文件系统被编译成为模块,当模块被加载后当模块被加载后模块的引用计数为模块的引用计数为0当用户用当用户用当模块被加载后当模块被加载后,模块的引用计数为模块的引用计数为0;当用户用当用户用mount命令挂上一个命令挂上一个MS-DOS的分区后,模块引用计数的分区后,模块引用计数就变成就变成1;只有在用户只有在用户umount后后,引用计数变成引用计数变成0,该该就变成就变成1;只有在
51、用户只有在用户umount后后,引用计数变成引用计数变成0,该该模块才能被卸载。模块才能被卸载。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块在内核中的表示模块在内核中的表示?在内核代码段中,有在内核代码段中,有3个段保存导出符号的相关信息:个段保存导出符号的相关信息:?_kstrtab保存导出符号的名字;保存导出符号的名字;?_ksymtab保存供所有模块使用的符号的地址;保存供所有模块使用的符号的地址;_ksymtab_gpl保存仅供保存仅供GPL协议模块使用的符号的地协议模块使用的符号
52、的地址。址。?只有被只有被EXPORT_SYMBOL和和EXPORT_SYMBOL_GPL宏导出的符号才会被宏导出的符号才会被C编译器写入内核代码的相应编译器写入内核代码的相应GPL宏导出的符号才会被宏导出的符号才会被C编译器写入内核代码的相应编译器写入内核代码的相应段中,在加载内核时,会根据代码段中的符号信息创建段中,在加载内核时,会根据代码段中的符号信息创建符号表符号表。当前内核符号表的内容可通过当前内核符号表的内容可通过/proc/kallsyms符号表符号表。当前内核符号表的内容可通过当前内核符号表的内容可通过/proc/kallsyms查看查看:内核模块机制的实现内核模块机制的实现内
53、核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块在内核中的表示模块在内核中的表示?在内核代码段中,有在内核代码段中,有3个段保存导出符号的相关信息:个段保存导出符号的相关信息:c0400294 T _stextc0400294 t run_init_processc0400294 T stextc04002d0 t initc04005c7 t rest_initc04005e8 t try_namec0400765 T name to dev t_c04009ac T calibrate_delayc0400c40 T hard
54、 smp processor id_p_p_c0400c50 t target_cpus内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块的加载与卸载模块的加载与卸载?模块的加载模块的加载?用户通过insmod命令将模块载入内核,该命令的主要操用户通过insmod命令将模块载入内核,该命令的主要操作如下:作如下:从命令行读入要被载入的模块名。从命令行读入要被载入的模块名。获得模块代码,它通常放在/lib/modules目录下。获得模块代码,它通常放在/lib/modules目录下。调用init_
55、module( )函数,将包含模块代码缓存的调用init_module( )函数,将包含模块代码缓存的指针指针、模块代码长度和用户参数传递给函数模块代码长度和用户参数传递给函数,该函该函指针指针、模块代码长度和用户参数传递给函数模块代码长度和用户参数传递给函数,该函该函数将完成模块的加载工作。数将完成模块的加载工作。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的加载模块的加载?init_module( )函数的主要工作有:init_module( )函数
56、的主要工作有:1.1.检查用户是否有权限加载模块(具有CAP_SYS_MODULE权限)。检查用户是否有权限加载模块(具有CAP_SYS_MODULE权限)。2.2.在核心空间中为模块申请主存,并将模块目标代码拷贝进入核心空间在核心空间中为模块申请主存,并将模块目标代码拷贝进入核心空间检查模块代码是否是有效的检查模块代码是否是有效的ELF(Executable andELF(Executable and3.3.检查模块代码是否是有效的检查模块代码是否是有效的ELF(ExecutableELF(Executable andand Linking Format,可执行连接格式),如果不是, Lin
57、king Format,可执行连接格式),如果不是,报错报错。报错报错。4.4.在核心空间为用户传递的模块参数申请主存,并在核心空间为用户传递的模块参数申请主存,并将参数拷贝到核心空间将参数拷贝到核心空间。将参数拷贝到核心空间将参数拷贝到核心空间。5.5.内核通过模块名检查模块是否已经被载入内核。内核通过模块名检查模块是否已经被载入内核。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的加载模块的加载?init_module( )函数的主要工作有:init_
58、module( )函数的主要工作有:为模块的可执行代码分配空间为模块的可执行代码分配空间,并将模块目标代并将模块目标代6.6.为模块的可执行代码分配空间为模块的可执行代码分配空间,并将模块目标代并将模块目标代码中的相应段拷贝到该空间。码中的相应段拷贝到该空间。7.7.为模块的初始化代码分配空间为模块的初始化代码分配空间,并将模块目标代并将模块目标代7.7.为模块的初始化代码分配空间为模块的初始化代码分配空间,并将模块目标代并将模块目标代码中的相应段拷贝到该空间。码中的相应段拷贝到该空间。8.8.获得模块的获得模块的modulemodule对象的位置对象的位置,在模块目标代码在模块目标代码获得模
59、块的获得模块的modulemodule对象的位置对象的位置,在模块目标代码在模块目标代码的正文段中存储着该对象。的正文段中存储着该对象。9.9.根据6)、7)行,初始化module对象中的根据6)、7)行,初始化module对象中的module_codemodule_code和和module_initmodule_init成员成员。module_codemodule_code和和module_initmodule_init成员成员。10.10.初始化modules_which_use_me,并把模块的引用初始化modules_which_use_me,并把模块的引用计数置成计数置成0 0。计数
60、置成计数置成0 0。11.11.根据模块的授权协议,设置license_gplok,如果该模块不符合GPL协议,该标志置为0。根据模块的授权协议,设置license_gplok,如果该模块不符合GPL协议,该标志置为0。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的加载模块的加载?init_module( )函数的主要工作有:init_module( )函数的主要工作有:12.12.根据模块和内核符号表,对模块代码进行重定位,将代码中的符号解析成主存地址
61、。根据模块和内核符号表,对模块代码进行重定位,将代码中的符号解析成主存地址。13.13.设置module对象中的syms和gpl_syms成员,这两个值被设置成模块导出符号表的地址。设置module对象中的syms和gpl_syms成员,这两个值被设置成模块导出符号表的地址。解析用户传递过来的参数解析用户传递过来的参数,并将值赋给模块中相并将值赋给模块中相14.14.解析用户传递过来的参数解析用户传递过来的参数,并将值赋给模块中相并将值赋给模块中相应的符号。应的符号。15.15.注册注册modulemodule对象中的对象中的mkobjmkobj成员成员。注册后注册后,在在15.15.注册注册
62、modulemodule对象中的对象中的mkobjmkobj成员成员。注册后注册后,在在sysfs文件系统的module目录中会增加一个该模块sysfs文件系统的module目录中会增加一个该模块的目录的目录,该目录下包含有该模块的信息该目录下包含有该模块的信息。的目录的目录,该目录下包含有该模块的信息该目录下包含有该模块的信息。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的加载模块的加载?init_module( )函数的主要工作有:init_modu
63、le( )函数的主要工作有:16.16.将第2)步中申请的主存释放。将第2)步中申请的主存释放。17.17.将module对象加入全局的模块对象双向链表。将module对象加入全局的模块对象双向链表。18.18.将模块状态设置为MODULE_STATE_COMING。将模块状态设置为MODULE_STATE_COMING。19.19.如果模块自定义初始化函数如果模块自定义初始化函数,调用模块的初始化调用模块的初始化如果模块自定义初始化函数如果模块自定义初始化函数,调用模块的初始化调用模块的初始化函数。函数。20.20.设置模块状态为MODULE_STATE_LIVE。设置模块状态为MODULE
64、_STATE_LIVE。21.21.结束结束内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的卸载模块的卸载?用户可以通过rmmod命令将内核模块卸载,该命令所用户可以通过rmmod命令将内核模块卸载,该命令所做的操作是:做的操作是:1)读取要被卸载的模块名。1)读取要被卸载的模块名。2)打开/proc/modules文件,查看该模块是否已经被卸载。2)打开/proc/modules文件,查看该模块是否已经被卸载。3 3)调用调用delete_module(
65、 )delete_module( ),把模块名传递给该函把模块名传递给该函3 3)调用调用delete_module(delete_module( ) ),把模块名传递给该函把模块名传递给该函数,该函数将完成模块的卸载工作。数,该函数将完成模块的卸载工作。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现? 模块的加载与卸载模块的加载与卸载?模块的卸载模块的卸载?sys_delete_module( )函数的主要工作是:函数的主要工作是:1.1.检查用户权限,只有具有CAP_SYS_MODULE权限的
66、用户才可以卸载模块。检查用户权限,只有具有CAP_SYS_MODULE权限的用户才可以卸载模块。2.2.将模块名拷贝进核心空间。将模块名拷贝进核心空间。3.3.在全局模块对象的双向链表中查找到该模块的在全局模块对象的双向链表中查找到该模块的modulemodule对象对象。modulemodule对象对象。4.4.通过module对象的modules_which_use_me成员检通过module对象的modules_which_use_me成员检查是否有其他模块依赖该模块查是否有其他模块依赖该模块。只有在没有依赖只有在没有依赖查是否有其他模块依赖该模块查是否有其他模块依赖该模块。只有在没有依
67、赖只有在没有依赖的情况下,函数才能继续完成卸载。的情况下,函数才能继续完成卸载。5.5.检查模块状态检查模块状态,只有处于只有处于MODULE_STATE_LIVEMODULE_STATE_LIVE状态状态5.5.检查模块状态检查模块状态,只有处于只有处于MODULE_STATE_LIVEMODULE_STATE_LIVE状态状态的模块才能被卸载。的模块才能被卸载。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块的加载与卸载模块的加载与卸载?模块的卸载模块的卸载?sys_delete_modu
68、le( )函数的主要工作是:函数的主要工作是:6.6.如果该模块有自定义初始化函数,该模块只有在也定义了清理函数的情况下才允许被卸载。如果该模块有自定义初始化函数,该模块只有在也定义了清理函数的情况下才允许被卸载。7.7.为了防止竞争,将系统中的其他CPU停止。为了防止竞争,将系统中的其他CPU停止。8.8.将模块的状态设置成MODULE_STATE_GOING。将模块的状态设置成MODULE_STATE_GOING。9.9.如果模块的引用计数大于0,模块不能被卸载。如果模块的引用计数大于0,模块不能被卸载。10.10.如果模块定义了清理函数,调用清理函数。如果模块定义了清理函数,调用清理函数
69、。内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?模块的加载与卸载模块的加载与卸载?模块的卸载模块的卸载?sys_delete_module( )函数的主要工作是:函数的主要工作是:11.11.将模块加载时注册的mkobj,取消掉。将模块加载时注册的mkobj,取消掉。12.12.如果有其他模块被该模块使用,修改其他模块的如果有其他模块被该模块使用,修改其他模块的引用关系。引用关系。13.13.释放该模块的module对象释放该模块的module对象14.14.释放模块占用的主存(代码、符号表、异
70、常表)释放模块占用的主存(代码、符号表、异常表)15.15.结束结束主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识主要内容主要内容主要内容主要内容?背景知识背景知识背景知识背景知识? ?内核模块概述内核模块概述内核模块概述内核模块概述? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块编程内核模块编程内核模块编程内核模块编程? ?内核模块机制的实现内核模块机制的实现内核模块机制的实现内核模块机制的实现?实验内容实验内容实验内容实验内容? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息
71、? ?通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息?实验说明实验说明实验说明实验说明通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息?实验说明实验说明实验说明实验说明?在内核中,所有进程控制块都被一个双向链表连接起来在内核中,所有进程控制块都被一个双向链表连接起来,该链表中的第该链表中的第1 1个进程控制块为个进程控制块为init
72、_taskinit_task。,该链表中的第该链表中的第1 1个进程控制块为个进程控制块为init_taskinit_task。?编写一个内核模块,模块接收用户传递的一个参数num,num指定要打印的进程控制块的数量;若用户不指定编写一个内核模块,模块接收用户传递的一个参数num,num指定要打印的进程控制块的数量;若用户不指定num或者num0,模块则打印所有进程控制块的信息。需要打印的进程控制块信息有:进程PID和进程的可执行num或者numtasks.next, struct task_struct, tasks);?访问该双向链表中的下一个进程控制块。在该双向链表中,第访问该双向链表中
73、的下一个进程控制块。在该双向链表中,第1个进程控制块为个进程控制块为init_task,如果开发者发,如果开发者发现下个进程控制块为现下个进程控制块为i it tk时时说明已经完整地说明已经完整地现下现下一一个进程控制块为个进程控制块为init_task时时,说明已经完整地说明已经完整地遍历过所有进程控制块。遍历过所有进程控制块。通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息?解决方案解决方案解决方案解决方案通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制
74、块信息?解决方案解决方案解决方案解决方案?访问进程控制块链表访问进程控制块链表?内核定义宏内核定义宏for each process用于遍历所有的进程控用于遍历所有的进程控?内核定义宏内核定义宏for_each_process用于遍历所有的进程控用于遍历所有的进程控制块,开发者通过该宏就能将所有的进程控制块访问一遍,该宏展开的形式为:制块,开发者通过该宏就能将所有的进程控制块访问一遍,该宏展开的形式为:for (p = &init_task ; (p = list_entry(p)-tasks.next, struct task_struct, tasks) != &init_task ; )
75、通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息?解决方案解决方案解决方案解决方案通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息通过内核模块显示进程控制块信息?解决方案解决方案解决方案解决方案?输出进程控制块信息输出进程控制块信息?进程控制块中包含进程大部分信息进程控制块中包含进程大部分信息,根据实验要求根据实验要求,?进程控制块中包含进程大部分信息进程控制块中包含进程大部分信息,根据实验要求根据实验要求,模块需要打印进程的模块需要打印进程的pid和可执行文件名,在进程控制块的数据结构中,成员和可执行文件名,在进程控制块的数据结构中,成员pid为进程的为进程的PID,而成员,而成员comm包含进程的可执行文件名。在内核中,模块可以通过包含进程的可执行文件名。在内核中,模块可以通过printk( )内核函数将这些信息打印到系统日志内核函数将这些信息打印到系统日志中中中中。第第第第1212章章 内核模块内核模块章章 内核模块内核模块