当前位置: 代码网 > 服务器>服务器>Linux > 【Linux】基础I/O——理解ext2文件系统

【Linux】基础I/O——理解ext2文件系统

2024年07月31日 Linux 我要评论
我们到现在为止讲的都是打开的文件。现在我们讲讲没有打开的文件如果一个文件没有被打开,那它就是在磁盘中被存储的,我们就要关心路径问题,存储问题,文件获取问题,那么操作系统是怎么处理这些问题的?不急,我们等会就讲我们先回答几个问题上面显示的内容叫文件的属性上面显示的是文件的内容 在Linux中我们存文件内容采用块来存储,文件属性则是采用inode来存储也就是说Linux文件在磁盘中存储,是将属性和内容分开存储的大家也没有见过磁盘? 最近5年我们笔记本电脑一般使用SSD——固态硬盘,很少见到磁盘了。

我们到现在为止讲的都是打开的文件。现在我们讲讲没有打开的文件

如果一个文件没有被打开,那它就是在磁盘中被存储的,我们就要关心路径问题,存储问题,文件获取问题,那么操作系统是怎么处理这些问题的?不急,我们等会就讲

我们先回答几个问题

上面显示的内容叫文件的属性

上面显示的是文件的内容

 在linux中我们存文件内容采用块来存储,文件属性则是采用inode来存储

也就是说linux文件在磁盘中存储,是将属性和内容分开存储的

1.磁盘/机械硬盘的物理构成

大家也没有见过磁盘?

        最近5年我们笔记本电脑一般使用ssd——固态硬盘,很少见到磁盘了。磁盘在十几年前很常见,它是电脑上唯一的机械部件,后来随着闪存技术的发展,就慢慢淡出大众的视野了。

不过磁盘有超大容量,成本也低,也比较稳定,磁盘这个东西在企业用的非常广泛,今后基本不会淘汰。

所以我们好好的学习一下磁盘

  1. 目前,磁盘是某些计算机(所有的服务器/十几年前的笔记本电脑/现在部分的台式机)的唯一的机械设备
  2. 在冯诺依曼结构体系中,磁盘也是外设,它速度很慢

我们来见见机械磁盘/磁盘,在那之前,我们先来看看光盘

 光盘只有一面是可读的,另外一面就打印的什么广告,就像下面一样

其实我们把磁盘拆开来,里面有一个和光盘特别像的东西 

 这个跟光盘类似的叫盘片/磁盘,盘片两个面都能存储数据,盘片越多,存储的东西越多

硬盘其实是由许许多多的圆形碟片、机械手臂、磁头与主轴马达所组成的,

实际的数据都是写在具有磁性物质的碟片上面,而读写主要是通过在机械手臂上的磁头(head)来完成。

        实际运行时,主轴马达让碟片转动,然后机械手臂可伸展让磁头在碟片上面进行读写的操作。另外,由于单一碟片的容量有限,因此有的硬盘内部会有两个以上的碟片。

这个磁头是一面一个的,一片盘片对应2个磁头

注意: 磁头并非与盘面进行直接接触,而是以 15 纳米的超低距离进行磁场更改

机械硬盘 不能在其运行时随意移动,因为角度的偏转也有可能导致发生摩擦,造成数据丢失,更不能用力拍打 机械磁盘

所以搭载了这磁盘的东西不能随便搬动,否则就数据损坏,这个就比较适合不移动的应用场景

        这个磁盘不能有灰尘,所以机械硬盘一旦拆开来就报废了

        计算机只认识二进制,所有的设备都认识二进制,磁盘也不例外,这个盘面也是,我们把这个盘面叫永久性存储介质

接下来我们来讲一下一个小故事就知道怎么存储这个

吸铁石有南极和北极之分,我们把北极称为1,南极是0,我们通电让南北极互换

磁盘可看作是由无数个吸铁石构成,磁头通过电磁特性来把磁盘的南北极逆置

加热磁盘?软件擦除才对!!!

