免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 962 | 回复: 0
打印 上一主题 下一主题

ext3 journal format [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-08-04 21:48 |只看该作者 |倒序浏览

                虽然没有人回应,我还是先自己讨论讨论吧。同样的东西在水木的kernelTech版也发过了。如果想和我讨论,我的邮箱   xjaguar@263.net   
      
               这个post对我自己来说,目的有两个:一,有经验的,可以帮我检验一下   
   理解,没经验的,这可以作为一个入门级的文档;二,希望有兴趣的,能和我   
   一起做移植的工作。   
         
               EXT3,是在EXT2上设计的,可以说是   EXT2   +   Journal(日志)。Journal   
   是为提高可靠性而设计的一个特殊的文件(确切说来也可以不是文件)。基本   
   过程是,把对文件系统操作划分为一个个事务,使用Journal记录这些事务,   
   然后再实际执行他们。这样,即使由于当机,导致事务没有完成,也可以根据   
   日志,快速的把文件系统恢复到一个正确的状态。可以看出以上所说的基本原   
   理、术语,都数据库相类似的。   
   ====================================   
   文件系统特点   
               文件系统保存两类数据:元数据(meta-data)和用户数据。元数据即分区   
   特征、目录结构、文件属性。   
               UNIX环境中有字符、区块两类设备,通常文件系统是存储在块设备中。保   
   存这些数据的基本单元是block   (区块),它通常是实际磁盘上   sector   大小的   
   2的幂次倍。创建、删除和修改文件等动作的最终结果,都是体现在对区块的   
   修改。   
      
      
         
   比如ext2分区中建立一个文件,需要完成这几步,(未必按照这个顺序)   
      a.分配inode,   
      b.需要找到他所在目录的inode,向他的数据中加入新的目录项,   
      c.分配文件所需的数据块。   
      d.修改分配inode的数据   
   (如果这些操作没有一起完成,那么你的磁盘上的文件系统就有点小问题了。)   
         
   显然这里至少修改了:   
   1(superblock)+1(inode-bitmap)   +   1(inode-table)+   1(block-bitmap)   
   这四个块。这也意味着,有了这四个块的正确数据,就足够把这个操作恢复了。   
   ===================================   
   缓存特点   
               缓存对文件系统显然是绝对不能少的,Unix的缓存的基本特征它以虚拟块为   
   单位。即,读取文件时,由文件文件系统计算出给定文件位置所对应的块号,根   
   据这个号码再向缓存管理模块请求这个块的数据。(插一句:还有另一种策略,   
   让缓存和文件偏移量相对应。也就是说,每个内核中的文件控制块(和物理文件   
   一一对应的数据结构)保存独立的缓存映射表,根据这个表可以直接从文件位置   
   (偏移量)找到数据,不需要文件系统的计算。这是NT的Cache   Manager采取的   
   策略。)   
               这种结构使得journal层纪录的东西可以大大简化。它只要记住被修改的块   
   的编号和数据,就可以完成恢复。这个设计很妙,好处是journal层和文件系统   
      
      
   的耦合很小。其结果:   
               文件系统的恢复可以不需要具体文件系统代码的参与。文件系统只需要说:   
   journal层,你给我检查xxx分区,有错的话就恢复它。而Journal层有足够的信   
   息完成它。如果journal层中记录的是文件的操作:   
         如"创建大小为xxx,属性为yyyy的   /xyz/xxx   文件",   
   恢复的时候,没有文件系统代码的帮助,journal层没办法完成。两边代码都少   
   了。   
            不同的文件系统都有可能使用一个journal层。道理很简单,对吧。   
   ===================================   
   Journal记录的数据   
                           Journal提供两种记录模式,一种只记录元数据,另一种记录所有写入的数   
   据。第一眼看到,你就会感觉"第二种方式很可能慢"。的确,按照设计者自己   
   的说法,性能差不多减半,因为数据要写到journal和实际文件两个地方,即写   
   了两次。同时,第一种方式有可能会产生意料之外的问题。因为既然Journal只   
   记录了元数据,那么就只能保证元数据的一致性,但是用户数据就…,所以用户   
   可能会看到原来的数据,甚至看到原本属于其它文件的数据(可能的安全漏洞哦,   
   不过这个问题的对策设计者自己也有说)。   
               不过我自己总是在想,有没有避免第二种方式中写入两次的办法?如果有,   
   那就可以放弃第一种办法。你有什么想法?   
   ==================================   
   对外接口   
            有了上面的概念,自然就该转到接口定义了。Jbd提供给文件系统层的一个   
      
      
   要修改inode-bitmap时,告诉jbd,我要修改一个和inode-bitmap所在块对应的   
   缓存;做完了,告诉jbd,事务结束。   
               这个东西现在好像文档还是很少(至少98年,ext3就应该在开发过程中了)   
   关于接口,比我刚才说的稍详细的文档在:   
   Documentation/DocBook/journal-api.tmpl   
   (make之前的,起始位置自然是你的linux源文件的目录)   
   ==================================   
   实现。。。   
         
            头大的问题,其实让我看jbd的实现的原始动机是移植ext3,在看ext3时又   
   发现还有个jbd。事情常常就是这样在以出人意料的方式连接在一起,对于我   
   这样的初学者来说。  
(继续实现部分)   
         
   实现·块缓存读写   
         
            Jbd中有一个专门的线程(执行的函数   fs/jbd/journal.c:   
   int   kjournald(void*))来根据一定的时间间隔去写将事务写入journal文件。   
   把事务写入,这显然不会是一个简单的操作,会要多部分数据,而文件系统可   
   能也要访问某一个块,所以同步问题又来了。在jbd中,有一个全局的   
   spinlock   journal_datalist_lock。(这个锁本不该是全局的,它会把多个   
   ext3分区的块缓存都用一个锁保护起来,实现中仍这样做的原因可能是全局   
   锁实现起来更简单,而设计者没有时间修改)。   
               事务是在纪录对块的操作,不可避免的会出现在几个事务中访问同一个   
   块。所以,jbd不但要能从事务找到它涉及到的块缓存,同时也要能从块缓   
   存知道它在那个事务中被用到。那么要记录多少个从   "块缓存->事务"   的这   
   种关联?答案是一个。   
               如果两个事务都在写,逻辑上没问题,后一次将覆盖前一次的结果。但   
   是,运行时却要复杂很多。比如,事务31要写块7511,之后事务32也写7511,   
   该怎么办?设计者选择的是copy-on-write(所以“答案是一个”:),将缓存   
      
      
   复制一份,交给…写。   
               把"谁"给"谁"?设想这时候还有人需要读块7511,它应该读到那个数据呢?   
   应该是32将处理的那个缓存。所以,缓存复制后,新复制出来的一份交给事   
   务31处理,旧的(jbd注释中把这个叫做primary   copy)交给事务32或是读者。   
   不过这部分的代码看起来比上面的要复杂得多。   
         
   实现·删除文件   
         
               按照设计者Dr.   Stephen   Tweedie的说法,"对于所有日志式文件系统的   
   设计者来说,删除文件是噩梦的来源"。   
               从一个例子来说。先删除目录   ./temp1(事务44),向文件./text按追   
   加模式写入数据(事务45)。具体点,删除目录导致释放目录使用的块7511;   
   追加数据时恰巧给./text   文件分配了块7511,然后写了一句话"nightmare",   
   就在这时,宕机了。   
               还有其他事情碰巧也发生在一起了:journal层没能把上面这两个事务记   
   录在案。世界重新开始,自然目录./temp1保留了下来,而且内容却是   
   "nightmare"。   
               解决的方法…,我并没有在代码中找到,倒不是说一定就没实现。也许,   
   被移到ext3的实现代码中,由ext3尽可能保证不将刚释放掉的块立即再使用。   
         
   实现·on-disk结构   
      
               这里的信息全部来自于阅读代码,主要出现在函数:   
               fs/jbd/transaction.c:   journal_commit_transaction   和   
               fs/jbd/recovery.c:   journal_recovery   。   
   所以,即是第一手资料,又很可能会有遗漏。   
         
               每个事务在文件里包含了三个区域:块描述符区,Revoke区和Commit区。   
   每个区都有共同格式的标头。标头中包含常见的MagicNumber,区类型标示符,   
   这个区所属的事务的标示号。   
         
   描述符区:   
         
               在标头之后,是一系列的journal_block_tag_t结构,这些tag之后,是   
   同样数量的数据块,每个tag,记录了后面一个数据块实际的区块号。   
         
   Reovke区:   
               这个区的结构和实现过程倒是不难理解。Revoke,按照字典的意思,是   
   废弃,似乎和删除等有关系。不过从何它相关联的东西看,似乎它的作用很   
   少。   
               还是从假设说起。试想事务34记录了对块7511的写动作,事务35里记录   
   了"删除"7511的动作。让我们从两个面来看:在恢复过程中,上面这样的动   
   作显然只需要做事务35里的"删除"(实际上就是jbd什么也不做);但是jbd在   
   记录时必须记下来,因为当还在34处时,它没办法预知未来要发生的事情。   
      
               块结构:在标头后是多个被Revoke的块的标号。   
         
   Commit区:   
               这里的数据最简单,除了标头区内别的数据完全没用。这个区的逻辑意   
   思是:这个事务被完整地记录了。   
      
               块结构:在标头后是多个被Revoke的块的标号。   
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/53103/showart_1106203.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP