基于Linux操作系统的光盘容错机制.pdf
第3 0 卷第5 期2 0 0 9 年5 月微计算机应用M I C R O C O M P U T E RA P P L I C 盯I O N SV 0 1 3 0N o 5M a v 2 0 0 9基于L i n u x 操作系统的光盘容错机制王建慧白凤娥(太原理工大学计算机与软件学院山西0 3 0 0 2 4)摘要:容错机制对于读光盘是很重要的。本文分析了L i n u x 操作系统下块设备驱动程序的工作流程,并实现了一种在驱动层通过扇区块跳读来实现光盘容错的方法,显著提高L i n u x 操作系统下光盘的重复利用率。关键词:L i n u x 驱动程序扇区块光盘容错F a u l t T o l e r a n to fL i n u x-B a s e dO p e r a t i n gS y s t e mo nR e a d i n gO p t i c a lD i s kW A N GJ i a n h u i,B A IF e n g e(C o l l e g eo f C o m p u t e ra n dS o f t w a r e,T a i y u a nU n i v e r s i t yo f T e c h n o l o g y,S h a n x i,0 3 0 0 2 4,C h i n a)A b s t r a c t:F a u l t t o l e r a n ti sv e r yi m p o r t a n tf o rr e a d i n go p t i c a ld i s k T h i sp a p e ra n a l y z e sh o wb l o c kd e v i c ed r i v e r sw o r ko nL i n u xo p e r a t i n ss y s t e m,a n db a s e do nt h i sp o i n t,f u l f i l l sam e t h o do ff a u l t t o l e r a n to nr e a d i n go p t i c a ld i s ko nd r i v e rl a y e r,b yw a yo fs k i p p i n gs e e t o r s T h i sm e t h o di n c r e a s e sr e u s er a t eo fo p t i c a ld i s ko nL i n u xo p e r a t i n gs y s t e m K e y w o r d s:L i n u x,d r i v e r s,s e c t o r,o p t i c a ld i s k,f a u l t t o l e r a n t2 l 世纪,信息的重要性已经得到了充分的证明,而存储信息的介质也因此备受关注。光存储类介质光盘自7 0 年代前后开始大量研究和开发以来,已经过了近3 0 多年的发展。作为一种信息存储媒介,与磁盘相比,光盘具有存储密度高(1 0 8 b i t c m 2)、存储寿命长(1 0 年)、抗污染性能好、信息位价格低和读取速度快等一系列优点,因而得到了广泛的应用。但是由于是移动存储设备,并且盘片的表面没有任何保护,因此在多次使用过程中,难免会出现划伤或沾染上杂物等情况,这些小毛病都会影响数据的读取。相对于读盘速度而言,光盘的容错性显得更加重要。为了提高读光盘的能力,厂商在光驱上做了很大改动,提高光驱中激光头的功率是常用的方法,这是从硬件设备上提高光盘的容错性能。但是,光头功率增大后,长时间“超频”使用会使光头老化,严重影响光驱的寿命。这种以牺牲光驱寿命来换取容错性的方法是不可取的。本文则是从软件角度出发,在L i n u x 操作系统下,在块设备驱动程序的基础上实现了软件层次的光盘容错机制,以驱动程序小的改动为代价实现了一定能力的光盘容错,提高了光盘的使用寿命。1L i n u x 设备驱动程序L i n u x 内核与外部设备之间的交互操作是通过设备驱动程序实现的。设备驱动程序属于内核的一部分,为外设定义了相关的数据结构和操作函数,并通过特定的接口与内核和其它设备驱动程序通信。图1 就是设备驱动层在内核中的位置:本文于2 0 0 8 1 1 2 6 收到。万方数据6 2微计算机应用2 0 0 9 年系统调用是操作系统内核和应用程序之间的接口,设备驱动程序是操作系统内核和机器硬件之间的接口。设备驱动程序为应用程序屏蔽了硬件的细节,这样在应用程序看来,硬件设备只是一个设备文件,应用程序可以像操作普通文件一样对硬件设备进行操作。设备驱动程序作为内核的一部分完成以下的功能。(1)对设备初始化和释放;(2)把数据从内核传送到硬件和从硬件读取数据;(3)读取应用程序传送给设备文件的数据和回送应用程序请求的数据;(4)检测和处理设备出现的错误。在L i n u x 操作系统下有三类主要的设备文件类内型,分别是字符设备、块设备和网络设备。字符设备和块设备的主要区别是:在对字符设备发出读写请求时,实际的硬件I 0 一般就紧接着发生了;块设备则不然,它利用一块系统内存作缓冲区,当用户进程对设备的请求能满足用户的要求,就返回请求的数据,如果不能,就调用请求函数来进行实际的I 0 操作。块设备主要是针对磁盘、光盘等慢速设备设计的,图1 设备驱动层在内核中的位置结构图以免耗费过多的C P U 时间来等待。光盘作为一种大容量存储设备,它是作为块设备被I A n u x 中的块设备驱动程序处理。2 块设备驱动数据结构及流程块设备驱动层作为内核的一部分,定义了很多的数据结构,有描述外设的,也有描述外设请求的,这些数据结构对于分析驱动程序流程至关重要,以下是其中的两个重要的数据结构,均在b l k d e v h 中定义:(1)请求队列结构体。r e q u e s t _ q u e u es t r u e tr e q u e s t _ q u e u e s t r u c tr e q u e s t _ l i s t r q;请求队列空列表,读请求一个,写请求一个i n tn r _ r e q u e s t s;一个请求队列上的请求数a t o m i c _ tn r _ s e c t o r s;每个队列上的5 1 2 b y t e 块的总块数i n tm a x q u e u e s e c t o r s;每个队列上的5 1 2 b y t e 块的最大块数(2)请求结构体:r e q u e s ts t r u e tr e q u e s t s t r u e th s t _ h e a dq u e u e;k d e v _ tr q _ d e v;i n te m d;u n s i g n e dl o n gs t m t _ t i m e;u n s i g n e dl o n gs e c t o r;u n s i g n e dl o n gn r _ s e e t o r s;,设备号标示读或者写要读的扇区块数s t r u c tl i s t _ h e a d q u e u e h e a d;r e q u e s t _ f n _ p r o c|-r e q u e s t _ f n;请求操作处理函数s p i n l o c k _ t q u e u e _ l o c k;互斥请求锁w a i t _ q u e u e _ h e a d _ tw a i t _ f o r _ r e q u e s t s;等待的任务队列;u n s i g n e dl o n gc u r r e n t _ n r _ s e c t o r s,h a r d _ c u r _ s e c t o r s;c h a r$b u f f e r;指向缓冲区的指针s t r u c tb u f f e r _ h e a d b h;管理缓冲区的结构体指针r e q u e s t _ q u e u e _ t q;光盘的读取请求是通过块设备驱动程序实现的,在L i n u x 操作系统下,这是通过请求队列的形式实现的。正常的读取操作过程包括三个步骤:万方数据5 期王建慧等:基于L i n u】【操作系统的光盘容错机制6 3(1)检查当前读取请求的有效性。这是由b l k h 中定义的宏I N I T _ R E Q U E S T 完成;(2)进行实际的数据传送。用变量C U R R E N T(实际上是个宏)可以获得发出请求的一些细节,C U R R E N T 是一个指向结构体r e q u e s t 的指针。r e q u e s t 是以r e q u e s t _ q u e u e(请求队列)为链接头、通过其中的双向循环链表q u e u e 链接起来进行管理,见图2 中第一列的三个结构体。每一个r e q u e s t(请求)又可以处理多个连续的读操作,通过图2 中的结构体b u f f e r _ h e a d 进行管理,而实际的数据保存在d a t a 中。(3)清除当前的请求。这个操作由函数i d e _ e n d _ r e q u e s t 完成,函数的代码在i d e h 中。实际的执行操作向这个函数传递一个参数,成功时为1,失败时为0。当i d e _ e n d r e q u e s t 以参数0 调用时,一个“I Oe l r o r”消息会被发给系统日志(通过p r i n t k),即发生读请求错误。3 设备驱动层次的容错机制总之,设备驱动层次的容错机制包括初始化、读操作判断以及错误处理这三个阶段,详细的容错流程则可以参考图3。在L i n u x 操作系统下,光盘容错处理机制的具体处理过程如下:(1)操作系统在收到读光盘命令后、在进行读操作之前,先进行初始化工作:s e c t o r s=N(N 是一个常量),s e c t o r s 是每次读操作失败之后跳过的扇区块数,在连续读错的情况下,以2 的倍数递增;s e c t o r _ e n d=0,s e c t o r e n d 是跳块之后下一次要读的块号,即有如下关系:s e c t o r e n d=c u r r e n t s e c t o r+s e c t o r s,c u r r e n t s e c t o r 是当前块号,初始化为0;E r r o r _ t i m e s=0,连续读错误的次数,有上限M(常数),初始化为0;(2)通过图3,可以看到正确的读操作流程图,如果发生读取操作错误,则进入到错误处理的流程中去,具体的操作如下:s e c t o r _ e n d=c u r r e n t s e c t o r+s e c t o r s,得到跳过s e c t o r s 块之后下一次要读取的块号;图2 块设备驱动程序主要数据结构关系示意图E r r o r _ t i m e s+,连读错误次数加l,并且要判断是否大于最大允许的连读错误次数,如果大于等于允许的最大连续读取错误次数,则认为光盘数据损坏严重,退出当前读命令;s e c t o r s=2 s e c t o r s,在连续读取错误时跳过的扇区块数加倍;真正跳块的操作是从下一次开始的s e c t o r s 块读取操作,但不一定是s e c t o r s 次循环,因为在L i n u x 块设备驱动程序中,每个读取操作是以d a t a 为单位的,而每个d a t a 中会存放若干个块的数据,此外,多次连续的读取操作可以合并到一个读请求中,可以参考图2。取消该次读操作所做的工作是由前面曾经提到过的i d e e n d _ r e q u e s t 函数实现的。i d e _ e n d r e q u e s t 函数是对于读取操作的扫尾工作,在正确的读取操作结束之后会返回1,而在错误的读取操作之后会返回0。如果没有错误处理机制,原始的驱动程序是一次处理一个d a t a的数据,而且要等到该次读错误操作返回。在底层操作中是通过一个时间溢出值为0 来标识的,在连续若干块发生错误的情况下,每次都要等到溢出值为0,导致读盘极其缓慢,对于检测中使用的高清碟片而言则是出现播放画面停顿或马赛克等现象。在上述错误处理机制中,要改变的是i d e e n d _ r e q u e s t 对于跳过的块的处理操作:就是把这些要跳过的块当成已正确读取结束而返回1。也就是在判断处于跳块操作过程后,不进行任何真正的读取操作,直接调用 万方数据微计算机应用2 0 0 9 正i d e e n d _ r e q u e s t 来对该次的读取请求进行清理工作。在每一次读取操作过程中,所做的清理工作是对于该次请求所使用的缓冲空间的释放。在i d e _ e n d r e q u e s t 中,我们要在合适的时机把该次r e q u e s t 中所有用来存放数据的d a t a 和管理d a t a 的b u f f e r _ h e a d 处理掉,采用的方法和正确读取数据之后对于这些结构体和缓冲区的处理方法一样:首先暂存r e q u e s t 中b h 所指向的b u f f e r h e a d 结构体;接着对r e q u e s t 中指向的b u f f e r h e a d和d a t a 进行释放操作,这是由b l k d e v h 中的b l k _ f i n i s h e d _ s e c t o r s 函数实现的;处理完之后通过暂存的前一个b u f f e r _ h e a d 使得下一个b u f f e rh e a d 前移,按照上面的方法继续调用b l k f i n i s h e d s e c t o r s 进行处理,直到所有的d a t a 和b u f f e r _ _ h e a d 都处理完毕。下面的一些示例代码展示了这个过程:w h i l e(b h=r e q 一 b h)!=N U L L)更新该次请求可读的块号底层清理函数b l k _ f i n i s h e d s e c t o r,3(r e q,n s e c t);处理下一个b u f f e r _ h e a dr e q 一 b h=b h 一 b _ r e q n e x t:i f(b h=r e q 一 b h)!=N U L L)更新要处理的块号r e q 一 h a r d s e c t o r+2n s e c t;r e q 一 h a r d _ n rs e c t o r s 一e l s e当作正确读到而返回1r e t u m1;图3 容错机制流程图代码中r e q 是r e q u e s t 结构体类型的变量,b h 是b u f f e rh e a d 结构体类型的变量,n s e c t 是一个d a t a 里的块数,h a r d _ s e c t o r、h a r d n r s e c t o r s 是r e q u e s t 的内部成员,分别存放的是当前要处理的块号和本次读请求的所有块数,会随着清理工作的进行而更新;万方数据5 期王建慧等:基于L i n u x 操作系统的光盘容错机制6 5(3)跳过相应的块数之后,下一次则按照正常的读操作进行,如果读操作正确,则进入到正确读操作流程,否则跳块操作持续下去直到光盘最后或者连读错误次数达到上限值M。4 结束语本文通过软件机制在L i n u x 驱动程序层次实现了一定的光盘容错机制,提高了对损坏光盘的容错性能。本方案经过大量的测试并初步用于高清媒体播放器中,结果表明,对于8 5 以上有坏块的光盘,在遇到损坏的部分时,经过修改的驱动程序可以对其继续读取,而未经修改的则长时间卡在损坏的地方不能继续读取。但是,本方案也有一定的局限性,测试结果表明:对于损坏比较严重的光盘,软件层次的检验需要花费不少的时间;另外,扇区块跳读的速度也不是最快的,有待于进一步的优化措施。参考文献1(美)鲁比尼等著,魏永明等译L i n u x 设备驱动程序(第二版)北京:中国电力出版社,2 0 0 2 3 4 6 3 9 72D a n i e lP-B o v e t,M a r c oC e s a t i 著U n d e r s t a n d i n gt h eL i n u xK e r n e l(2 n dE d i t i o n)O R e i l l y,2 0 0 2 1 5 03 孙树清,陈萍可录型光盘与菁染料光存储媒体的研究进展化学通报,1 9 9 9,(第6 期):4 宋宝华著L i n u x 设备驱动开发详解北京:人民邮电出版社,2 0 0 8 2 7 l5l i n u x 一2 4 3 3 2 t a r 乎,f t p:h p k e r n e l o r g p u b l i n u x k e m e l v 2 4 2 0 0 6 一0 8 2 2 作者简介王建慧,男,1 9 8 4 年,硕士生,研究方向:嵌入式文件系统。白凤娥,女,1 9 6 6 年,教授、硕士生导师,研究方向:计算机监控系统。万方数据基于Linux操作系统的光盘容错机制基于Linux操作系统的光盘容错机制作者:王建慧,白凤娥,WANG Jianhui,BAI Fenge作者单位:太原理工大学计算机与软件学院,山西,030024刊名:微计算机应用英文刊名:MICROCOMPUTER APPLICATIONS年,卷(期):2009,30(5)参考文献(5条)参考文献(5条)1.linux-2.4.33.2.tar.gz 20062.宋宝华 Linux设备驱动开发详解 20083.孙树清;陈萍 可录型光盘与菁染料光存储媒体的研究进展 1999(06)4.Daniel P Bovet;Marco Cesati Understanding the Linux Kernel 20025.鲁比尼;等;魏永明 Linux设备驱动程序 2002 本文链接:http:/