文件系统,隐匿在 Linux 背后的机制( 二 )


举个例子 , 下面是一个使用链接之前的图
文件系统,隐匿在 Linux 背后的机制文章插图
以上所示 , 比如有两个工作账户 jianshe 和 cxuan , jianshe 想要使用 cxuan 账户下的 A 目录 , 那么它可能会输入 /usr/cxuan/A, 这是一种未使用链接之后的图 。
使用链接后的示意如下
文件系统,隐匿在 Linux 背后的机制文章插图
现在 , jianshe 可以创建一个链接来使用 cxuan 下面的目录了 。 ‘
当一个目录被创建出来后 , 有两个目录项也同时被创建出来 , 它们就是 . 和 .., 前者代表工作目录自身 , 后者代表该目录的父目录 , 也就是该目录所在的目录 。 这样一来 , 在 /usr/jianshe 中访问 cxuan 中的目录就是 ../cxuan/xxx
Linux 文件系统不区分磁盘的 , 这是什么意思呢?一般来说 , 一个磁盘中的文件系统相互之间保持独立 , 如果一个文件系统目录想要访问另一个磁盘中的文件系统 , 在 Windows 中你可以像下面这样 。
文件系统,隐匿在 Linux 背后的机制文章插图
两个文件系统分别在不同的磁盘中 , 彼此保持独立 。
而在 Linux 中 , 是支持挂载的 , 它允许一个磁盘挂在到另外一个磁盘上 , 那么上面的关系会变成下面这样
文件系统,隐匿在 Linux 背后的机制文章插图
挂在之后 , 两个文件系统就不再需要关心文件系统在哪个磁盘上了 , 两个文件系统彼此可见 。
Linux 文件系统的另外一个特性是支持 加锁(locking) 。 在一些应用中会出现两个或者更多的进程同时使用同一个文件的情况 , 这样很可能会导致竞争条件(race condition) 。 一种解决方法是对其进行加不同粒度的锁 , 就是为了防止某一个进程只修改某一行记录从而导致整个文件都不能使用的情况 。
POSIX 提供了一种灵活的、不同粒度级别的锁机制 , 允许一个进程使用一个不可分割的操作对一个字节或者整个文件进行加锁 。 加锁机制要求尝试加锁的进程指定其 要加锁的文件 , 开始位置以及要加锁的字节
Linux 系统提供了两种锁:共享锁和互斥锁 。 如果文件的一部分已经加上了共享锁 , 那么再加排他锁是不会成功的;如果文件系统的一部分已经被加了互斥锁 , 那么在互斥锁解除之前的任何加锁都不会成功 。 为了成功加锁、请求加锁的部分的所有字节都必须是可用的 。
在加锁阶段 , 进程需要设计好加锁失败后的情况 , 也就是判断加锁失败后是否选择阻塞 , 如果选择阻塞式 , 那么当已经加锁的进程中的锁被删除时 , 这个进程会解除阻塞并替换锁 。 如果进程选择非阻塞式的 , 那么就不会替换这个锁 , 会立刻从系统调用中返回 , 标记状态码表示是否加锁成功 , 然后进程会选择下一个时间再次尝试 。
加锁区域是可以重叠的 。 下面我们演示了三种不同条件的加锁区域 。
文件系统,隐匿在 Linux 背后的机制文章插图
如上图所示 , A 的共享锁在第四字节到第八字节进行加锁
文件系统,隐匿在 Linux 背后的机制文章插图
如上图所示 , 进程在 A 和 B 上同时加了共享锁 , 其中 6 - 8 字节是重叠锁
文件系统,隐匿在 Linux 背后的机制文章插图
如上图所示 , 进程 A 和 B 和 C 同时加了共享锁 , 那么第六字节和第七字节是共享锁 。
如果此时一个进程尝试在第 6 个字节处加锁 , 此时会设置失败并阻塞 , 由于该区域被 A B C 同时加锁 , 那么只有等到 A B C 都释放锁后 , 进程才能加锁成功 。


推荐阅读