stage 0 Basic Workflow
- 从一个文件是如何被访问到的开始.来阐明inode/硬链接/软链接到底是啥.
例如,在linux中,访问一个文件,需要给出文件名,得到的结果是获取到该文件的内容. - 例如我现在输入 cat /tmp/fuckfs.txt
整体流程是什么呢?
大致过程如下:
带路径文件名 ---->访问目录文件(directory)---> 目录项(dentry)---->inode ----> blocks ----> disk(请求落盘).
目录也是文件,并且该文件的内容是一堆的目录项表示该目录下的文件,另外目录可以嵌套.
目录文件内容大概是这样:
dentry_0
dentry_1
...
dentry_M
linux 文件类型有这么几种:普通文件(regular)、目录文件(directory)、软链接(symbol link)、块文件、字符文件.
其中一个目录项(dentry)大概是这样:(一个pair关系)
| file name | inode num
|-----------|------
| file1 | 1234
|-----------|------
这里根据文件名得到inode编号,接着可以在inode-table中得到具体某个文件的inode.接着根据inode中的数据域可以访问文件的内容.注意这里的inode也可能是目录文件的inode, 要读目录文件内容也需要读其inode得到数据域.
一个inode是一个文件的一些信息描述(权限、大小、修改时间等)及数据域,其大致结构大概像下面这样:
|--------------------+--------------------------...------------------------------------------------|
|mode | size | owner | inlining | direct_blks | indirect_blks | double_ind_blks | triple_ind_blks |
|--------------------+--------------------------...------------------------------------------------|
其中inode的数据域可能有inlining - 当文件非常小时,文件内容可以直接存在inode节点中,具体需要看哪种特定的fs.
一般(古典)可以认为inode最后几个域有几种不同级别的数据块索引,以支持大文件.(以前经常碰到计算题,计算文件大小的就是这些不同级别的数据块索引在捣鬼)
ok,到了这里可以回答上面的问题了,cat /tmp/fuckfs.txt
的流程无非是,
- 读/目录文件的inode,找到其数据域
- 在其内容中找到/tmp所在目录项,根据目录项提示的inode编号读/tmp目录文件的inode
- 找到其数据域,在其内容中找到/tmp/fuckfs.txt的目录项,根据该目录项提示的inode编号读/tmp/fuckfs.txt常规文件的inode
- 找到其数据域,返回数据块内容.
另外这里还有种问法就是cat /tmp/fuckfs.txt
这个命令最多可能访问磁盘几次? 最多就是inode都得来一次,读目录文件的内容也得来一次(虽然现在有些fs可能目录里文件比较少的直接扔inode里面了,但我们考虑最多嘛),最后读该txt文件的数据块再来个几次(当文件比较大的时候,虽然现在的fs一般都会把同一个文件的数据块都尽量放在同一个512bytes之内),反正只要fs设计的足够SB,磁盘可以读很多次.
stage 1 软链接/硬链接
硬链接
硬链接实际上是文件的别名,当为一个文件创建硬链接,实际上就是在文件所在目录的目录文件中增加一个<文件硬链接名,inode编号>的pair关系.
这里的inode编号与原文件inode编号一致,并且该inode上的links域会增加1.
这样,删除原来的文件,则利用创建的硬链接也能访问原始文件的数据.
(实际上是这样的,但其内部如何实现的删除给人好多联想,删除是否都是只把目录项下的dentry删除呢?)
软链接
软链接又称符号链接,是一种特殊的文件,文件内容是链接到的文件的路径(? 这个要在查一下?).
给一个文件创建软链接,原始文件的inode的links数不会增加,新创建出来的软链接的inode编号与原始的不同(其实他们就是不同的文件).软链接可以重新指定链接的目的地(dest).(硬的也可以,不过会使links数减1)
------->很像c++里ref与ptr的区别吧?
但仅是很像而已,硬链接这里也可以更改的,例如用ln -f
强制更改.只不 过后遗症就是假如原始文件没人链接了,那么原始文件也就读不了了.
root@vm1:~/test_inode# touch testk
root@vm1:~/test_inode# ln testk testk.hard
root@vm1:~/test_inode# stat testk
File: ‘testk’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 801h/2049d Inode: 1052967 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2016-06-26 20:06:08.253381199 +0800
Modify: 2016-06-26 20:06:08.253381199 +0800
Change: 2016-06-26 20:06:16.537381272 +0800
Birth: -
root@vm1:~/test_inode# stat testk.hard
File: ‘testk.hard’
Size: 0 Blocks: 0 IO Block: 4096 regular empty file
Device: 801h/2049d Inode: 1052967 Links: 2
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2016-06-26 20:06:08.253381199 +0800
Modify: 2016-06-26 20:06:08.253381199 +0800
Change: 2016-06-26 20:06:16.537381272 +0800
Birth: -
这在补充一下,所以inode与文件名
不是一一对应的.
也有种说法就是inode与文件
不是一一对应的,多个文件
共享同一个inode也就是硬链接的情况.唉笔试嘛,就是喜欢搞文字游戏.
stage 1.2 what the fuck is VFS
我目前个人的理解就是在文件系统层次进行一种抽象(很像c++ OOP里定义的抽象类),VFS只定义了一套需要实现的接口,具体下面怎么做的是由具体哪一种文件系统被用到来决定的.
stage 2 现代文件系统的实现
妈的这个题目太大,吓尿了.
主要是上面讲的一些都是很基础,面试里才会考的东西,如果接到任务需要搞(定制)一个文件系统呢?
目前的信息 & todo
- 上面只讨论了最基本的一些逻辑上的处理,还需要了解一下实际中的一些重要的东西例如磁盘的布局(disk layout,描述了哪里放超级块,哪里放inode的bitmap等等)
- 某些fs带有LSM特性的,自带GC,支持日志,可以减少随机写的落盘.例如xfs,f2fs.
- 某些fs在inode的实现上除了posix定义的标准之外,还实现了其他的一些机制,比如对小文件的支持(inlining feature)等.
- 某些(目前大部分)的fs在目录项的获取上做了一定(很多)的优化,例如inode可能会有cache之类的.
- 某些(大部分)fs可能会把多个inode包起来形成一个extent,用来优化读inode的overhead.
引用一下f2fs的图: