ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

初识Linux(14)Ext系列⽂件系统

初识Linux(14)Ext系列⽂件系统 之前谈论的都是已打开文件在操作系统的中的管理但是还有更多的文件没有被打开被存在磁盘中如何管理这些磁盘中的文件就是本篇的学习目标。目录1.理解硬件磁盘结构扇区的读写CHS地址定位磁盘的逻辑结构2. 引⼊⽂件系统分区inode :Data Blocks:BitmapSuper Block和GDT格式化inode与block的分配3. inode和block的映射4. 目录文件重点5. dentrydirectory entry6. 文件描述符、内存、进程与 目录缓存路径 的关系 难点7. 挂载mount了解1.理解硬件磁盘、服务器、机柜、机房计算机中有许多重要的硬件比如寄存器由各种各样的门电路逻辑电路组合而成而机械磁盘是计算机中的唯一的一个机械设备。磁盘是一种外设不同于现在的ssd卡虽然早期的磁盘都相对速度慢同时单位容量的价格也更便宜任然广泛运用于计算机中。磁盘、二进制计算机只认识二进制是一种宏观表示这个二进制的具体实现在不同的物理设备上有不同的具体体现。比如高低电平网卡上的电脉冲或者是磁盘上的NS磁性所以在磁盘中改变0、1其实是将N极改成S极或者将s极改成n极然后由磁性得到1或者0磁头和磁盘是悬浮着距离极小的外壳相对于内层一定是完全密封的因为灰尘直径远大于磁头和磁盘的距离灰尘在上方撞击可能导致数据丢失的问题。主轴能让磁盘旋转永磁铁能让磁头沿半径移动读取所有磁道上的内容真实情况相邻磁极之间的磁性远大于内部的磁性所以本质是用两个微磁体之间是否由磁性来确定1和0。磁盘结构侧面来看 磁盘可以分成三层或者两层或者四层等下图是三层每层两个面都能记录数据俯视来看每个面上不同的半径形成的是不同的磁道一定距离的磁道构成一个扇区。所有面上的相同半径构成了一个圆柱面扇区是磁盘存储数据的基本单位512字节块设备(就算只访问这512字节当中的一个字节也需要全部访问这个扇区整个扇区是一块完整的存储结构)从最外圈的磁道开始编号为0然后依次向内递增盘面的编号也是从0开始的。这一点在之后的计算中有用。扇区的读写能定位在任何磁道上就能定位在任何扇区上。如何定位⼀个扇区呢可以先确定磁头要访问哪⼀个柱⾯(磁道)cylinder再定位磁头哪一层header定位⼀个扇区(sector)CHS地址定位⽂件 内容属性 都是数据⽆⾮就是占据哪⼏个扇区的问题我们认为不同半径的磁道所能容纳的扇区的数量是一样的但是靠近主轴的同⼼圆⽤于停靠磁头不存储数据磁盘容量 柱面个数磁道数*磁头数层数*每个磁道扇区数*每个扇区字节数就像一个三维坐标只要知道了磁道位置/磁头位置以及第几扇区就能定位扇区。对早期的磁盘⾮常有效知道⽤哪个磁头读取哪个柱⾯上的第⼏扇区就可以读到数据了。但是CHS模式⽀持的硬盘容量有限不够长。磁盘的逻辑结构将磁道上的扇区化曲为直得到LBA的概念。LBALogic Block Address是一种逻辑抽象但是实际去找的时候是否还是需要去转换成CHSLBA将扇区的变成一个一个独立的单元像三维数组一样联系到一起整个盘同时可以用一维数组来构建具体的LBA地址半径为r的一个盘面上的一个磁道由该磁道相同半径的磁道组成的柱面多个柱面组成整个逻辑结构一个三维数组就被我们抽象成一维的线性存储模式***重点对于OS来说知道LBA地址即可LBA地址与CHS地址的转换由磁盘⾃⼰来做固件(硬件电路自动完成注意柱面号、磁头号通常都是从0开始编号的。这种编号方式是硬盘存储结构的一种约定俗成的规定有助于硬盘控制器和操作系统对磁盘进行统一的寻址和数据管理。所以一个CHS地址的柱面号表示的是当前所用地址以外已经被完全占满的柱面。每⼀个扇区都有⼀个下标我们叫做LBA(Logical Block Address)地址,其实就是线性地址。所以 怎么计算得到这个LBA地址呢CHS转成LBA•磁头数*每磁道扇区数 单个柱⾯的扇区总数•LBA 柱⾯号C*单个柱⾯的扇区总数 磁头号H*每磁道扇区数 扇区号S - 1•即LBA 柱⾯号C*(磁头数*每磁道扇区数) 磁头号H*每磁道扇区数 扇区号S - 1•扇区号通常是从1开始的⽽在LBA中地址是从0开始的•柱⾯和磁道都是从0开始编号的•总柱⾯磁道个数扇区总数等信息在磁盘内部会⾃动维护上层开机的时候会获取到这些参数。LBA转成CHS•柱⾯号C LBA // (磁头数*每磁道扇区数)【就是单个柱⾯的扇区总数】•磁头号H (LBA % (磁头数*每磁道扇区数)) // 每磁道扇区数•扇区号S (LBA % 每磁道扇区数) 1•//: 表⽰除取整以上公式都不需要死记硬背对于工科生来说理解这个图就能理解换算办法。2.引⼊⽂件系统操作系统读取硬盘数据的时候其实是不会⼀个个扇区地读取这样效率太低⽽是⼀次性连续读取多个扇区即⼀次性读取⼀个”块”block。毕竟磁盘是外部设备每次IO都有成本。因此磁盘也是一种“块”设备。硬盘的每个分区是被划分为⼀个个的”块”。⼀个”块”的⼤⼩是由格式化的时候确定的并且不可以更改最常⻅的是4KB出于教育目的的数值中比如408考试中页面大小和盘块大小一般都默认是4KB即连续⼋个扇区组成⼀个 ”块”。”块”是⽂件存取的最⼩单位。所以8个LBA数据构成一个“块”即块号 LBA // 8LBA块号*8nn是指该块中的哪个扇区或者 块号*8该块的LBA起始地址分区对于win系统来说我们有C盘D盘E盘F盘等等其实这就是一个硬盘中分区的表示。每个分区独立可以装不同的文件系统分区之间互不影响。分治思想管好一个组就能管好所有的组。我们先研究操作系统如何管理分区中的一个组比如我们将 group0 分成很多个block groupdata block所占空间远大于其他的几个模块文件内容属性类似于PCB或者struct filesinode就是管理磁盘上文件属性的结构体Boot Sector也称作启动区大小为1kb任何文件系统都不能改变启动区的内容启动区里存放了启动信息和分区信息。宏观来说inode存文件属性data block存文件内容inode里面有相关的映射内容便于去data block中找具体的文件内容。在linux系统下文件名不会存在inode中。我们认为inode是128字节大小一个块win系统中叫簇能存32个inode4*1024 / 128每一个分组都有这些固定字段我们依次介绍。inode :•存放⽂件属性 如 ⽂件⼤⼩所有者最近修改时间等•当前分组所有Inode属性的集合•inode编号以分区为单位整体划分不可跨分区我们还认为inode结构里还有个block数组这个数组用于记录属于该inode对应文件内容所存储的块号Data Blocks:按照“块”的大小一个一个存储在内存中一个块4字节用于存储文件内容。Bitmapinode Bitmap来显示inode是否存在的位图。比如该区域有8个inode位图为0010 0001则表示第1、6个已经有内容了。一个块写进内存一万个比特位的位图也才不到2kb一个块4kb所以不影响我们前文提到的内存要加载4kb来进行操作。整体修改完了再写出来即可。Block Bitmap :同理检测对应的data blocks是否合法的存在是否已经被使用。Super Block和GDTSB一般在每个分组的第一个字段中存储的是该分区的文件系统信息每个分区的文件系统可以不一样但并不是每个分组中都有也不是只有第一个分组有这样能保证一个超级块出问题时其他超级块能用正确的信息来修复。当所有的超级块都被破坏时说明这个文件系统已经崩溃了。该字段记录的包括不限于总的inode数和block数还能使用的inode数和block数最近一次挂载时间、修改时间等。struct ext2_super_block { __le32 s_inodes_count; /* Inodes count */ __le32 s_blocks_count; /* Blocks count */ __le32 s_r_blocks_count; /* Reserved blocks count */ __le32 s_free_blocks_count; /* Free blocks count */ __le32 s_free_inodes_count; /* Free inodes count */ __le32 s_first_data_block; /* First Data Block */ __le32 s_log_block_size; /* Block size */ __le32 s_log_frag_size; /* Fragment size */ __le32 s_blocks_per_group; /* # Blocks per group */ __le32 s_frags_per_group; /* # Fragments per group */ __le32 s_inodes_per_group; /* # Inodes per group */GDT块组描述符描述当前块组中哪里到哪里是哪些内容。创建一个文件可能只写了hello world的完整步骤先在inode bitmap中找一个可以用的位置将0置1加载对应的文件属性到 inode 中去此时文件内容少直接将内容放到inode指向的data block中去。删一个文件相当于是把inode Bitmap和Block Bitmap对应的比特值从0置1所以删除一个文件是可以恢复的。删除的本质其实是让文件无效删除之后如果想恢复最好的办法就是什么都不做避免被其他文件覆盖覆盖了就真的无了格式化我们想要在硬盘上储⽂件必须先把硬盘格式化为某种格式的⽂件系统才能存储⽂件。⽂件系统的⽬的就是组织和管理硬盘中的⽂件。格式化的本质是在一个分区中写入新的空的文件系统两个bitmap要清0GDT里的使用率要降到0SB中未使用的block和inode要加到最大。包括在win系统中格式化也是对于每一个分区来说的从分区落实到分组每个组里的inode和block的个数是动态计算后固定的所以比例也是固定的。inode和block会成比例分配比如一个inode分配十个block这比例是固定的。磁盘中存在inode被分配完的情况都是小文件。一个组里面的inode的值是固定的都是从a~b一整个 分区C盘D盘 的inode是一套一整个 分区 的block也是一套。inode与block的分配每个分组占据了多少编号到多少编号的inode或者block都记录在GDT里因此每次只需要确定每个分组的起始inode值即可。block同理。可以 跨组Block group0,Block group1 建立块号和inode的映射关系inode和block的映射关系是在全局建立的。但是inode和block的编号都是分区独立分组分配的。•分区之后的格式化操作就是对分区进⾏分组在每个分组中写⼊SB、GDT、BlockBitmap、Inode Bitmap等管理信息这些管理信息统称: ⽂件系统•只要知道⽂件的inode号就能在指定分区中确定是哪⼀个分组进⽽在哪⼀个分组确定是哪⼀个inode•拿到inode⽂件属性和内容就全部都有了可以通过Inode完成对文件的增删查改根据inode找文件内容的大概流程查区间inode减去起始编号查对应的bitmap从而查到对应的inode table中的数据根据映射关系找到data block3. inode和block的映射一个inode128字节一个指针4字节就算全部存指针也只能存32个块一个块能存4kb32*4 128kb甚至不到1MB这样的文件也太小了吧一共有15个块指针12个是直接块指针还有三个间接块指针。比如一级间接块索引指向的是一个不装文件数据、只存其他块号的块一个块能存1024个块号相当于通过这个一级索引能找1024*4kb4mb的空间。同理二级索引指向的全是只存一级索引块能装4gb三级能装4tb。所以一个inode实际能装的大小远超过一个正常文件的大小甚至大于整个磁盘的大小。4. 目录文件重点linux文件系统基础--VFS中的file、dentry和inode--讲得非常透的一篇文章_vfs dentry-CSDN博客建议有能力的读者去看看这篇深度好文。/就是一个目录文件/user也是一个目录文件文件夹就是目录前者是win的概念后者是linux的概念目录文件存放他下面的“子目录文件的文件名和inode的映射”以及普通文件的文件名和inode的映射每个文件的inode和文件名的映射是存在其所在的文件夹中的。在上层使用时好像从来没有用过inode都是直接操作文件名。文件名和inode的关系是什么正如上所述在linux中文件名不存储在inode中文件名的信息是存在其所存在的目录所以地址的意义就在此/user/zhangsan/test.cc在/中找user文件名即“user”对应的inode找到这个inode在其对应的data block中找到zhangsan对应的inode依次找到test.cc将test.cc加载到内存中去.......进程都有CWD的意义也在于此通过CWD再加上open等函数就能拼成所需的完整路径让操作系统永远都能获得一个完整路径。为什么以inode作为比较、查找的对象因为整数的查找添加等比字符串简单。这样更高效。类似于GID、UID和USERNAME这种关系字符串是给用户看的。5. dentrydirectory entry两个现象1在文件夹中能直接进行tree命令2诸如下图这种情况只能不断的访问磁盘文件系统吗文件系统是外设速度很慢解决办法引入结构体dentry。将曾经访问过、经常访问的路径在内存中缓存起来形成一棵多叉树这样就不需要一直访问磁盘了6. 文件描述符、内存、进程与 目录缓存路径 的关系 难点task_struct中的files_struct维护该进程打开的文件列表列表中存的是一个个打开的file对象经过VFS系统封装出来的让所有文件都是file对象通过file对象我们可以找到包括但不止于1文件对应的操作表就是将每个文件的具体操作封装成write,read等接口的函数指针数组2文件内核缓冲区缓冲够了直接由OS往外设发送3f_pathf_path指向了一个包含dentry的结构体。再观察dentry的结构有parent和child由此说明dentry维护的 的确是一个树形结构。dentry里还有一个inode对象其对应的 inode值 就是此时file所对应的 inode值file中前面两个包含的结构是在上一篇文章中学习过的提出来只是为了复习。所以当一个目录文件被打开后不再需要去访问磁盘找data block从而找到子目录或文件而是能通过file中的dentry直接找到子目录或文件dentry已经在内存中了注意不是将整个结构树给塞进内存而是将结构记录在dentry中加载对应的文件的时候就能把该文件所对应的目录关系给加载到内存中去。最终就能通过dentry找到希望打开文件的inode了。这个树形结构整体构成了Linux的路径缓存结构打开访问任何⽂件都在先在这棵树下根据路径进⾏查找找到就返回属性inode和内容没找到就从磁盘加载路径添加dentry 结构缓存新路径7. 挂载mount了解df -h 查看磁盘的挂载状态。linux中必须将分区挂载到一个文件目录树上才能使用该分区。Mounted on : 挂载使用指令建立好分区之后进行查找刚创建好是查不到也用不了的要先挂载才能用挂载和查看操作
返回列表