本章目标
1.inode与datablock映射
2.目录与文件名
3.路径解析
4.路径缓存
5.分区挂载
6.软硬连接
1.inode与datablock映射
我们之前说过inode保存着一个文件的大部分属性信息,我们管它叫做元数据
其种inode中有一个inode number的东西来标识一个文件用来区分其他文件的标识
它其种也包含着datablock它所占用的的块号我们可以通过内核看一眼
就是这个结构可是我们看到这个结构才15个大小啊
它是怎么进行存储大量的块号的呢
其他在磁盘当中一个inode是通过分级存储的方式来存储块号
在这个数组当中前12个数据块用来直接进行存储数据块
一个数据块的大小是4kb,也就是48kb
当大于这个值他就会用二级存储
这个指针指向的是一张索引表
这个数据块用来存储其他数据块的块号
我们假设一个地址用4个字节
它就会增加4096/4=1024个数据块的大小
102410244=4mb的大小
当超过这个大小之后,他就会用二级索引
它第一个指针指向的就是第一个索引表
对于二级索引来说,它的这个索引表指向的是下一个索引表
第二个索引表指向的才是真正数据块的块号
也就是1024102410244 =4g
对于3级索引来说就是4g1024 =4tb的大小
这也就是解决了存储大文件的内容
那么我们既然知道了文件的inode号和inode和datablock是如何进行映射的
那么一个文件是如何进行创建删除修改查找的呢
1创建:
对于创建来说,我们首先会在内存当中为这个文件创建inode,并写入属性信息,然后再由os在inode bitmap中找到一个没有使用的地方,分配inode号,然内存中的inode通过inode将自身刷入inode table当中.如果由数据的话,会在block bitmap当中找到空闲的块号,然后根据块号填写上面的映射表,把数据写入到对应的数据块当中
2.删除
对于删除,我们会在inode bitmap找到对应inode号去查inode table,找到对应的映射表,把block bitmap中的内容全部置为0,最后再将inode bitmap对应的位置置0即可.
3.修改
对于修改,一定遵守的是下面的规则,先加载,再修改 ,再刷新.
我们需要把对应的文件加载到内存当中,在内存当中修改,最后刷新到磁盘当中.
刷新的过程如创建一样.
4.查找.
我们只需要拿到对应的inode号,就能找到inode,根据inode就能够找到对应的文件信息
2.目录与文件名
可是在前面,我们并没有使用过inode去查找一个文件,而是使用文件名去查找的
这里我们就需要理解文件目录了.
在Linux当中一切皆文件,
对于目录来说,它也是文件.对于一个文件它一定有自己的数据,数据就分为属性和内容.
对于目录的属性在前面,我们通过权限已经见过了.
今天我们要谈的是文件目录的内容
对于文件目录的内容来说,它存储的就是文件名和inode的映射.
所以我们就可以通过文件名去访问inode了
#include<stdio.h>#include<string.h>#include<stdlib.h>#include<dirent.h>#include<sys/types.h>#include<unistd.h>intmain(intargc,char*argv[]){if(argc!=2){fprintf(stderr,"Usage: %s <directory>\n",argv[0]);exit(EXIT_FAILURE);}DIR*dir=opendir(argv[1]);//系统调⽤,⾃⾏查阅if(!dir){perror("opendir");exit(EXIT_FAILURE);}structdirent*entry;while((entry=readdir(dir))!=NULL){//系统调⽤,⾃⾏查阅// Skip the "." and ".." directory entriesif(strcmp(entry->d_name,".")==0||strcmp(entry->d_name,"..")==0){continue;}printf("Filename: %s, Inode: %lu\n",entry->d_name,(unsignedlong)entry->d_ino);}closedir(dir);return0;}大家可以用上面的代码验证一下.
在这里我们要重新讨论下块号和inode编号了
对于一块磁盘,我们是不可能使用到100%的利用率的.
实际上一个inode有多少,一个inode一般分配多少块号都是固定好的.
但是这都是经验值.如果在系统里大文件多,在inode和块号的分配比就小一点,1:50
如果大文件多那么就100个块号分配一个inode
所以是存在inode还是可是创建不处文件出来的情况
所以inode和块号都是不可跨分区的.
3.路径解析
那么我们向找到一个文件,就必须去查看该文件的工作目录,可是这个目录也是文件啊,那他去找上级目录.
而这个类似如递归的过程,我们就叫做解析.而出口是根目录
如果我们访问一个目标文件.哪一般都是有目录的/home/whb/code/test/test/test.c
都要从根⽬录开始,依次打开每⼀个⽬录,根据⽬录名,依次访问每个⽬录下指定的⽬录,直到访问到test.c。这个过程叫做Linux路径解析。
对于根目录,根⽬录固定⽂件名,inode号,⽆需查找,系统开机之后就必须知道
对于路径是谁提供的?
1.进程通过自身的cwd来提供,我们一般都是通过指令和工具来使用,本质上都是进程访问
2.open文件的时候由用户指定的
4.路径缓存
我们了解了路径解析,但是我们的Linux如何每次打开一个文件都去解析,效率就太低了.
所以我们的Linux将我们曾经的路径缓存起来,就方便我们下一次查找了.
在内核当中,维护的结构是struct dentery
问题1:Linux磁盘中,存在真正的⽬录吗?
答案:不存在,只有⽂件。只保存⽂件属性+⽂件内容
问题2:访问任何⽂件,都要从/⽬录开始进⾏路径解析?
答案:原则上是,但是这样太慢,所以Linux会缓存历史路径结构
问题2:Linux⽬录的概念,怎么产⽣的?
答案:打开的⽂件是⽬录的话,由OS⾃⼰在内存中进⾏路径维护
每个⽂件其实都要有对应的dentry结构,包括普通⽂件。这样所有被打开的⽂件,就可以在内存中形成整个树形结构,普通文件就是这颗目录树的叶子节点
整个树形节点也同时会⾪属于LRU(LeastRecentlyUsed,最近最少使⽤)结构中,进⾏节点淘汰
整个树形节点也同时会⾪属于Hash,⽅便快速查找
更重要的是,这个树形结构,整体构成了Linux的路径缓存结构,打开访问任何⽂件,都在先在这棵树下根据路径进⾏查找,找到就返回属性inode和内容,没找到就从磁盘加载路径,添加dentry结构,缓存新路径
5.分区挂载
在前面我们说过inode和块号,那么我们是如何进行区分分区之间的inode的呢?,我们怎么知道我们的inode是哪个分区的?
我们做个实验
ddif=/dev/zeroif=./disk.img bs=1M count=5我们伪造一个大文件作为磁盘
mkfs.ext4 disk.img这一步是向这个文件写入管理信息,就是格式化,创建文件系统
用ext系列的文件系统即可
当我们向这个磁盘当中写入管理信息,这个文件系统也用不了
我们需要把它挂在在一个分区上,
我们可以通过 df -h来查看一个磁盘的使用情况
sudomount-t ext4./disk.img/mnt/mydisk通过mount指令将分区进行挂载
这样我们就可以使用这个磁盘了
我们的linux是根据最长路径进行匹配的,我们可以在这个路径下创建文件
通过umount来卸载分区
没有东西了
分区写⼊⽂件系统,⽆法直接使⽤,需要和指定的⽬录关联,进⾏挂载才能使⽤。
所以,可以根据访问⽬标⽂件的"路径前缀"准确判断我在哪⼀个分区。
6.软硬连接
硬链接
我们看到,真正找到磁盘上⽂件的并不是⽂件名,⽽是inode。其实在linux中可以让多个⽂件名对应于同⼀个inode。
我们可以通过ln命令创建硬链接
通过ls -i选项查看inode
硬链接主要有两个方面的应用.
1.给文件创建备份,主要是大文件.
对于一个文件的删除如果文件的映射关系大于等于2,都是删的映射关系.
只有变为1才会去真正去删除文件
2… 和…就是硬链接.除了这两个文件目录其他的目录不能够创建硬链接
因为会有回路的问题.
软连接
硬链接是通过inode引⽤另外⼀个⽂件,软链接是通过名字引⽤另外⼀个⽂件,但实际上,新的⽂件和被引⽤的⽂件的inode不同,应⽤常⻅上可以想象成⼀个快捷⽅式。在shell中的做法
我们通过ln -s方法创建软连接
软连接是真正意义上的文件.它是有自己独立的inode的