2.盘面的构成

  1. 一个盘面=n条磁道(图中有8条)
  2. 一条磁道=n个扇区(也叫磁盘块)
  3. 每个扇区存储的数据量一样大

也就是说每个盘片被划分为一个个磁道,每个磁道又划分为一个个扇区。

        我们知道同心圆外圈的圆比较大,占用的面积比内圈多。所以,为了合理利用这些空间,外围的圆会具有更多的扇区。

此外,当碟片转一圈时,外圈的扇区数量比较多,因此如果数据写入在外圈,转一圈能够读写的数据量当然比内圈还要多。

        因此通常数据的读写会由外圈开始往内写,这是默认方式。

之前硬盘的扇区都是设计成512字节的大小,但目前绝大部分的高容量硬盘已经使用了4kb大小的扇区设计。现在我们就算是只修改某扇区里面的1个字节的内容,也要把整个扇区加载到内存里

  1. 首先我们得定位是磁片的哪一面,也就是要访问哪个磁头(一个磁头对应一面)
  2. 其次我们要知道是哪个磁道
  3. 最后得知道是哪个扇区

有人就说了,你这柱面在哪里啊?

我们看定义——由于磁盘里面可能会有多个碟片,因此在所有碟片上面的同一个磁道可以组合成所谓的柱面(cylinder)。

所以上图3个蓝色的圆圈(所有碟片上的同一个磁道)就是一个柱面

至于为啥叫柱面,看下图你就明白了

怎么样?是不是很清晰明了 

  • 这其实是定位磁道和柱面的过程 

当定位到柱面和磁道了之后磁头就不动,变成盘片自转来定位扇区

  1.  磁头左右摆动确定磁道和柱面的过程
  2. 磁头确定好了磁道和柱面时,通过盘片的自转来寻找扇区的过程

如果我们在磁盘里面乱放数据,这样磁头就要到处乱转,访问时间长,效率低下!!!

所以在对应的设计上,我们一定要有意识的将数据尽量存在一起

        我们可以先根据磁头(head)确定盘面,再根据半径定位磁道(柱面 cylinder),最后根据块号确定扇区(sector),这种寻址方法称为 chs 定位法,是机械设备查找具体扇区时的方法

3.对硬盘进行逻辑抽象

大家也没有见过磁带

 也没有勾起你童年的回忆?

这个磁带被复读机的转轴转动的时候,一边的磁带会变多,另一边的就会变少!!!

如果想重新读,就得把磁带卷回原来那个圈里去

这就说明数据是存储在这条带子上面

         我们要是把磁带扯出来,拉直,数据也是存在的,这个磁带和磁盘的存储信息的形式是异曲同工的,我们可以这么理解磁盘

我们完全可以将磁盘看成一条拉长的磁带,然后就能分成无数个扇区!!!!

将盘面分割为多个线性分区,通过下标 n 计算出 chs 地址,然后进行文件访问

