Chinaunix首页 | 论坛 | 博客
  • 博客访问: 31025
  • 博文数量: 6
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 18
  • 用 户 组: 普通用户
  • 注册时间: 2015-01-06 20:34
个人简介

better in time

文章分类
文章存档

2015年(6)

分类: LINUX

2015-01-07 18:40:19

pagecache层在调用文件系统提供的get_block()函数分配数据块时,如果成功分配,那么需要调用unmap_underlying_metadata()对新分配的数据块做如下处理:根据新分配磁盘块的块号,从文件系统所在的块设备基树中查找相应的buffer,如果buffer存在,1.清除buffer的dirty标志,2.等待buffer的IO完毕.那么,文件系统为什么无法保证buffer的dirty标志被清除?起初猜想的原因:使用dd等工具直接写裸盘,导致buffer cache中存在脏buffer,文件系统分配磁盘块时恰巧分配到了这些脏buffer对应的磁盘块,此时必须将buffer的dirty标志清除,避免脏buffer回写,破坏文件的内容,后来一想,内核是不负责buffer cache和page cache之间的同步的,也没法负责,unmap_underlying_metadata()的作用绝不是处理用户态程序弄脏buffer cache的情形.从unmap_underlying_metadata()函数的字面意思看,应该是处理元数据引起的脏buffer问题,但是文件系统(ext23)的元数据:超级块,块组,inode表,inode位图,数据块位图都是在做文件系统时确定的,是不可能作为数据块分配给文件的,唯一可能的元数据是文件的间接数据块,因为文件删除后,文件的间接数据块也会随之释放,但是间接数据块还可能保留在块设备基树中,随后,其他的文件分配数据块时,可能分配到这些间接数据块,那么文件系统在释放这些间接数据块之前,随手将间接块buffer的dirty标志清除不就干净了吗?事实上ext2就是这么做的:
ext2_free_branches()
 bforget(bh);
  clear_buffer_dirty(bh);
 ext2_free_blocks(inode, nr, 1);//释放间接块(树枝)对应的数据块
ext2在释放间接数据块以前,会先清除buffer的dirty标志,保证释放的数据块被重新分配给其他文件时肯定是干净的,当然等待buffer IO完毕是必要的.那么其他文件系统(如:ext3)为什么不能这么做呢?原因是日志!ext3释放间接块的代码:
ext3_free_branches()
 ext3_forget(handle, 1, inode, bh, bh->b_blocknr);
 ext3_free_blocks(handle, inode, nr, 1);
ext3使用ext3_forget()代替了bforget(),ext3_forget()的处理流程:
ext3_forget()
 journal_revoke()
  journal_forget()
   //jh属于当前运行的事务
   if (jh->b_transaction == handle->h_transaction) {
    //jh属于当前运行的事务,可以直接清除dirty标志
    clear_buffer_dirty(bh);
    clear_buffer_jbddirty(bh);
    if (jh->b_cp_transaction) {
     __journal_temp_unlink_buffer(jh);
     __journal_file_buffer(jh, transaction, BJ_Forget);
    } else {
     //jh只被当前事务看到,直接删除
     __journal_unfile_buffer(jh);
     journal_remove_journal_head(bh);
     __brelse(bh);
     __bforget(bh);
    }
   else {//jh属于正在提交的事务,不能修改其状态
    if (jh->b_next_transaction) {
     jh->b_next_transaction = NULL;
    }
   }
journal_forget()函数中,如果jh属于当前运行的事务,那么可以直接清除bh的dirty标志,如果jh不在检查点事务中,可以直接执行__bforget(),此时,和ext2的做法是一样的.关键在于,如果jh属于正在提交的事务,按照事务操作bh的原则(如果buffer不属于事务A,那么事务A是不能修改buffer的状态的),当前运行的事务不能清除buffer的dirty标志,正在提交的事务提交完毕后buffer脱离JBD的管理,其dirty标志被置位,等到当前运行的事务提交后(间接块的数据块位图写入到日志空间),buffer对应的磁盘块就可以被重新分配使用,如果此时回写子系统还没来得及将buffer回写(清除dirty标志),即会出现get_block()分配的磁盘块在buffer cache中dirty标志置位的情况.综上,get_block()后需紧跟unmap_underlying_metadata()还真不是文件系统挖坑,确实是文件系统有苦衷!
阅读(1462) | 评论(0) | 转发(0) |
0

上一篇:没有了

下一篇:对通用日志层JBD的理解

给主人留下些什么吧!~~