Linux文件系统_inode
1,粗略了解磁盘分组后内部结构与文件系统
我们知道磁盘分完组之后,组内结构就如下图所示:
其中,inode Table是用来存储inode数据的区域,inodeBitmap则是用来查看inodeTable的具体使用情况。
Data blocks则是用来存放文件内同数据的,Block Bitmap则是用来查看Data blocks的具体使用情况。
由此我们可以知道,存储文件属性与内容的位置与位图的位置上是一一对应的,如果inode table中某组数据被占用了,就把inode bitmap中的位置变为1,表示此数据为有效数据;Data blocks也是一样。
如果需要修改bitmap时,先把内容复制到内存中进行修改(磁盘是块设备,无法进行二进制修改),然后再刷新回磁盘的bitmap中,都是以4kb的读取方式来修改。
如果需要使用内存时,向inode申请,再看需要几个块的内存,比如说需要两个块,再从Block bitmap中查看哪个块在空闲,找到之后把Block bitmap位置变为1,再把数据放入Dtata blocks中:
怎么找文件?
去找inode的编号,再去根据inode编号确定inodeBitmap是否合法,再去block bitmap找数据是否合法,最后就去找Data Blocks;
删除文件
只用在inode Bitmap和对应的Block Bitmap中的下标由1变为0,就约等于删除了数据。
所以,删除文件可以被恢复,只需要拿到删文件的inode Bitmap,把里面的位图由0改为1,在查与块的关系,把块号拿到,再把Block bitmap中的位图由0变为1,就可以把数据恢复了。
所以如果把文件误删除了,最好的办法就是什么都不要做,在Linux系统中,删除的本质上是让文件无效化,如果再乱用,把之前的inode等被别的数据占用覆盖,删除的文件就再也找不回来了。
GDT
我们如何知道块组的内存够不够?怎么知道用了多少Blocks?用了多少inode?使用比例是多少?
这时候我们看到组内还有一个管理模块:
Group Descriptor Table
简写为GDT
GDT块组描述符,就是对他后面的内容进行管理。
super Block
这个代表了一个分区的整体情况,他就是文件系统,不同的分区可以用不同的文件系统。
为什么superBlock会出现在组里?其实superBlock不需要分配给每一个组。
因为再一个分区里,一个superBlock挂了,那整个分区都没了!分组情况都不清楚了,所以,super Block会打散在每个不同的组里,如果某个super Block挂了,可以去其他组找superBloc并把数据覆盖回来。
格式化
每个分组,就算里面没有我一个文件,也要对Bitmap,group等做数据填入,比如将位图里全部制为0,这个过程就叫做格式化。
2,理解什么叫文件,什么叫目录(准确理解文件系统)
每一组里inode号个数,Blocks个数都是固定的!以一定的比例来分配inode与blocks。
那是否存在inode用完,block没用完的情况?存在,或许会有大量小文件存在某一组中。
那是否由blosk用完了inode没用完的情况?这种情况不存在。
1,关于inode与block
inode以分区为单位,一套inode。
inode分配的时候,只需要确定起始inode!!
块号也是统一编号的,相对应的bitmap也确定了,所以blockgroup里所有东西都是确定的。
在组中GDT里,有一个结构体:star_inode 1/star_inode 10001
有我们之前对磁盘的了解我们知道,对内存管理其实用下标就行,在同一分区的每一组中,假如每一组有1000个inode,100000个块,那么第一组的star_inode就是1,第二组star_inode就是1001,块也是一样,所以在inode分配的时候,只需要确定起始inode就可以确定后面的inode。
这些star_inode等管理存放在GDB里,所以每个组都有自己对应的区间:
inode区间举例子:
【1,1000】【1001,2000】
2,group问题
1,我们是如何分配inode的?
在inodeBitmap里的0001000(位图中有效数据) 加上 star_inode:就可以找到inodeTable
2,如何分配block?
在blockBitmap中的00001000 (位图中有效数据)再加上star_block的数据就可以找到block。
又因为块号是全局建立的,所以可以跨组分配空间(当组内空间不够时),这时就可以解释了当一组内只有1gb时如何放得下2gb数据。
如何全局定位?
用inode号用遍历去找区间他对应的区间,确定inode
用block号去遍历,在位图中找到inode_table ,databloks 就可以全局定位了。
3,回顾
1,如何查找文件?:遍历!
2,如何删除文件?就得先找到文件,在将位图中1改成0
3,如何修改文件?先查找文件,拿改属性举例子:
找属性-》inode,将inode信息从磁盘cp到缓冲区当中,将需要修改的内容写入,在刷新会磁盘中。
有了以上的知识,我们衍生出了两个子问题:
1,inode和block究极是怎么映射的?
inode中除了有文件属性之外,还存着15个指针,其中12个指针直接映射块号,
有三个指针映射的块号中存其他块号得以扩充容量:
2,凭什么拿到inode号?我们平时访问的都是文件名啊?/如何理解目录文件
看到上面的inode属性,我们可以知道文件名不在inode中保存,那文件名存在那?
我们先来理解什么是目录文件,大家都应该知道,在Linux中一切皆文件,目录也不意外,目录也是文件,也有自己的属性加内容,有自己的inode和datablock,也需要对应的数据块,同时我们知道在Linux中创建文件时,文件名不能相同,所以inode号和文件名互为映射关系,我们可以用vim来打开目录文件:
我们知道了目录也是文件,可以重新来理解一下目录权限:
没有权限r:没办法读文件,是因为没有权限打开dataBlock
没有权限w:不能创建文件:是因为无法把文件名映射关系写道目录中
没有权限x:进不去
为什么?
找到文件名-》首先打开当前目录(inode编号)-》目录也是文件,也有文件名?
可以逆向的路径解析!
其中,根目录是确定的,在Linux启动就默认创建了一个根目录。
为什么任何一个文件都要有路径?
因为如果没有路径,inode与文件名映射关系就建立不起来,所以每一个进程都要有一个cwd,路径就算进程给的。
Linux系统需要对路径结构进行缓存!
以什么结构来缓存我们的数据?
多叉树!
在进程中有一个纯内存的数据结构:struct dentry,里面有inode和内容,同时对路径进行缓存。所以对路径的访问就算不断的进行访问磁盘文件。
所以找路径=找缓存结构
同时,操作系统中lur会把多叉树中不用的节点去掉,就变成了链表·的访问增删了。
3,文件描述符与进程关系
进程中有一个指针指向文件描述符:
文件描述符指向file:
其中file里有操作表,缓冲区的指针,同时有一个path,path里面有指针指向dentry:
在dentry中可以看到有block,inode,然后有parent,child以多叉树的形式链接起来。
其中每个目录都有自己的dentry,这样就可以实现通过路径,找到当前dentry的inode,拿到inode号就可以访问文件数据:
4,做一个小实验:
我们怎么确认我们在哪个分区?
多个分区-》一个分区包含根目录(/)-》有若干个目录文件
如果只有分区是无法使用的,必须挂载在目录上,分区才能通过路径的方式进行访问!
指令:df -h可以查看挂载分区:
可以看到,我们的盘挂载在根目录上,这个时候我们写一个大型文件来模拟分区:
指令:dd if=/dev/zero of =./disk.ios bs=1M count=5
dd表示创造大型文件,if表示创建分区,of表示创建在哪里包括文件名,bs表示创造大小,count表示创造多少次:
然后用指令:mkfs.ext4 disk.ios来挂载目录:
图中还写了文件中有多少ionde多少block
然后用指令:sudo mkdir /mnt/myvda2
然后:
sudo mount -t ext4 ./disk.ios /mnt/myvda2
这时我们就创建好了临时分区:
就可以进去了:
这个时候可以创建文件:
需要加sudo
卸载分区指令:
umount /mnt/myvda2
可以发现删除不了,因为这个分区正在启动,需要退出分区目录才可以:
可以看见分区已被卸载。
文件系统是Linux操作系统的里一座大山,大家加油!