将磁道拉长,会得到一串线性空间(数组),其中的每个单位(扇区)为 512 字节(或者 4 kb

 磁盘就是n个扇区的数组 ,任意一个扇区都有下标

假如我们有10万个扇区,但是我们的硬件只认识chs定位法,那怎么办呢?

这样子很厉害了啊 

接下来我们回归硬件啊

我们整个”计算机“里,不止cpu有寄存器,外设也有,包括我们今天谈的磁盘,磁盘中有3个快速接收地址的东西

  1. 控制寄存器(是要读还是写)
  2. 数据寄存器(数据)
  3. 地址寄存器(往哪里写)
  4. 状态寄存器(写入成功?)

这说明硬件是可以被访问的!!!!

4.分区

我们说磁盘是按线性结构来存储的

假设磁盘有800gb,那么操作系统怎么对磁盘进行管理呢?

我们存的是文件,那么文件内容和属性是分开存储的,这样子注定不能简单的就使用扇区存储。

这就好比我们国家领土广袤,怎么管理呢?先分省,省内再分市,市内再分县,县下还有镇……

例如,在计算机里,我们通过分区来将800gb分成了几个区,像下面这样子的分区

按照现在的水平,我们完全可以把分区简单理解为就是通过设置一个开始点和结束点(虽然和实际情况八竿子打不着)

struct partion
{
int start;
int end;
};

        800gb难管理,我们管理最前面的200gb怎么样??!!

         我们把200gb看作中央,其他分区相当于地方。在这200gb这里,我们只要拿到最基本的数据(包括分区数据等),我们所有决策从200gb这里发出,然后其他分区按命令行事,就能完成管理好那其他分区!!!

        有人说200gb也不好管理!!!这个时候我们就要来了解一下分区的结构了

5.分区结构

我们将200gb细分开来

 

这样子就把管理200gb就变成了管理好这些小部分即可 

5.1.boot block(启动块) 

启动块(boot block 是文件系统中的一个特殊块,位于文件系统的起始位置。它包含了引导加载程序(boot loader)所需的信息,用于引导操作系统的启动过程。这是个非常重要的设计,因为如此一来我们就能够将不同的启动引导程序安装到别的文件系统最前端.

5.2.block group(块组)

block group(块组),它们有着统一的格式,具体内容如图所示:

5.2.1.data blocks(数据块)

这个区域是整个block group里内存占比最大的 

5.2.2.inode table (索引图)

5.2.2.1.inode(索引节点)

inode,中文译名为“索引节点”

        首先我们要明白inode是个结构体!!!!

我们看看inode的源码

struct inode {

	struct hlist_node i_hash; 哈希表

		struct list_head i_list; 索引节点链表

		struct list_head i_dentry; 目录项链表

		unsigned long i_ino; 节点号

		atomic_t i_count; 引用记数

		umode_t i_mode; 访问权限控制

		unsigned int i_nlink; 硬链接数

		uid_t i_uid; 使用者id

		gid_t i_gid; 使用者id组

		kdev_t i_rdev; 实设备标识符

		loff_t i_size; 以字节为单位的文件大小

		struct timespec i_atime; 最后访问时间

		struct timespec i_mtime; 最后修改(modify)时间

		struct timespec i_ctime; 最后改变(change)时间

		unsigned int i_blkbits; 以位为单位的块大小

		unsigned long i_blksize; 以字节为单位的块大小

		unsigned long i_version; 版本号

		unsigned long i_blocks; 文件的块数

		unsigned short i_bytes; 使用的字节数

		spinlock_t i_lock; 自旋锁

		struct rw_semaphore i_alloc_sem; 索引节点信号量

		struct inode_operations* i_op; 索引节点操作表

		struct file_operations* i_fop; 默认的索引节点操作

		struct super_block* i_sb; 相关的超级块

		struct file_lock* i_flock; 文件锁链表

		struct address_space* i_mapping; 相关的地址映射

		struct address_space i_data; 设备地址映射

		struct dquot* i_dquot[maxquotas]; 节点的磁盘限额

		struct list_head i_devices; 块设备链表

		struct pipe_inode_info* i_pipe; 管道信息

		struct block_device* i_bdev; 块设备驱动

		unsigned long i_dnotify_mask; 目录通知掩码

		struct dnotify_struct* i_dnotify; 目录通知

		unsigned long i_state; 状态标志

		unsigned long dirtied_when; 首次修改时间

		unsigned int i_flags; 文件系统标志

		unsigned char i_sock; 套接字

		atomic_t i_writecount; 写者记数

		void* i_security; 安全模块

		__u32 i_generation; 索引节点版本号

		union {

		void* generic_ip; 文件特殊信息

	} u;

};

   inode:存放了单个文件的所有属性

有以下特点!!!!

  • 每个 inode 大小均固定为 128 bytes;
  • 每个文件都仅会占用一个 inode ,因此文件系统能够创建的文件数量与 inode 的数量有关;
  • 一个文件只需要一个inode节点来存储文件的元信息就够了,所以文件和inode节点是一一对应的(注意这里是文件,不是文件名);

到现在我们就明白了我们最开始讲的:文件的属性和文件的内容是分开来存储的!!!

上面显示的内容叫文件的属性,存在inode里面

上面显示的是文件的内容,存在data block里面!!

这里我要告诉大家一个比较震惊的事实:文件属性不包含文件名,操作系统只知道文件的inode编号

我们怎么查这个编号呢?

最前面的就是inode编号 

我们找到了inode,又怎么能找到我们的数据块的?

我们看看inode里面存了什么再说

 怎么样?

我们只需要找到inode编号,按照inode 表访问inode,然后就能访问到数据块

5.2.2.2.inode和inode table的区别和联系
  1. inode table的作用与结构
    • 索引节点的组织inode table作为一个数组或类似的数据结构,其每个元素都是一个inode。它为文件系统提供了一个有效的方式组织和查找所有的inode,即通过inode号来索引对应的inode,从而实现对文件和目录的高效管理。
    • 优化文件访问速度:通过inode table,文件系统能够快速定位到任何指定的inode,进而访问或修改文件的元数据和数据块位置信息,这对于提高文件系统的读写速度非常关键。
  2. 二者的关系
    • 相互依存inode是文件元数据的容器,而inode table则是这些容器的集合,负责组织和管理这些inode。没有inode,inode table无法发挥作用;反之,如果没有inode table的组织,inode则会变得孤立,难以被系统有效利用。
    • 功能互补:inode关注单个文件的元数据和数据块索引,而inode table则从宏观上组织所有inode,确保文件系统的有序和高效运行。两者的功能相互补充,共同支持文件系统的基本操作,如文件的创建、删除、读取和写入等。

 

有人想问整个inode_number在哪里?

源码里的unsigned long i_ino就是inode_number 

 5.2.2.block bitmap(块位图)

        我们现在面临一个问题,假设我们的data block有20000个块,创建一个文件就要申请块,删除一个文件就要释放块,这么多块,那我们怎么知道哪些块被使用了,哪些没有被使用呢?

        这就要通过区块对照表的辅助了。从区块对照表当中可以知道哪些区块是空的,因此我们的系统就能够很快速地找到可使用的空间来处理文件。
        同样,如果你删除某些文件时,那么那些文件原本占用的区块号码就要释放出来,此时在区块对照表当中对应到该区块号码的标志就要修改成为【未使用中】,这就是对照表的功能。

          block bitmap是一种数据结构,它的主要功能是用于追踪每个block group中哪些block已经被使用。具体来说,block bitmap是一个特殊的文件,其大小恰好为一个block,而在这个block中,每个bit表示一个对应block的占用情况。如果该位为0,则表示对应的block为空,如果为1,则表示相应的block中存有数据。

          这种block bitmap技术的优势在于,当需要读取或修改文件时,可以快速找到空闲的block位置。例如,当执行写入操作时,系统会首先检查block bitmap,找出哪些block是空闲的,然后将新的数据写入到这些空闲的block中。同样地,当某个block不再使用时,系统会在block bitmap中将相应的bit标记为可用,以供后续的存储操作使用。

          此外,需要注意的是,一个block group中最多只能包含8×4096=32768个block。因此,对于一个含有大量数据的磁盘分区来说,可能需要多个block bitmap来分别记录各个block group的使用情况。

 看到这里你也应该明白了,新建、删除文件只需要改块位图即可!

5.2.3. inode bitmap(inode位图)

        这个其实与区块对照表的功能类似,只是区块对照表记录的是使用与未使用的区块号码,inode对照表则是记录使用与未使用的inode号码。

        在linux系统中,inode bitmap是一种数据结构,它的主要功能是用于追踪inode table中的每个inode是否已经被使用。具体来说,每个bitmap中的每一个位都对应于inode table中的一个inode,如果该位为0,则表示对应的inode为空,如果为1,则表示相应的inode 已被使用。

       这种位图技术(bitmap)的优势在于,当需要修改文件系统时,可以快速找到空闲的inode位置。例如,当需要新建一个文件时,系统会先检查inode bitmap中哪些inode是空闲的,然后将新文件的信息存储到这个空闲的inode中。同样地,当文件被删除时,对应的inode会被标记为可用,以供后续的新建文件使用。

        inode bitmap的比特位的位置和inode编号映射起来,比特位的内容和inode的状态相关

5.2.4.gdt(global descriptor table)

我们这个block group的所有属性都放在这里!!!

描述的是整个分组基本的使用情况,inode table和data block用了多少,还剩多少,总共多少,都在这里存着

5.2.5.super block(超级块)

         在linux操作系统中,superblock是一个特殊的数据结构,它记录了文件系统的整体信息,包括inode和block的总量、使用量、剩余量,以及档案系统的格式与相关信息等。

        具体来说,它包含了文件系统的类型、block大小、block总数、inode大小、inode总数、group的总数等等。

需要注意的是只有个别组内会有superblock,并不是所有的组都有。此外,有super block的group 中的superblock都是对 main superblock(主superblock)的备份,用于处理主superblock故障或者误删的情况。

6.格式化

至此,我们的文件系统讲完了,我们来讲讲格式化

 7.理解文件操作

 我们怎么理解文件操作呢?

我们先复习一下

  • linux系统中,一个文件有一个inode,每个inode有自己的inode编号(只在自己的分区有效),inode的设置是以分区为单位的,不能跨分区
  • inode表示文件的所有属性,但是文件名并不是属性

7.1.新建一个文件

首先我们创建文件是在某个路径下面创建,这个路径可以确定我们是在哪个分区下面,哪个分组下面,分区给我们的文件分配一个inode

假设我们想要新增一个文件,此时文件系统的操作是:

  • 1.先确定用户对于欲新增文件的目录是否具有w与x的权限,若有的话才能新增;
  • 2.根据inode bitmap找到没有使用的inode号码,并将新文件的权限/属性写入;
  • 3.根据block bitmap找到没有使用中的区块号码,并将实际的数据写入区块中,且更新inode的区块指向数据;
  • 4.将刚刚写入的inode与区块数据同步更新inode bitmap与block bitmap,并更新super block的内容。

其实就是查查inode bitmap里没有使用的inode

7.2.删除一个文件

删除文件的步骤

  • 首先找到inode编号
  • 再将该文件对应的inode,在inode bitmap当中置为无效(置0)
  • 最后将该文件申请的数据块,在block bitmap当中置为无效(置0)

此删除操作并不会真正将文件对应的信息删除,而只是将其inode号和数据块号置为了无效,起到了访问不到就等于删除的效果

说白了:删除=允许被覆盖 

         为什么说是短时间内呢,

        因为该文件对应的inode号和数据块号已经被置为了无效,因此后续创建其他文件或是对其他文件进行写入操作申请inode号和数据块号时,可能会将该置为无效了的inode号和数据块号分配出去,此时删除文件的数据就会被覆盖,也就无法恢复文件了。

7.3.查找一个文件

cat找文件内容的路径如下:目录->分区->分组->inode bitmap(看看对应inode的位置是不是1,如果是就去读取inode table)->inode table -> datablock

7.4.修改一个文件

我们要修改什么?

改文件的什么?要修改之前都得找到inode,这跟上面不是一样吗??

8.如何理解目录

linux下一切皆是文件,目录也是文件,目录也有自己独立的inode,自己的属性

 问题来了

目录有内容吗?-》目录要不要data block?

目录当然要,那目录的数据块存的是什么?

存放的是该目录下   的    所包含文件的文件名,以及该文件名对应的inode号码。

系统是根据文件名找到inode的!!!!

ls命令只列出目录文件中的所有文件名:

ls -i命令列出整个目录文件,即文件名和inode号码:

如果要查看文件的详细信息,就必须根据文件名找到inode号码,再访问inode节点,读取信息。ls -l命令列出文件的详细信息。

来回答几个问题

 

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com