ext3 journal format

超好的一篇帖子:http://topic.csdn.net/t/20021222/01/1284250.html

讲journal在ext3 中起的作用

 

虽然没有人回应,我还是先自己讨论讨论吧。同样的东西在水木的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的块的标号。  

 

 

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值