f2fs中node page的lock_page

node page的lock_page首先是为了改变page的状态:set_page_dirty, 还有set_nid操作时也会设置父节点的nid, 但是这样设置node-page的粒度是不是太小了!

node_page首先不会有用户态的进程去操作它, 因为node对用户态是透明的, 所以lock_page node page的处理的race condition是:

node分成两类:dnode和间接node, 对于dnode, 需要处理的gc和f2fs_write_data_page之间的

dnode的lock_page处理的是gc&f2fs_write_data_page的互斥;

gc是一个非常简单的进程, 找到了文件的node之后,就直接move_data了,原来GC才是整个f2fs文件系统的终极大boss! 里面包含着一个非常重要的互斥: gc和truncate互斥!

因为整个gc的过程是通过SSA完成的, SSA中存放的是这个block的dnode的nid,然后再通过这个nid找到nid所属的ino的信息;

由于SSA一经写回便不再修改, 所以参照SSA去回收数据的时候, 最重要的一个参考就是sit bitmap, 这是个超重要, 如果一直以来没有操作这个文件还好, 一旦发生了文件的写操作, 导致了异地更新, 那么这个block就是无效的, 但是sit的判断已经过了呢! 还有一个问题, 那就是truncate部分数据, 以及truncate掉这个文件所有的数据, 会发现,这个block的地址都是无意义的才对, 但是SSA中这一块的数据仍然是在的!

如何判断一个inode的数据仍然是在的呢?

首先根据summary中的nid得到node_page, node_page中的信息就丰富了(这个另谈), 然后根据nid的信息, 我们查找nid_root基树, 根据这棵树, 我们就能找到这个nid更丰富的信息, 包括这个nid的blkaddr, ino, version, 还有flag, 当然这个flag是指CHECKPOINTED那些, 是给fsync, recovery机制用的!也就是说, 根据SSA中的nid, 基本这个文件的信息就全乎了!

那么下面说说各种竟态条件:

1) 当文件发生了异地更新. 此时, 这个nid依旧是坚挺的, 我还要用,  但是我node_page中的索引发生了变化, 所以需要判断一下是否是node_page[ofs] 是否是和 blk_addr相等,

2)当文件发生了truncate操作. 分两种情况, 该data_block的dnode是否被删除了, 如果没有, 那么可以归结为状况1), 如果被删除了, 那么这个nat_entry中version就要+1了, 并且已经没有了dnode,  连地址都没得比![看来, 看lock_page还是对的, 瞅瞅, version一直以来的未解之谜终于解开了! ]

3)当整个文件都被truncate掉了, 可以归结为状况2);

应该没有其他的情况了, 因为f2fs的代码里面也就说了1)和2), 哎, 我也不想了, 心累!

但是, 还!没!完! 还有更高级的大boss在等着, 那就是这里到底是如何处理互斥的,

可以看到, 这里和互斥相关的代码有两部分, 首先看gc部分:

gc中的代码主要是上来先把dnode的锁(lock_page)持有了, 这个就很重要了,  因为我们发现, 当异地更新truncate的时候,  也是先要试着得到dnode的锁才能进行下面的操作呢(异地更新:do_write_data_page, truncate:truncate_dnode)! 数据更新部分都是在这两部分之间完成的!

但是整个代码是值得商榷的, is_alive函数里面, 在dnode在lock_page的前提下进行的inode的检查, 检查完了之后, 就直接退了出来,  假设就在这个时候, 发生了do_write_data_page 或者 truncate_dnode, 那么is_alive一步的检查也被过滤掉了, 其实可以最大限度地过滤掉无用segment!

-----------------

至此, f2fs文件系统里面,基本所有的元数据都研究结束了!

那么, high level地去看文件系统中的锁, 有如下心得:

1) 文件系统会暴露出外部接口供用户态使用:write/read/truncate/mkdir/unlink/fallocate等等, 这些操作都是有 inode->i_mutex 保护, 这个锁的粒度是很大的, 可以屏蔽掉我们许多的顾虑. inode->i_mutex加锁, 是为了达到用户文件操作层面的原子性, 这一点是很重要的, 因为涉及到文件元数据的更新, 一定不能同时进入这个共享资源区!

2) 许多重要的元数据的变化都是外部文件系统接口变化引入的, 比如 f2fs 文件系统, truncate 的时候, 会涉及到大面的 nat_entry 基树中节点的数据变化, node page中无效索引的变化

3) write_back过程涉及到如下几个点: ①元数据的更新, 因为涉及SIT的update, SSA, 还有全局的数据, 包括valid block的数目等, 所以需要有f2fs_lock_op来保证与write_checkpoint的互斥! ② 由于data page已经被lock_page住了, 所以我们最害怕的truncate操作肯定是不用担心了, 因为truncate这个page的时候会lock失败的, 因此此时此刻, 不会又进程会碰到这个页, 这样也不会碰到这个page的dnode也不会出现什么问题, 所以这个page是安全的, 此时dnode的page已经创建了, 但是此时此刻, dnode应该也是安全的[会不会有一个竟态? truncate的时候, 不都是先得到dnode, 然后再去truncate里面的数据的吗?应该不会, truncate之前会truncate掉所有page-cache中的页!]

4) write_back完了之后, 很可能马上会触发truncate操作, 此时就很尴尬了, 刚写回的东西是无效的了, 但是不影响我们文件系统的行为!

