日期:2014-05-16  浏览次数:21054 次

多角度分析为什么 Linux 的硬连接不能指向目录

译者注: 最近在看文件系统相关的,每当读到inode相关的东西时,书上或者博客上都会涉及硬链接/软链接相关的内容,于是今天专门针对硬链接翻译了几篇英文,弄懂它!

一、硬链接

本节翻译自:http://c2.com/cgi/wiki?HardLink

在传统的UNIX文件系统中,一个目录就是一个包含关联列表的文件。目录文件中的条目是字符串形式的文件名及其对应的唯一文件标识符-- inode号。一个inode号本质上是一个磁盘上的指针,文件对象可以高效的通过它定位。没有两个磁盘对象共享一个inode号,也没有一个磁盘目标有两个inode号。

“硬链接”本质上是“目录项”的同义词当一个目标第一次被创建,就会为它创建一个目录项。这其实就是硬链接,而大多数人常常把“硬链接”联想成“为一个已有的对象创建一个额外的目录项”。但是原来的目录项其实没有任何特殊,所有的链接都是平等的,所以一定意义上来说没有方法能识别出哪个是原来的。

目录也可以包含目录,当然,这是通过硬链接完成的。当一个子目录被创建时,在其父目录中也创建了一个目录项,这个目录项用于将子目录的名称与新创建inode关联起来。此外,新的目录文件中也自动创建了两个目录项,这两个目录项分别将"."".." 当前目录及其父目录关联起来。所以,创建一个子目录会创建一个新的硬件链接到其父目录,以及两个对新创建对象(子目录)的硬件链接:一个来自其父目录,另一个来自他自己("."),也就是说一个目录项的硬链接数最少是2。

long@zhouyl:~/test$ mkdir abc
long@zhouyl:~/test$ ls -l
total 1
drwxr-xr-x  2 long long 4096 Apr 17 09:02 abc
            |
            -- 硬链接数

目录硬链接比较特殊。首先,创建它们惟一的方法是创建目录;操作系统硬件链接函数不会允许一个硬链接的操作目标是一个目录inode。其中的原因是可能会在文件系统目录结构中产生循环。这也得根据内核,是否允许目录硬链接也需要遵从文件系统模块本身。

在传统的UNIX文件系统中,循环很不好,有如下两个原因:
第一,存储的回收是基于引用计数的,而它不处理循环引用。特殊的方向引用是"."和"..",但是它们是被当作特殊情况来处理的。
其次,在树形结构中方向引用可以导致恶心的多线程问题。在传统的内核设计中(比如BSD内核),正在使用的inode表现为内存中的结构 vnodes。这些节点被同时访问,并且包含锁。一些操作会在访问一个目录的子目录时保留该目录的锁。这可能会导致死锁的发生。这些锁操作一般是不能被信号中断的,所以死锁的进程会一直保持死锁状态直至重启。


在BSD中访问".."时有特殊的方法来避免这种死锁。基本上,在原来目录vnode上的锁刚释放,".."锁就被请求然后原来目录再次被锁。这就象一个竞赛一样。(这一段和下一段翻译得不好,但是和理解硬链接关系不大,其实上面已经解释的足够了!我只是想尽量完整而已)

曾经我实现了一个对于vnode锁的周期检测算法,尽量支持一个BSD版本的文件系统的循环硬链接,但是问题是:尽管程序运行得很好,但是很难让内核的其他部分配合。内核中的很多地方,比如文件系统驱动以上的层都简单地假设锁会成功,或者最终会成功,所以并没有处理EDEADLK错误的方法。这并不很清楚,甚至如果你被允许使用那些提示你一个死锁可能会发生的信息,你又该如何处理呢?你会打断所有的系统调用?你会使用什么样的重试?应用进程又该如何响应可能有死锁的随机文件系统操作?


二、为什么硬链接不能指向目录

这一节翻译自: http://unix.stackexchange.com/questions/22394/why-hard-links-not-allowed-to-directories-in-unix-linux

第一节中已经对硬链接和inode等概念有了很好的解释,但是为了保证原文的完整性,下面内容可能有重复解释!

2.1 从inode角度谈

允许目录的硬链接可能会打破文件系统的有向无环图结构,可能创建目录循环,这可能会导致fsck以及其他一些遍历文件树的软件出错。

首先,要想理解这点必须先了解inode。文件系统中的数据保存在磁盘上的数据块中,而这些数据块由inode集合在一起。可以说inode就是文件,但是inode缺少文件名,所以就需要链接。一个链接其实就是一个指向inode的指针。目录是一个保存着这些链接的inode,目录中的每一个文件名都是一个指向inode的链接。这里提一下,UNIX系统中打开一个文件也会创建一个链接,但是它是不同类型的链接(它不是一个命名链接)。
硬链接只是一个指向inode的额外的目录项,当你使用ls -l命令查看文件时,文件权限后面的数字就是命名连接数。绝大多数文件只有一个链接。创建一个新的硬链接到一个文件会将两个文件名指向同一个inode。
long@zhouyl:~/test$ touch test
long@zhouyl:~/test$ ls -l
total 0
-rw-r--r-- 1 long long 0 Apr 16 16:56 test
long@zhouyl:~/test$ ln test test1
long@zhouyl:~/test$ ls -l
total 0
-rw-r--r-- 2 long long 0 Apr 16 16:56 test
-rw-r--r-- 2 long long 0 Apr 16 16:56 test1


现在你可以清楚的看到,其实并没有什么硬链接,一个硬链接和正常的名字是一样的(这和第一节中介绍的硬链接一样,第一节中解释硬链接就是目录文