首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Linux 文件系统中元数据使用计数的机制(3)分布式文件系统对使用计数机制的扩展

Linux 文件系统中元数据使用计数的机制(3)分布式文件系统对使用计数机制的扩展

分布式文件系统和本地文件系统有所差别,典型的结构由三部分构成:客户端、元数据服务器、数据服务器。它的一个特点就是允许多客户端的模式,因此有些场景跟单机的模式不大一样。
查找后的 revalidate前面提到过,在查找操作中,会先到内存去找,如果找不到还要到具体文件系统的磁盘上去取。在分布式环境中,当一个客户端更新了一个文件,从而相应地修改了其元数据,其他客户端并不能马上知道这个更新,于是当查找操作在内存中找到所要的元数据后,会判断一下文件系统是否实现了 d_op -> d_revalidate 这个接口函数,如果实现了,就会再到元数据服务器取一份最新的元数据,从而保证客户端缓存中数据的有效性,这也是这个操作名称叫做 revalidate 的原因。
本地文件系统如 Ext2, Ext3 都没有实现这个接口函数,也没有必要。 NFS 中是有实现的。
前面说过,查找操作会增加 dentry 的使用计数,也就是说不管走了什么路径,只要找到了所需的元数据,那么通过查找操作所返回的 dentry 结构,其使用计数是增加过的。所以具体文件系统的 d_revalidate 函数也要对 dentry 的使用计数进行增加,这样才能和 VFS 层正确衔接起来。
dput 函数的变动大家是否还记得,前面介绍 dput() 函数时,曾经提到其处理步骤可分为五步,第2步中要判断具体文件系统是否定义了 d_op -> d_delete 这个接口函数。由于 Ext2, Ext3 都没有定义,我们也就跳过了这个判断。然而,在 NFS 中,是有定义这个接口函数的,但没有什么实质内容,基本就是直接返回。其实,是否定义这个函数是一个路口的转向。如果定义了, dput() 的流程就会直接跳转到函数 __d_drop() ,其作用是把 dentry 从哈希链上移除;再接下来就进入 dentry_iput() 尝试删除 inode 。
大家也许会奇怪,前面介绍了 dput() 和 unlink 操作之间那么多复杂的关系,怎么这里直接就都跳过了。这其实是分布式环境的一种解决方法。在分布式环境中,由于有多个客户端,只要有一个客户端进行了删除操作,相应的元数据就应该可以被删除。如果按照本地文件系统的那种机制,此时只有进行了删除操作的客户端才可以通过 dput() 最终走到函数 s_op -> delete_inode() ,从而在元数据服务器端释放元数据;其他客户端由于没有进行删除操作,它们的 dput() 都无法走到 dentry_iput() 那一步,更别说 s_op -> delete_inode() 了。所以在分布式环境中,就采用另一种思路:只要 dentry 的使用计数为1,此时调用 dput() 都可以走到 dentry_iput() ,如果此时 inode 的使用计数也为1,就能继续一直走到 generic_drop_inode() , generic_drop_inode() 可以继续走到 s_op -> delete_inode() 。这样,元数据服务器就可以自己记录有哪些客户端使用了这个 dentry ,而各个客户端在递减 dentry 的使用计数为0时,都会通过 dput() 与元数据服务器通信。元数据服务器就可以知道某个时刻是否还有客户端在使用这个 dentry ,从而当元数据被删除时决定何时可以进行释放。
这里还有一个问题。前面介绍过, generic_drop_inode() 会根据 inode -> i_nlink 是否为0来判断要调用哪个函数:
若 inode -> i_nlink为0,说明没有 hard link 指向该 inode ,可以将其删除,路径为:
1
generic_drop_inode() > generic_delete_inode() > s_op->delete_inode()




若 inode->i_nlink 不为0,说明仍有 hard link 指向该 inode ,不能将其删除,路径为:
1
generic_drop_inode() > generic_forget_inode()




也就是说 generic_drop_inode() 不一定能走到 s_op -> delete_inode() 。而且 inode -> i_nlink 会记录在具体文件系统的磁盘上,它的值是一个全局的值,而不是针对某个客户端的。所以一种解决办法就是不以 s_op -> delete_inode() 作为客户端与元数据服务器的通信接口,而以 s_op -> clear_inode() 作为通信接口。对于 s_op -> clear_inode() ,无论 inode -> i_nlink 的值为多少,都会被调用:
1
2
(1) generic_drop_inode() > generic_delete_inode() > s_op->clear_inode()
(2) generic_drop_inode() > generic_forget_inode() > s_op->clear_inode()




总结通过上面的介绍,我们看到了 Linux 如何对 dentry 和 inode 的使用计数进行操作:何时增加,何时减少。并且了解了元数据操作是如何通过这些使用计数来表明自己正在使用这些元数据的。我们也看到了当删除一个元数据后,如何等到所有使用者都把该元数据的使用计数递减为0之后,才真正对元数据进行释放。最后我们通过分布式文件系统的一些机制了解了在分布式环境下对使用计数的操作要做哪些相应的改变。
返回列表