突然想起一件事情, 在这里白扯白扯, 就是在write_checkpoint的时候, 怎么就能保证文件系统的一直性呢? 首先, 我们会把所有的脏的dentry写回, 然后把脏的node_page写回, 然后一些基本的元数据也是一样一样地写回去, 然后就是一些基本的数据了,包括NAT, SIT,SSA等信息, 但是, 这个时候有个很尴尬的问题, 那就是NAT, 包括dnode中有很多索引都是NEW_ADDR(-1), 即数据都还没有写回呢都!

首先NAT是不会出现这个问题的, 因为write_checkpoint的时候, node的page会强制的刷回, 这样一来, 所有已经分配的NID, 其对应的node都会对应的, 所以这个是无所谓的, 但是dnode中还是可能会存在NEW_ADDR的情形,  这个时候就说明上次数据没写回就强制断电了!

时间: 2024-12-15 14:41:20

f2fs中node page的lock_page的相关文章

文件系统学习之八:SVR4中的Page Cache

在SVR4中,所有文件的读写都会经过Page Cache.不同于有固定长度的物理cache,或者buffer cache, 或者DNLC. PageCache和其他cache的区别在于:它可以根据软件需求换进或者换出.另外也和buffer cache不同:buffer cache用设备和块号来索引cache,而page cache用vnode和offset来索引. page cache的构成 一个支持seg_map操作(比如当前段的缺页异常处理)的段: 一个具有多种用途的空闲页表链表(list)

回发或回调参数无效。在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true" %> 启用了事件验证。

回发或回调参数无效.在配置中使用 <pages enableEventValidation="true"/> 或在页面中使用 <%@ Page EnableEventValidation="true" %> 启用了事件验证.出于安全目的,此功能验证回发或回调事件的参数是否来源于最初呈现这些事件的服务器控件.如果数据有效并且是预期的,则使用 ClientScriptManager.RegisterForEventValidation 方法来注册

cocos2d-x中Node中重要的属性

cocos2d-x中Node中重要的属性 Node还有两个非常重要的属性:position和anchorPoint. position(位置)属性是Node对象的实际位置.position属性往往还要配合使用anchorPoint属性,为了将一个Node对象(标准矩形图形)精准的放置在屏幕某一个位置上,需要设置该矩形的锚点,anchorPoint是相对于position的比例,默认是(0.5,0.5).我们看看下面的几种情况: 以anchorPoint为(0.5,0.5)为例,这是默认情况. 下

Linux系统中的Page cache和Buffer cache

Linux系统中的Page cache和Buffer cache Free命令显示内存 首先,我们来了解下内存的使用情况: Mem:表示物理内存统计 total:表示物理内存总量(total = used + free) used:表示总计分配给缓存(包含buffers 与cache )使用的数量,但其中可能部分缓存并未实际使用. free:未被分配的内存. shared:共享内存. buffers:系统分配但未被使用的buffers 数量. cached:系统分配但未被使用的cache 数量.

TP框架中的page分页实现

今天介绍一下如何在tp框架中使用分页功能(TP3.2) 1.第一步,找到我们需要使用的分页类(page.class.php),并将其放在命名空间根目录下的一个位置,比如Library文件夹下或者当前模块下(例如Application  ) 打开分页类,修改命名空间 2.第二步,找到需要分页功能的控制器中相对应的操作方法 public function index(){ $art=M("article"); //分页显示方法 $zts=$art->count(); //查询总条数

JSP中关于Page的学习

Page是用来定义整个页面的属性 Page的属性:contentType, import, language, session, buffer, autoFlush, isThreadSafe, pageEncoding 格式:<%@ page 属性1=”属性值1”,”属性值2” 属性2=”属性值”%> 一个属性指定多个属性值时属性值用引号,属性值之间用逗号(标点英式) Page的多个属性之间空格 langusge属性:目前只能指定Java语言. 格式:<%@ page language

Cocos2D中Node的userObject实例变量使用时一个要注意的地方

大熊猫猪·侯佩原创或翻译作品.欢迎转载,转载请注明出处. 如果觉得写的不好请告诉我,如果觉得不错请多多支持点赞.谢谢! hopy ;) 我们知道在Cocos2D中,CCNode对象有一个ivar为userObject,它可以用来很方便的存储一些和该对象相关的数据,这样你就没必要费劲的去写子类继承了. 但是要注意的是,如果你的node添加到一个节点当做子类,比如: [someBaba addChild:myNode]; 那么在调用如下一句将myNode从父节点中删除时,其中的userObject也

WebStorm中Node.js项目配置教程——项目设置

上一章讲解了Node.js项目在WebStorm中的两种创建方式,当完成Node.js项目创建以后,剩下的就是涉及配置设置工作. 为了确保Node.js全局和Node.js核心模块的代码完成功能,打开Settings|Languages & Frameworks | JavaScript|Libraries进行设置: 值得注意的是:WebStorm将建议创建一个Node.js依赖的JavaScript库,并添加到列表用于代码完成.语法突出显示.导航和文档查找等. 对于Express框架,可以直接

JS中Node节点总结

Node的三个基本属性: 1.nodeType:表明节点类型,1是元素节点,3是文本节点. 2.nodeName:  表明节点名称,元素节点为标签名,文本节点为#text. 3.nodeValue:表明节点值,元素节点为null,文本节点为文本内容. Node的节点关系: 1.parentNode与childNodes parentNode寻找当前节点的父节点,childNodes寻找当前节点的子节点,其中包括文本节点和元素节点(特别需要注意空白的文本节点也算是节点)如下程序 <!DOCTYPE