目录
学前补充
问题:计算机只认二进制,即0、1,什么是0、1?
解释:0、1在物理层面可能有不同的表现,0、1是数字逻辑,可以表示高低电平....
问题:什么是磁盘?
解释:磁盘本质是一个机械设备,由盘片、磁头、主轴电机、控制器板组成,盘片是可读可写可擦除,一篇两面都可写,一面一个磁头
磁盘的存储结构
基本概念:磁盘是一个机械设备,是外设,数据的存取速度慢,但是性价比高,用很少的钱就可以买到一个数据存储的硬件设备,于其它更昂贵的数据存储设备相比,对数据的读取速度是相差10^n(跟越nb的相比n就越大)
扇区:磁盘读写的基本单位,大小是512字节
- 1磁盘 = n 个磁道
- 1磁道 = m 个扇区
注意事项:一般情况下计算机系统中,磁盘和内存之间的数据传输是以块为单位进行的,块大小通常是512字节或更大。如果只需要修改一个比特位,也要讲整个块的512字节加载到内存中,在内存中对一个比特位进行修改后再将整块写入磁盘中(其实也可以通过“原子写入”技术避免块在传入内存时出现部分要修改+部分不要修改的情况)
问题:如何找到一个指定位置的扇区?
解释:CHS定址法:(在一个 CHS 定址系统中,“0/0/1”表示第 1 个扇区位于第 0 柱面、第 0 磁头和第 1 扇区处)
- 确认指定的磁头:Header
- 找到指定的磁道(柱面):Cylinder
- 找到指定扇区:Sector
补充:盘片旋转是为了定位扇区,磁头左右摆动是为了定位磁道,此外磁盘还分为民用的桌面级磁盘和企业用的企业级磁盘
结论:文件 = 内容 + 属性,它们都是数据,从更本质上将讲都是二进制数据,文件在没有被打开时在磁盘中存放是磁盘文件,即文件其实就是在磁盘中占有几个扇区(512字节)的问题
OS如何对磁盘的存储进行逻辑抽象
基本概念:OS会对磁盘这样的硬件设备进行管理和抽象,这是因为如果OS直接使用CHS对磁盘进行管理,耦合度太高,不希望OS可以直接拿到硬件设备的一些参数,同时也是为了方便实现内核并进行磁盘管理
问题:如何进行逻辑抽象?
解释:将磁盘的圆形结构抽象成一个线性结构:
此外,由于一个扇区512字节太少了,从磁盘读取一个8KB大小的数据需要访问磁盘十六次,因此虽然访问磁盘的基本单位是一个扇区512字节,但一般情况下,OS与磁盘交互时,会一次访问4KB即8个扇区(规定),我们将这八个扇区统称为数据块,该数据块就是OS层面读取磁盘时的基本单位
- 块就是LBA,即逻辑区块地址
- 磁盘总大小 / 4 = 磁盘中块的个数
磁盘中的多个扇区组成一个LBA类型的数组LBA blocks[N],此时OS对磁盘的管理就变成了对LBA数组的管理(用数字来描述,用数组进行组织),用一个数字就可以描述一个块的位置进而知道该块中扇区的CHS地址
- 一个800GB的磁盘太大了,我们可以将它分成多份,即分区,只要我们总结好一个200GB分区的管理方法,就可以将该方法复刻到其它分区
物理层面(原来):磁盘 —> 面 —> 磁道 —> 扇区
虚拟层面(现在):磁盘 —> 多个LAB数组 —> 多个LAB —> 扇区
结论:文件 = 很多个LBA地址
分区中的一个组中又会有多个磁盘级文件系统:
- Group Descriptor Table:块组描述符GDT,获取块组的属性信息
- Super Block:超级块,存放一个分区中的文件系统的信息(当前分区中block和inode的总量,未使用的block和inode的数量,一个block和inode的大小,最近一次挂载的时间等),如果它被破坏则整个分区的文件系统结构就被破坏了,因此为了保证系统的健壮性,它会被下放至分区中的个别分组中(没必要每个分组都有,保证效率),这样即使它对应的某个物理扇区被损毁后也可以从其它分组中的超级块中拷贝一份信息
- GDT记录的是一个分组中的信息,每个分组都有
- SB是记录一个分区中的信息,位于个别的分组中
- struct file处理的是用户与操作系统间的关系,而文件系统中的struct inode处理的是操作系统与硬件设备之间的关系,OS可以依据struct file中存放的信息找到struct file对应的struct inode
格式化:为每个分区分组后,写入文件系统的管理数据(本质就是在磁盘中写入文件系统)
细节内容
1、inode number是以分区为基本单位划分的,一个分区中的inode number不能重复,两个分区中的inode number可能重复
2、GDT会记录当前组的start inode number和end inode number,SB会记录整个分区中inode number的所属情况
3、不同的文件系统inode结构体的大小可能不同
4、inode结构体中的datablock[]数组大小一般是15,通过数组下标[0,11]中存放的是可以直接寻址到data blocks中的数据块,即直接寻址;而[12,13]是一级间接寻址,[14]是二级间接寻址(实际情况更复杂,了解实际寻址的时候有这种一级、二级、甚至三级映射的概念即可,这种寻址方式解决了文件大小问题,保证可以存放更大的文件)
5、目录是一种特殊的文件,利用指令对比普通文件和目录的信息
6、目录 = 文件属性 + 文件内容,目录的文件内容中存放的是文件名和inode编号的映射关系
- 因此同一目录下不能创建同名文件(互为键值)
- 查找文件顺序是:文件名 -> inode number,文件名属性位于目录的数据块中而不是在inode结构体中这是为了保证inode结构体大小固定,便于管理
- 目录r权限的本质是是否允许读取文件名和inode number的映射关系
- 目录w权限的本质是是否允许向目录中新增文件名和inode number的映射关系
7、windows的回收站本质是一个目录,删除文件的本质就是将该文件复制到该目录下,将linux中的rm指令功能修改为mv并令mv指向一个自定义的回收站就可以实现linux的回收站功能(这也是为什么回收站中的内容仍然是占据磁盘空间的)
问题:为什么我们对文件的操作有时候并未提及文件所在路径,但是OS仍然可以找到文件所在路径,为什么?
解释:每个进程的cwd中都会记载文件当前所在的路径,该路径 + 文件名就可以拼成一个完整的路径,从而告诉OS当前文件所在的完整路径
问题:如何确定文件在哪个分区?
解释:对文件进行操作时要先进入该文件所在的分区,而任何一个分区在使用时,该分区已经被写入文件系统(格式化)并挂载到指定的目录下,此时就需要通过文件的完整路径确定文件所属分区,report.doc文件的完整路径如下图所示:
OS会先进行正向分析,根目录 / 通常是系统启动时挂载的主文件系统,接着就会将/后的第一个目录名视为分区的挂载点,文件就属于该分区中
问题:打开目录中的文件,就要先找到该目录,如何找到该目录?
解释:目录也是文件,要找到该文件的属性和内容就要去c目录的数据块中寻找,寻找c目录的数据块就要去b目录的数据块寻找...寻找home的数据块就要去/的数据块中寻找(逐层向上寻找的过程中,会有一个属于访问该文件时的路径解析缓存结构体,记录了寻找文件时经历的所有目录,便于在找到后返回时能依据该缓存的目录内容更快的确定文件位置)/数据块中的文件和inode number是在系统启动时默认设置好的,然后依据缓存结构体可以快速确定在/数据块中要寻找哪个文件与inode number的映射关系,确认并进入该文件的数据块后再次依据缓存结构体确定在该数据块中要寻找的下一对儿映射关系,直到缓存结构体清空时,表示已经找到了最终的文件名与inode number的映射关系,最后通过文件名告诉OS我们最初要找的inode number的内容即可(这一系列的过程是OS自己进行的,用户感觉到的就只是输入了文件名就找了该文件)
问题:我们一直在用文件名访问文件,但是OS访问文件时用的是inode number,为什么我们通过文件名就能访问到文件?
解释:正常情况下,我们在访问文件时一定位于某个目录下,那么我们只需要告诉我们要找到文件的文件名,然后OS就会通过目录中存放的文件名与inode number的映射关系确定并依据该inode number找到我们想要的文件属性和内容(至于是查看属性还是内容就是更复杂一点的内容,不做过多解释,这里只大概知道如何找到文件的内容和属性即可)
终极结论:对文件的所有操作一定涉及路径(上面描述的只是甚至算不上大概的意思,实际上会更复杂,一些细节内容没有涉及比如vfs、目录缓存等概念,不要求掌握只要求知道OS在打开一个文件时一定要有确定文件所在分区,确定文件所在目录,确定文件的Inode number这些操作,确定分区和寻找目录那里我也很迷惑建议别信)
文件的增删改查
增:在当前目录所处分区中申请一个inode number(SB会负责告诉OS该分配哪个inode number),通过inode number确定分组的编号(系统启动时已经划分好了分组),然后再去inode bitmap中从低向高位寻找一个比特位为0的位置,将其改为1后,在inode table中分配一个与该inode number对应的inode结构体(到这里已经建立了inode number与文件属性结构体inode的映射关系),后续如果想向文件中写内容,首先要根据写入内容的大小计算所需数据块的个数,之后再去block bitmap中从低位向高位寻找几个比特位为0(不一定连续),并将它们修改为1,将要写入的内容写入这些比特位对应的data blocks中的某几个数据块中,然后将这些块的编号写入Inode中的datablock数组中(建立data blocks中的文件内容数据块与文件属性结构体inode的映射关系)最后将该新申请的inode number编号返回给目录,由目录记录新的文件名与inode number的映射关系
删:删除文件并不删除文件的内容和属性,而是将文件的inode bitmap由1变为0,这时虽然没有删除文件的内容和属性但是存放它们的值可以被其它文件的内容和属性覆盖了(Linux中误删文件后最好什么都别做,因为这可能导致被误删文件的内容和属性被覆盖,可以通过查找日志或是专业修复软件来恢复误删软件,但最好还是别误删文件)
改:与查类似依据inode number找到文件的属性和内容后进行修改
查:inode number= 10000,通过SB找到inode number属于哪个分组,再用10000减该分组的start inode number,从而确定在该分组的相对位置,再在inode bitmap中从右向左找到并查看该位置上的比特位是0还是1,如果为0则该10000不是一个合法inode number,如果合法则接着去inode table数组中找到索引为10000-start inode number的inode结构体即文件属性的结构体(上图中inode结构体中存放该结构体对应的inode number,寻找时只需要一个个的比对inode结构体的该参数存放的值即可),如果还想获取文件内容,就接着利用inode结构体中的datablock数组查找data blocks中的存放文件内容的数据块
~over~