文件系统

什么是文件系统

文件系统 决定着从存储设备中对文件进行 命名、 存储 和 检索 的方式

为什么需要文件系统

嗯,答案是,如果没有文件系统,存储设备会将大量数据简单地堆积存储,如此一来数据间便无法区分。
但也不能说文件系统的功能仅限于整理数据。

空间管理,元数据,数据加密,文件访问控制和数据完整性同样是文件系统施展拳脚的阵地

那将存储设备当成一个图书馆,如何划分空间,如何分配存储,如何索引 如何保护

分区

举例来说,一个基础的Linux安装就具有三个分区:一个专门用于存储操作系统,一个专门用于存放用户文件,外加一个交换分区。

分区方案

  • 主引导记录(MBR)方案
  • GUID分区表(GPT)方案

无论选择哪种方案,存储设备上的前几个存储块所存储的始终都是有关分区的关键数据。

固件是嵌入电子设备中以操作该设备或引导另一个程序来操作该设备的低级软件。
固件存在于计算机,外围设备(键盘,鼠标和打印机)中,甚至存在于家用电器中。
在计算机中,固件为诸如操作系统之类的复杂软件提供了启动和使用硬件组件的标准环境。
但是,在打印机等较为简单的系统上,固件却是设备的主要操作系统。打印机菜单就是其固件的人机界面。
计算机固件依据以下两个规范执行:
基本输入/输出(BIOS)
统一可扩展固件接口(UEFI)

MBR内存有以下信息:
引导程序,它是(机器代码中的)一个 简单程序,用于启动引导过程的第一阶段
分区表,其中包含有关分区的信息。

现在的文件系统

FAT
新技术文件系统(NTFS)
扩展文件分配表(exFAT)
分层文件系统(HFS), HFS+ 以及最近推出的 苹果文件系统(APFS).

文件系统中的 扩展文件系统(ext) 家族是专门为Linux内核(即Linux操作系统的核心)创建的。

文件系统的体系架构

物理层

物理层是文件系统的具体实现,负责数据存储和检索,以及存储设备上的空间管理(或者更确切地说是分区)。
物理文件系统通过 设备驱动程序与实际的存储硬件进行交互

虚拟文件系统 (抽象虚拟层)

虚拟文件系统提供了一种支持在操作系统上安装的各类文件系统的 一致视图。
那么,这是否意味着一个操作系统可以同时使用多种文件系统呢?
答案是肯定的!
可移动存储工具通常都具有与计算机不同的文件系统。
例如,在使用NTFS作为主要文件系统的Windows环境下,闪存可能已格式化为exFAT或FAT32。

VFS堪称连接用户(你)和后台文件系统的“便利层”。
它制定了一种 合同 ,要求所有的物理文件系统都必须以操作系统支持的方式工作。

但是,这种合规性并未内置于文件系统的核心中,也就是说,文件系统的源代码并不包含对各种操作系统的支持。

事实是,这些源代码利用 文件系统驱动程序 来遵守VFS的规则。
驱动程序是一种能够使软件与另一个软件或硬件进行通信的特殊程序。
但用户程序不会直接与VFS交互。
而是利用位于程序和VFS之间的统一API实现交互。
没错,我们接下来要说的就是逻辑文件系统。
逻辑文件系统是文件系统中面向用户的一层。通过提供API,它能使用户程序无需处理任何存储硬件便能执行各种文件操作,例如 打开, 读, 写。
话说回来,VFS也在逻辑文件系统(程序与之交互)和一组物理文件系统之间搭建了桥梁。

挂载文件系统

元数据

文件元数据
文件元数据是一种数据结构,存储 有关文件的数据,比如:

  • 文件大小
  • 时间戳,如创建日期,上次访问日期和修改日期
  • 文件所有者
  • 文件权限状态(“谁”可以“如何”处理文件)
    *分区上的哪些块分配给了文件
    等等

空间管理

存储设备内分为大小固定的区块,称为 扇区。

扇区是存储设备上的 最小存储单元,大小介于512字节和4096字节之间(高级格式)。

然而,文件系统实际使用高级概念 区块 作为存储单元。

