⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 00000006.htm

📁 一份很好的linux入门资料
💻 HTM
字号:
<HTML><HEAD>  <TITLE>BBS水木清华站∶精华区</TITLE></HEAD><BODY><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER>发信人:&nbsp;axp33a&nbsp;(无聊中...),&nbsp;信区:&nbsp;Linux&nbsp;<BR>标&nbsp;&nbsp;题:&nbsp;Linux内核源代码分析2-2-3&nbsp;<BR>发信站:&nbsp;BBS&nbsp;水木清华站&nbsp;(Thu&nbsp;Aug&nbsp;&nbsp;3&nbsp;11:22:25&nbsp;2000)&nbsp;WWW-POST&nbsp;<BR>&nbsp;<BR>2.2.3&nbsp;&nbsp;&nbsp;内核模块
&nbsp;<BR>整个内核并不需要同时装入内存。应该确认,为保证系统能够正常运行,一些特定的内核&nbsp;<BR>必须总是驻留在内存中,例如,进程调度代码就必须常驻内存。但是内核其他部分,例如&nbsp;<BR>大部分的设备驱动就应该仅在内核需要的时候才装载,而在其他情况下则无需占用内存。&nbsp;<BR>
&nbsp;<BR>举例来说,只有在内核真正和CD-ROM通讯时才需要使用完成内核与CD-ROM通讯的设备驱动&nbsp;<BR>程序,因此内核可以被设置为在和设备通讯之前才装载相应代码。内核完成和设备的通讯&nbsp;<BR>之后可以将这部分代码丢弃。也就是说,一旦代码不再需要,就可以从内存中移走。系统&nbsp;<BR>运行过程中可以增减的这部分内核称为内核模块。
&nbsp;<BR>内核模块的优点是可以简化内核自身的开发。假设你购买了一个新的高速CD-ROM驱动器,&nbsp;<BR>但是现有的CD-ROM驱动程序并不支持该设备。你自然就希望增加对这种高速模式的支持以&nbsp;<BR>提高系统光驱设备的性能。如果作为内核模块来编译驱动程序,你的工作将会方便得多:&nbsp;<BR>编译驱动程序、加载到内核、测试、卸载驱动程序、修改驱动程序、再次加载驱动程序到&nbsp;<BR>内核、测试,如此周而复始。如果你的驱动程序是直接编辑在内核中的,那么你就必须重&nbsp;<BR>新编译整个内核并且在每次修改驱动程序之后重新启动机器。这样慢得很多。
&nbsp;<BR>自然,你也必须留意内核模块。对于指明其他内核模块在磁盘上的驻留位置的那些模块,&nbsp;<BR>一定不能从内存中卸载,否则,内核将只能通过访问磁盘来装载处理磁盘访问的内核模块&nbsp;<BR>,这是不可能实现的。这也是我们要选择把部分内核作为模块编译还是直接编译进内核使&nbsp;<BR>其常驻内存的又一个原因。知道自己系统的设置方式,因而也就可以选择正确使用的方式&nbsp;<BR>(如果为了确保安全,可以简单的忽略内核模块系统的优点,而把所有的内容都编译到内&nbsp;<BR>核里面)。
&nbsp;<BR>内核模块会带来一些速度上的损失,这是因为一些必需的代码现在并不在RAM中,必需要&nbsp;<BR>从磁盘读入。但是整个系统的性能通常会有所提高,这主要是因为通过丢弃暂时不使用的&nbsp;<BR>模块可以释放出额外的RAM供应用程序使用。如果这部分内存被内核所占用,应用程序将&nbsp;<BR>只能更加频繁地进行磁盘交换,而这种磁盘交换会显著地降低应用程序的性能(磁盘交换&nbsp;<BR>将在第8章中讨论)。
&nbsp;<BR>内核模块还会带来因复杂度的增加所造成的开销,这是因为在系统运行的过程中,移进移&nbsp;<BR>出部分内核需要额外的代码。然而,复杂度的开销是可以管理的。通过使用外部程序来代&nbsp;<BR>理一些必需的工作还可以更进一步降低复杂度的开销(更为确切的说法是,这样做不是减&nbsp;<BR>少了复杂度的开销,而是把复杂度的开销重新分配了一下)。这是对内核模块原理的一个&nbsp;<BR>小小的扩展:即使是内核的支持模块,对于内核来说也只是外部的、部分可用的,只有在&nbsp;<BR>需要的时候才被装入内存。
&nbsp;<BR>通常用于这种目的程序称为modprobe。有关的modprobe代码超出了本书的范围,但是在&nbsp;<BR>Linux的每个发行版本中都包含有它。本节的剩余部分将讨论同modprobe协同工作,以装&nbsp;<BR>载内核模块的内核代码。
&nbsp;<BR>1.&nbsp;request_module
&nbsp;<BR>24432:作为函数说明之前的注释,request_module是一个函数。内核的其他模块在需要&nbsp;<BR>装载其他内核模块的时候,都必须调用这个函数。就像内核处理其他工作一样,这种调用&nbsp;<BR>也是为当前运行的进程进行的。从进程的角度来看,这种调用的请求通常是隐含的—正在&nbsp;<BR>执行进程其他请求的内核可能会发现,必须调入一个模块才能够完成该请求。例如,请参&nbsp;<BR>见10070行,这里是一些将在第7章中讨论的代码。
&nbsp;<BR>24446:以内核中的一个独立进程的形式执行exec_modprobe函数(24384行)。这并不能&nbsp;<BR>只通过函数的简单调用实现,因为exec_modprobe要继续调用exec来执行一个程序。因此&nbsp;<BR>,对函数exec_modprobe的简单调用将永远不会有返回。
&nbsp;<BR>这和使用fork以准备exec调用十分类似,你可以认为kernel_thread对内核来说就是较低&nbsp;<BR>版本的fork,虽然两者有很大不同。fork是从指定函数开始执行新的进程,而不是从调用&nbsp;<BR>者的当前位置开始运行。正如fork一样,kernel_thread返回的值是新进程的进程号。
&nbsp;<BR>24448:和fork一样,从kernel_thread返回的负值表示内部错误。
&nbsp;<BR>24455:正如函数中论述的一样,大部分的信号将因当前进程而被暂时阻塞。
&nbsp;<BR>24462:等待exec_modprobe执行完毕,同时指出所需要的模块是已经成功装入内存,还是&nbsp;<BR>装载失败了。
&nbsp;<BR>24465:结束运行,恢复信号。如果exec_modprobe返回错误代码,则打印错误消息。
&nbsp;<BR>2.&nbsp;&nbsp;exec_modprobe
&nbsp;<BR>24384:exec_modprobe运行为内核增加内核模块的程序。这里的模块名是一个void*的指&nbsp;<BR>针,而不是char*的指针。原因简单说来就是kernel_thread&nbsp;产生的函数通常都使用void*&nbsp;<BR>指针参数。
&nbsp;<BR>24386:设置modprobe的参数列表和环境。modprobe_path(24363行)用来定位modprobe&nbsp;<BR>程序的位置。它可以通过内核的sysctl特性来修改,这一点将在第11章中介绍(参见&nbsp;<BR>30388行)。这意味着root可以动态选择不同于/sbin/modprobe的程序来运行,以适应当&nbsp;<BR>modprobe被安装到其他地方或者使用修改过的modprobe替换掉了原有的modprobe之类的情&nbsp;<BR>况。
&nbsp;<BR>24400:(正如代码中描述的一样)出于安全性考虑,丢弃所有挂起的信号和信号句柄(&nbsp;<BR>handl-ers)。这里最重要的部分是对flush_signal_handlers的调用(28041行),它使&nbsp;<BR>用内核默认的信号句柄代替所有用户定义的信号句柄。如果在此时有信号被传送到内核,&nbsp;<BR>它将获得默认响应—通常是忽略信号或杀死进程。但是不管怎样都不会引起安全风险。由&nbsp;<BR>于该函数从触发它的进程中分离出来(如前所述),所以,不管原始进程在此处是否改变&nbsp;<BR>其原来分配的信号,句柄都不会产生任何影响。
&nbsp;<BR>24405:关闭调用进程打开的所有文件。最重要的是,这意味着modprobe程序不再从调用&nbsp;<BR>进程中继承标准输入输出和标准错误。这很有可能会引起安全漏洞(这可能是在替代&nbsp;<BR>modprobe的程序中引起的问题,但是modprobe本身实际上并不关心这个差异)。
&nbsp;<BR>24413:modprobe程序作为root运行,它拥有root所拥有的所有权限。和整个内核中其他&nbsp;<BR>地方一样,请注意root使用用户ID号0的假定在这里已经被写入程序。用户ID号和权能系&nbsp;<BR>统(capability&nbsp;system,在接下来的几行中会用到)将在第7章中介绍。
&nbsp;<BR>24421:试图执行modprobe程序。如果尝试失败,内核将使用printk打印错误消息并返回&nbsp;<BR>错误代码。这里是可能产生printk的缓冲器过载的地点之一。module_name的长度并没有&nbsp;<BR>明确限制,就我们对该调用的看法而言,它可能长达一百万个字符。为防止printk缓冲器&nbsp;<BR>过载,你必需遍历所有对于该函数的调用(实际上是对request_module的调用),以保证&nbsp;<BR>每个调用者使用足够短的、不会为printk造成麻烦的模块名。
&nbsp;<BR>24427:当execve成功执行时,它不会返回任何结果,因此本处是不可能执行到的。但是&nbsp;<BR>编译器却并不知道这一点,因此,此处使用了return语句以保证gcc不出错。
&nbsp;<BR>对于内核的进一步讨论将超出本章的既定范围,因此在这个问题上我们到此为止。然而本&nbsp;<BR>书中也包括了其他必需的内核代码。在读完第4章和第5章之后,也许你会希望再次仔细研&nbsp;<BR>读一下这部分内容。有关这个问题的两个文件是include/linux/module.h(从15529行开&nbsp;<BR>始)和/kernel/module.c(从24476行开始)。和sys_create_module(24586行)、&nbsp;<BR>sys_init_module(24637行)、sys_delete_module(24860行)和sys_query_module(&nbsp;<BR>25148行)四个函数需要特别注意一样,struct&nbsp;module(15581行)也要特别引起注意。&nbsp;<BR>这些函数实现了modprobe及insmod、lsmod和rmmod所使用的系统调用,以完成模块的装载&nbsp;<BR>、定位和卸载。
&nbsp;<BR>内核触发直接回调内核程序的现象看起来很令人奇怪。但是,实际上进行的工作不止于此&nbsp;<BR>。例如,modprobe必须实际访问磁盘以搜寻要装载的模块。而且更为重要的一点是,这种&nbsp;<BR>方法赋予root对内核模块系统更多的控制能力。这主要是因为root也可以运行modprobe及&nbsp;<BR>相关程序。因此,root既可以手工装载、查询、卸载模块,也可以由内核自动完成。&nbsp;<BR>&nbsp;<BR>--&nbsp;<BR>※&nbsp;来源:·BBS&nbsp;水木清华站&nbsp;smth.org·[FROM:&nbsp;166.111.196.22]&nbsp;&nbsp;<BR><CENTER><H1>BBS水木清华站∶精华区</H1></CENTER></BODY></HTML>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -