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

📄 (ldd) ch11-kerneld和高级模块化(转载).htm

📁 LINUX驱动编程
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<TABLE borderColor=#666666 cellPadding=2 width="90%" align=center border=2>
  <TBODY>
  <TR>
    <TD bgColor=#000000>
      <P align=center><A href="http://joyfire.net/lsdp/index.htm"><FONT 
      color=#ffffff size=2>目录页</FONT></A> | <A 
      href="http://joyfire.net/lsdp/13.htm"><FONT color=#ffffff 
      size=2>上一页</FONT></A> | <A href="http://joyfire.net/lsdp/15.htm"><FONT 
      color=#ffffff size=2>下一页</FONT></A></P>
      <P align=center><FONT face=黑体 color=#ffffff size=6>(LDD) 
      Ch11-kerneld和高级模块化(转载)</FONT></P><SPAN 
      style="LINE-HEIGHT: 1; LETTER-SPACING: 0pt"><FONT color=#ffffff size=3>
      <P>发信人:&nbsp;Altmayer&nbsp;(alt),&nbsp;信区:&nbsp;GNULinux<BR>标&nbsp;&nbsp;题:&nbsp;(LDD)&nbsp;Ch11-kerneld和高级模块化(转载)<BR>发信站:&nbsp;饮水思源&nbsp;(2001年12月13日08:57:37&nbsp;星期四),&nbsp;站内信件<BR>&nbsp;<BR>【&nbsp;以下文字转载自&nbsp;<FONT 
      color=#00ff00>UNIXpost&nbsp;</FONT>讨论区&nbsp;】<BR>【&nbsp;原文由<FONT 
      color=#00ff00>&nbsp;altmayer.bbs@bbs.nju.edu.cn,</FONT>&nbsp;所发表&nbsp;】<BR>&nbsp;<BR>【&nbsp;以下文字转载自&nbsp;<FONT 
      color=#00ff00>altmayer&nbsp;</FONT>的信箱&nbsp;】<BR>&nbsp;<BR>第11章&nbsp;kerneld和高级模块化<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;在本书的第二部分,我们要讨论的话题比到目前为止我们所接触过的话题都更为<BR>高级。我们将再次从模块化讲起,第二章“编写和运行模块”中对模块化的介绍只是其<BR>中的一部分;modules包(它们的最新版本被称作modutils)支持一些更高级的特性,它们<BR>比前面讨论的安装和运行一个基本的驱动程序所需的特性要更为复杂。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;本章将讨论kerneld程序,模块中的版本支持(一种便利性,它使你在升级内核时<BR>不必重新编译你的各个模块)以及在卸载和重新装载一个模块时对数据持久性的支持。最<BR>后这项功能只有2.0.0版或更新版本的modules包才提供。<BR>&nbsp;<BR>按需加载模块<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>按需加载模块<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;为了方便用户加载&nbsp;托对啬&nbsp;块,并且避免把不再使用的驱动程序继续保留在核心<BR>中浪费内核存储空间,Linux提供了对模块的自动加载和卸载的支持。(在1.2版以前不提<BR>供这种支持)要利用这个特性,在编译内核前进行的配置中你必须打开对kerneld的支持<BR>。需要时可以请求附加模块的能力对于使用堆叠式模块的驱动程序尤其有用。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>隐藏在kerneld之后的思想很简单,但却很有效。当内核试图访问不可用资源时,它会通<BR>知用户程序而不仅仅是返回一个错误。如果守护进程成功地获得该资源,内核将继续工<BR>作;否则它将返回错误。实际上申请任何一种资源的时候都可以使用这种办法:诸如字<BR>符设备和块设备驱动程序,行律和网络协议等等。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>用于获得按需装载能力的机制是使用一个修改过的消息队列,利用它在内核空间和用户<BR>空间之间相互传递文本信息。要让按需装载能正确工作,必须正确地配置用户级守护进<BR>程,并且内核代码必须做好准备,等待所需的模块。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>可以从按需装载中受益的驱动程序的一个典型例子是通用帧捕获者(frame-grabber)驱动<BR>程序。它能支持几种不同的外设,但却表现出相同的外部行为。发布中将包括它所支持<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>程序。它能支持几种不同的外设,但却表现出相同的外部行为。发布中将包括它所支持<BR>的所有设备卡的代码,但是在运行时只有正在被使用的那个特定设备卡的代码才真正需<BR>要。这样开发者就能够把具体实现划分为一个定义软件接口的通用模块和一系列用于低<BR>层操作的与硬件相关的模块。在通用模块检测到系统中安装的捕获者的类型后,它就能<BR>够为该捕获者申请正确的模块。<BR>&nbsp;<BR>用户级方面<BR>kerneld程序生存在用户空间,负责处理来自内核的对新模块的请求。它通过创建自己的<BR>消息队列和内核相连,然后进入睡眠,等待请求。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>请求一个模块时,守护进程从内核中接收一个字符串并试图解析它。这个字符串可能是<BR>下面两种形式之一:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;目标文件的名字,就象insmod命令的典型参数一样。floppy是这种名字的一个<BR>例子;在这种情况下,守护进程将查找文件floppy.o并装载它。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;更一般的标志符,比如block-major-2,它用来指明主设备号为2的块设备-也<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;更一般的标志符,比如block-major-2,它用来指明主设备号为2的块设备-也<BR>就是软盘驱动程序。这种类型的字符串是最常见的,因为内核通常只知道资源的数字标<BR>志符。例如,当你试图使用一个块设备时,内核只知道它的主设备号;仅仅就为了能通<BR>过名字来请求每个块设备而为它们实现各自不同的钩子函数很浪费。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>显然,后一种情况时,必须有某种方法把模块的"id"映射成它的实际名字。这种关联并<BR>不由kerneld本身完成而是由kerneld调用modprobe来完成。在depmod命令的帮助下,由m<BR>odprobe来处理模块装载的细节;kerneld本身只负责与内核的通讯并生成外部任务。所<BR>有这些程序都在modules包中一起发布。depmod是一个能产生类似Makefile那样的模块依<BR>赖信息的工具,而modprobe是能替代insmod用来正确装载模块堆栈的程序。例如ppp模块<BR>堆叠在slhc模块(Serial&nbsp;Line&nbsp;Header&nbsp;Compression)之上(换句话说,可以使用slhc模块<BR>中的符号)。除非已经装载了slhc,否则命令insmod&nbsp;ppp就会失败;另一方面,假如在安<BR>装好模块之后会调用命令depmod&nbsp;-a来创建依赖规则,命令modprobe&nbsp;ppp就能成功。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>insmod和modprobe间的另一个差别是后者不会在当前目录中查找模块,它只在/lib/modu<BR>les下的缺省目录中查找。这是因为该程序是一个系统实用例程,而不是一个交互工具;<BR>你可以通过在/etc/modules.conf中指定你自己的目录,来把它们加入缺省目录集。<BR>&nbsp;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>&nbsp;<BR>/etc/modules.conf是一个用于定制modules包的文本文件。它负责把象block-major-2这<BR>样的名字关联到floppy。注意,2.0前的版本的modules包查找的是另一个文件/etc/conf<BR>..modules;出于兼容的考虑,仍支持这种文件名,但提倡更为标准的名字modules.conf<BR>。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>modules.conf的语法在depmod和modprobe命令的man页中有很好的描述;然而,我觉得有<BR>必要在这里提及一些重要命令的意思。我用下面几行作为例子:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>#sample&nbsp;line&nbsp;for&nbsp;/etc/modules.conf<BR>&nbsp;<BR>keep<BR>&nbsp;<BR>path[misc]=~rubini/driverBook/src/*<BR>&nbsp;<BR>option&nbsp;short&nbsp;irq=1<BR>&nbsp;<BR>alias&nbsp;eth0&nbsp;ne<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>alias&nbsp;eth0&nbsp;ne<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>上面显示的第一行是注释;path[misc]指出在哪查找各种模块-而keep指出应把用户路<BR>径加到缺省路径中,而不是替换缺省路径。Option制导(directive)指出在装载short模<BR>块时总是设定irq=1,alias行则指出当需要装载eth0时,相关的文件是ne.o(ne2000接口<BR>的驱动程序)。象alias&nbsp;block-major-2&nbsp;floppy这样的行并不真正需要,因为modprobe已<BR>经知道的所有设备的官方主设备号,并且这些“可预见”的alias命令在程序中预定义过<BR>了。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>那么,按需装载模块的正确安装,就是在文件/etc/modules.conf中加入这么几行,因为<BR>kerneld是依靠modprobe来进行实际的装载操作。<BR>&nbsp;<BR>内核级方面<BR>请求加载模块和卸载模块,内核代码可以使用&lt;linux/kerneld.h&gt;中定义的函数。这些函<BR>数都定义成内联函数,实际上又将参数传递给了kerneld_send。kerneld_send函数是用<BR>来与kerneld通讯的一个灵活的引擎,它存在于文件ipc/msg.c中,如果你感兴趣的话,<BR>可以到那里浏览它。<BR>&nbsp;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>&nbsp;<BR>这里,我不准备探讨kerneld_send的细节,因为在头文件&lt;linux/kerneld.h&gt;中定义的下<BR>列一些调用,足够你用来实现按需装载:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>int&nbsp;request_module(const&nbsp;char&nbsp;*name)<BR>&nbsp;<BR>需要加载模块的时候可以调用该函数。参数name或者是模块的文件名,或者是在用户空<BR>间解析的id类型字符串。在装载成功完成(或失败)后该函数返回。request_module只能<BR>在进程上下文中被调用,因为当前进程将进入睡眠,等待模块被加载。任何一个按需加<BR>载的模块,在使用计数降为0时,都将自动卸载。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>int&nbsp;release_module(const&nbsp;char&nbsp;*name,int&nbsp;waitflag)<BR>&nbsp;<BR>请求立即卸载一个模块。如果waitflag不为0,意味着函数在返回前必须等待卸载结束。<BR>如果waitflag为0,函数可以在中断时间内调用-如果值得这么做的话。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>int&nbsp;delayed_release_module(const&nbsp;char&nbsp;*name)<BR>&nbsp;<BR>请求延迟的模块卸载。该函数总是立即返回。它的效果就是模块name在使用计数降为0就<BR>卸载,即使该模块并不是由kerneld加载的。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>int&nbsp;cancel_release_module(const&nbsp;char&nbsp;*name)<BR>&nbsp;<BR>该函数取消delayed_release_module的作用,它不阻止按需装载模块的自动卸载,最少<BR>当前的实现是这样的。一般不需要该函数,在这里提到它主要是出于完整性的考虑。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>如果在内核空间检测到了错误,kerneld_send的返回值,包括所有列出的这些函数的返<BR>回值都会是负的。如果内核中一切运行正常,返回值被置为执行这些操作的用户空间程<BR>序的退出值。成功时的退出值为0,出错时为1到255间的一个数值。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>有关kerneld_send的一个好消息就是即使在内核配置成不提供对kerneld的支持时,该函<BR>数仍然存在(并向模块开放)。因而,模块编写者总是可以调用上面显示的这些函数,但<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>数仍然存在(并向模块开放)。因而,模块编写者总是可以调用上面显示的这些函数,但<BR>此时只返回-ENOSYS。当然,不能运行在1.2版的内核上,因为所有这些机制都是到1.3.5<BR>7版才引入的。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>现在,让我们实际地试着使用这些按需加载函数。为此目的,我们使用两个模块,分别<BR>叫作master和slave,O'Reilly的FTP站点上的misc-modules目录下以源文件的形式发布<BR>。我们还将使用slaveD.o来测试延&nbsp;傩&nbsp;载,并且使用slaveH.o来测试手工加载以及自动<BR>卸载模块。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>为了不安装模块也可以运行测试代码,我在自己的/etc/modules.conf文件中加入了如下<BR>一些行:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>keep<BR>&nbsp;<BR>path[misc]=~rubini/driverBook/src/misc-modules<BR>&nbsp;<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>&nbsp;<BR>slave模块只是一个空文件,而master模块看起来象下面这样:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>#include&nbsp;&lt;linux/kerneld.h&gt;<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>int&nbsp;init_module(void)<BR>&nbsp;<BR>{<BR>&nbsp;<BR>int&nbsp;r[3];&nbsp;&nbsp;/*&nbsp;结果&nbsp;*/<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>r[0]=request_module("slave");<BR>&nbsp;<BR>r[1]=request_module("slaveD");<BR>&nbsp;<BR>r[2]=request_module("unexists");<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>r[2]=request_module("unexists");<BR>&nbsp;<BR>printk("master:&nbsp;loading&nbsp;results&nbsp;are&nbsp;%i,%i,%i\n",r[0],r[1],r[2]);<BR>&nbsp;<BR>return&nbsp;0;&nbsp;/*&nbsp;成功&nbsp;*/<BR>&nbsp;<BR>}<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>void&nbsp;cleanup_module(void)<BR>&nbsp;<BR>{<BR>&nbsp;<BR>int&nbsp;r[4];/*&nbsp;results&nbsp;*/<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>r[0]=release_module("slave",1/*&nbsp;wait&nbsp;*/);<BR>&nbsp;<BR>r[1]=release_module("slaveH",1&nbsp;/*&nbsp;wait&nbsp;*/);<BR>&nbsp;<BR>r[2]=delayed_release_module("salveD");<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>r[2]=delayed_release_module("salveD");<BR>&nbsp;<BR>r[3]=release_module("unexists",1&nbsp;/*&nbsp;wait&nbsp;*/);<BR>&nbsp;<BR>printk("master:&nbsp;unloading&nbsp;results&nbsp;are&nbsp;%i,%i,%i,%i\n",r[0],r[1],r[2],r[3]);<BR>&nbsp;<BR>}<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>在装载时,master模块试着载入两个模块和一个并不存在的模块。除非你改变了终端的<BR>日志级别(loglevel),否则printk消息将出现在终端上。下面是系统被配置成支持kerne<BR>ld而该守护进程又是活动的时候,装载mater模块时的结果:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>morgana.root#&nbsp;depmod&nbsp;-a<BR>&nbsp;<BR>morgana.root#&nbsp;insmod&nbsp;master<BR>&nbsp;<BR>master:&nbsp;loading&nbsp;results&nbsp;are&nbsp;0,0,255<BR>&nbsp;<BR>morgana.root#&nbsp;cat&nbsp;/proc/modules<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>morgana.root#&nbsp;cat&nbsp;/proc/modules<BR>&nbsp;<BR>slaveD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>slave&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>master&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<BR>&nbsp;<BR>isofs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;(autoclean)<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>从request_module返回的值以及/proc/modules文件(在第二章的“初始化和终止”一节<BR>中描述)均显示slave模块已经正确装载。另一方面,装载unexists的返回值255意味着<BR>用户程序失败,退出码是255(或-1,因为它的长度为一个字节)。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>我们简要的看看在卸载时会发生些什么,但在此之前先让我们手工加载slaveH:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>morgana.root#&nbsp;insmod&nbsp;slaveH<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>morgana.root#&nbsp;insmod&nbsp;slaveH<BR>&nbsp;<BR>morgana.root#&nbsp;cat&nbsp;/proc/modules<BR>&nbsp;<BR>slaveH&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<BR>&nbsp;<BR>slaveD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>slave&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>master&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0<BR>&nbsp;<BR>isofs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>morgana.root#&nbsp;rmmod&nbsp;master<BR>&nbsp;<BR>master:&nbsp;unloading&nbsp;results&nbsp;are&nbsp;0,0,0,255<BR>&nbsp;<BR>morgana.root#&nbsp;cat&nbsp;/proc/modules<BR>&nbsp;<BR>slaveD&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;0&nbsp;(autoclean)<BR>&nbsp;<BR>isofs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;(autoclean)<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>isofs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;(autoclean)<BR>&nbsp;<BR>morgana.root#&nbsp;sleep60;cat&nbsp;/proc/modules<BR>&nbsp;<BR>isofs&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;1&nbsp;(autoclean)<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>结果显示,除了unexists的卸载,一切都很正常,并且slaveD在一段时间过后也会被卸<BR>载。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>尽管提供了各种例程,你还会发现,大部分时间request_module函数都能满足你的需要<BR>,而不要求你处理模块卸载;实际上,对不使用的模块,缺省地会自动进行卸载。绝大<BR>大部分时候,你甚至不必检查函数的返回值,因为只需要模块提供的一些函数。下面的<BR>实现比检查request_module的返回值更方便:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>if&nbsp;(&nbsp;(ptr&nbsp;=&nbsp;look_for_feature())&nbsp;==&nbsp;NULL&nbsp;)&nbsp;&nbsp;&nbsp;/*&nbsp;是否没有该特性&nbsp;*/<BR>&nbsp;<BR>request_module(modname);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;试图装载它&nbsp;*/<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>request_module(modname);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;试图装载它&nbsp;*/<BR>&nbsp;<BR>if&nbsp;(&nbsp;(ptr&nbsp;=&nbsp;look_for_feature())&nbsp;==&nbsp;NULL&nbsp;)&nbsp;&nbsp;&nbsp;/*&nbsp;是否仍没有该特性&nbsp;*/<BR>&nbsp;<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;-ENODEV;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;出错&nbsp;*/<BR>&nbsp;<BR>模块中的版本控制<BR>关于模块的一个主要问题是它们的版本相关性,在第二章的“版本相关性”一节中我曾<BR>经介绍过。针对每个要使用的版本的不同头文件都需要重新编译一次模块,当你运行好<BR>几个定制的模块时,这是件非常痛苦的事情。如果你运行的是以二进制形式发布的商业<BR>模块时,甚至连重新编译也是不可能的。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>幸运的,内核开发者找到了一个变通的办法来处理版本问题。他们的想法是,只有改变<BR>了内核提供的软件接口,一个模块才不能兼容不同的内核版本。然后,软件接口可以由<BR>函数原型以及函数调用涉及到的所有数据结构的确切定义所表示。最后,可以使用一个C<BR>RC算法把所有关于软件接口的信息映射到一个单一的32位数值*上去。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>版本相关性的问题通过在每个由内核导出的符号的名字后面附加一个该符号相关信息的<BR>校验和来得到处理。解析头文件,就可以从中取出这些信息。这种便捷性是可选的,在<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P>校验和来得到处理。解析头文件,就可以从中取出这些信息。这种便捷性是可选的,在<BR>编译的时候可以启动它们。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>例如,当启动版本支持时,符号printk以类似printk_R12345678的形式向模块开放,这<BR>里12345678时函数使用的软件接口的检验和的16进制表示。加载一个模块到内核时,仅<BR>当加到内核中每个符号上的检验和匹配加到模块中相同符号上的校验和时,insmod(或mo<BR>dprobe)才能够完成它的任务。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>让我们来看看内核和模块都启动了版本支持的时候,会发生些什么:<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;内核本身并不修改符号。进程以通常的方式与内核链接,而且vmlinux文件的<BR>符号表看起来也和以前一样。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;公共符号表使用版本名字创建,如/proc/ksyms文件所示。<BR>&nbsp;<BR></P></FONT><FONT 
      color=#ffffff size=3>
      <P><BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;模块必须使用合并后的名字编译,这些名字在目标文件中是以未定义符号出现<BR>的。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>l&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;装载程序用模块中未定义符号匹配内核中的公共符号,因此也要使用版本信息<BR>。<BR>&nbsp;<BR>&nbsp;<BR>&nbsp;<BR>然而,上述情况只有当内核和模块都创建成支持版本化时才有效。如果有任何一方使用<BR>了原来的符号名,insmod都会放弃版本信息,并试着用第二章的“版本相关性”一节中<BR>描述的方式来匹配模块声明的内核版本号和内核提供的版本号。<BR>&nbsp;<BR>在模块中使用版本支持<BR>当内核已经准备(可选的)输出版本化的符号时,模块源代码只需准备好支持该选项。可<BR>以在两处加入版本控制:在Makefile中或在源代码本身。因为modules包文档描述了在Ma<BR>kefile中如何做,我将向你显示在C源代码中如何做。用于演示kerneld如何工作的maste<BR>r模块能够支持版本化符号。如果用于编译模块的内核利用了版本支持的话,这种能力会<BR>自动启动。<BR></P></FONT><FONT 

⌨️ 快捷键说明

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