块是对物理扇区的抽象,由多个扇区组成。

根据文件的大小,文件系统为每个文件分配一个或多个块。

进行空间管理时,文件系统很明确分区上每个 已使用 和 未使用 的块,因此便可以为新文件分配空间或在收到请求时获取现有文件。

ext4格式的分区中最基本的存储单元就是块。

为便于管理,连续的块会被集中在一起,组成 块组。

linux文件系统

https://pic1.zhimg.com/80/v2-9a85e905f1d5d649bbd6b5524d8b2954_720w.webp
Linux 文件系统会为每个文件分配两个数据结构:索引节点(index node)和目录项(directory entry),它们主要用来记录文件的元信息和目录层次结构。

索引节点,也就是 inode,用来记录文件的元信息,比如 inode 编号、文件大小、访问权限、创建时间、修改时间、数据在磁盘的位置等等。索引节点是文件的唯一标识,它们之间一一对应,也同样都会被存储在硬盘中,所以索引节点同样占用磁盘空间。
目录项,也就是 dentry,用来记录文件的名字、索引节点指针以及与其他目录项的层级关联关系。多个目录项关联起来,就会形成目录结构,但它与索引节点不同的是,目录项是由内核维护的一个数据结构,不存放于磁盘,而是缓存在内存。
https://pic2.zhimg.com/80/v2-9d77e25913894df26b0374ceae25c605_720w.webp
https://pic3.zhimg.com/80/v2-b92499b17ed11bc279689ecdb6efb4b6_720w.webp

文件的使用

查找

空闲空间管理

分配(堆 栈)(为啥不压栈)(就是链表-但不适合大文件)

空闲表法

空闲链表法

位图法

目录的存储

硬链接是多个目录项中的「索引节点」指向一个文件,也就是指向同一个 inode,但是 inode 是不可能跨越文件系统的,每个文件系统都有各自的 inode 数据结构和列表,所以硬链接是不可用于跨文件系统的。由于多个目录项都是指向一个 inode,那么只有删除文件的所有硬链接以及源文件时,系统才会彻底删除该文件。

文件io

缓冲与非缓冲 I/O

比方说,很多程序遇到换行时才真正输出,而换行前的内容,其实就是被标准库暂时缓存了起来,这样做的目的是,减少系统调用的次数,毕竟系统调用是有 CPU 上下文切换的开销的。

直接与非直接 I/O

我们都知道磁盘 I/O 是非常慢的,所以 Linux 内核为了减少磁盘 I/O 次数,在系统调用后,会把用户数据拷贝到内核中缓存起来,这个内核缓存空间也就是「页缓存」,只有当缓存满足某些条件的时候,才发起磁盘 I/O 的请求。

那么,根据是「否利用操作系统的缓存」,可以把文件 I/O 分为直接 I/O 与非直接 I/O:
直接 I/O,不会发生内核缓存和用户程序之间数据复制,而是直接经过文件系统访问磁盘。
非直接 I/O,读操作时,数据从内核缓存中拷贝给用户程序,写操作时,数据从用户程序拷贝给内核缓存,再由内核决定什么时候写入数据到磁盘。
如果你在使用文件操作类的系统调用函数时,指定了 O_DIRECT 标志,则表示使用直接 I/O。如果没有设置过,默认使用的是非直接 I/O。

阻塞与非阻塞 I/O VS 同步与异步 I/O

注意,阻塞等待的是「内核数据准备好」和「数据从内核态拷贝到用户态」这两个过程。过程如下图:

下图是使用 select I/O 多路复用过程。注意,read 获取数据的过程(数据从内核态拷贝到用户态的过程),也是一个同步的过程,需要等待:

阻塞 I/O 会阻塞在「过程 1 」和「过程 2」,而非阻塞 I/O 和基于非阻塞 I/O 的多路复用只会阻塞在「过程 2」,所以这三个都可以认为是同步 I/O。

异步 I/O 则不同,「过程 1 」和「过程 2 」都不会阻塞

posted @ 2024-04-22 14:15  skyycj  阅读(3)  评论(0编辑  收藏  举报