1.linux下如何看待目录(文件名保存在哪里)
(1)
目录也是有自己的inode和数据内容的。目录的数据结构存的是其内部所有文件的文件名与inode之间的映射关系,也就是说一个文件得文件名是保存在当前文件所属目录得数据内容中。
磁盘无法区分普通文件和目录的,只能通过inode中的信息进行区分,也就是说磁盘中的文件系统只认识inode。
我们使用的所有文件名前面是默认带了当前路径的。
可以得到我们使用文件名打开一个文件的本质(不完全正确):OS先找到用户所在路径,然后打开目标文件所在目录的数据内容,找到所需文件名与其inode之间的映射关系,最后使用inode中的inode_number来在磁盘中进行文件的查找(此处也说明了目录的本质也只是一个普通文件,只是其的数据内容存的是文件与inode之间的映射关系)
其实这样就会发现目录自身也需要inode,因此有往前推找inode,最后一定会去到根目录(其的inode_number一直为2),然后在从根目录往后推导,因此访问文件的本质就变成了一条路径访问,这里也就说明了我们访问所有文件都是要有对应得路径的。
路径是通过进程提供的(bash),表层看是env,但从底层看linux的所有操作本质都是进程,从这个角度上讲路径由进程提供。
(2)struct dentry
如果每一次我们都要从根目录下进行路径解析,那么每次就会对磁盘进行多次IO操作,导致效率很低。因此OS在进行路径解析时会讲历史访问的所欲目录(路径)形成一颗多叉树并保存,这就是linux系统中的树状目录结构(是内存级的目录缓存),也就是说维护这个树状路径结构的是一个在内存中才存在的结构体->struct dentry。
dentry有一个成员list_head d_lru(淘汰链表),也就说dentry自身还是一个链表,当有些结点使用次数很少时,该链表就会注销掉该结点。

目录结构中是连最后的普通文件也要储存的。每一个dentry都有其自己指向的inode,因此才能通过dentry模拟路径解析的过程。(其实dentry也是struct file的一个成员,也就是说不是遍历到了这个文件才生成dentry,而是每一个文件本身就有一个struct dentry,被调用时才创建且刚开始时处于初始化的状态也就是并没有和其他文件之间建立起关系但其他必要的属性已经初始化完了)
例:新打开根目录下的一个文件,/目录用其存储的数据内容初始化该文件的dentry并连接,然后该文件就通过自己的dentry寻找inode中的数据。只是整棵树都是创建在内存中,该文件的磁盘数据内容和inode中并没有dentry这么一个结构体。
2.定位分区的方式
不同分区之间没有什么联系,inode只能定位分组和数据块的位置,那么是怎么定位一个文件所在的分区的呢?
我们实际上无法真的进入一个磁盘文件中进行操作,也就是我们无法直接使用一个分区。
我们必须将我们的一个分区与一个特定的路径进行关联,通过进入和修改这个路径中的数据来间接操作一个分区,这种行为就叫挂载.
指令:df -h
查看分区的情况,其中Mounted on就代表该分区挂载在哪个路径上
[root@VM-0-2-centos ~]# df -h
Filesystem Size Used Avail Use% Mounted on
devtmpfs 989M 0 989M 0% /dev
tmpfs 1000M 24K 1000M 1% /dev/shm
进入这个路径就相当与进入该分区了。
umount + 目录 -> 取消该分区的挂载。
所有的分区通过挂载就与路径有联系了,而我们在调用一个文件时,其所在的路径上一定符合某些挂载(分区)的路径。
也就是说匹配分区的方式就是将当前文件路径与所有的挂载路径进行匹配,根据就近原则与当前文件路径最像的那个分区就是这个文件所在的分区。
(1)介绍一下fopen的全过程
OS先通过路径缓存树查找到对应文件所在的目录,然后找到该文件与inode之间的映射关系,之后就能在内核中找到对应的inode与数据内容。然后OS在内存中创建该文件的struct_file来管理这些数据,管理完后给用户返回对应的fd。(找映射关系是在内存中进行的,也就是找映射关系时inode并不一定在内存中)
dentry中还有一个成员 super_block* d_sb;是用于记录这个文件当前处于哪个分区的。
(2)DIR opendir(const char*filename);和 struct dirent* readdir(DIR dir);
opendir返回该文件件的DIR结构体,readdir返回该dir的dirent。
struct dirent中中有两个成员分别存储了这个文件的文件名和文件的inode_number。
我们在内存中操作的inode和磁盘中真实存在的inode并不是同一个inode,在硬盘中存的叫struct ext2_inode,因为在实际操作时我们并不需要ext2_inode中的所有信息,也就是说我们实际操作的inode是ext2_inode的一个残疾版本。
ext2_inode中存储数据块地址的数组大小是15.

这个数组前12个空间就是直接指向存储文件数据的数据块,后三个分别是1,2,3级间接块指引指针,一级就是指向一个数据级,里面存的都是存储文件地址数据块的地址,二级就是叠两层,三级就是叠三层。
inode和Data Block在文件系统中具有全局属性,及每一个组中的inode都可以跨组指向不同组的数据块,所以inode指向的数据块可以来自其他组。
(3)总结一个进程从文件到硬盘的整个过程

(1)进程开启。生成task_struct,OS帮其打开fd_array[]存文件fd和打开fs_struct明确当前进程所在路径。
(2)通过fd_array[]找struct file
(3)找struct file的一个成员f_path来找dentry(dentry其实在一个文件生成时就有了,只是最初还没有挂到树上而已),最后就可以通过dentry找到磁盘的inode和super_block了.