文件系统基础

文件系统基础

  1. 为什么我们需要文件系统
    • 持久化保存数据需求(Persistence)
    • 进程结束、关机/关电、宕机/掉电
    • 使用持久化存储设备:磁盘、SSD等
  2. FS 是对持久化数据存储的抽象
    • 给用户/程序开发者提供一个逻辑上的持久化存储
      • 文件、目录形式
      • 简单、易理解、操作方便
    • 将复杂的、公共的管理功能从用户程序中移出
      • 存储设备管理,例如磁盘
      • 数据管理,即程序持久化数据的组织和增删改查
  3. 对FS的基本需求
    • 能够保存大量(复杂多样)的信息 -> 管理问题
    • 多个进程同时访问 -> 并发控制问题
    • 多用户共享数据 & 私有数据 -> 安全保护问题

文件系统的用户视图

  1. 文件:数据组织的单位
    • 文件是命名的字节数组
    • 用户将数据组织成文件,根据文件名来访问对应的数据
    • FS不感知文件的内容:使用文件的进程负责解析内容
  2. 目录:文件组织的单位
    • 一组文件和目录的命名集合
    • 父目录、子目录
    • 同一目录下没有重名的
  3. 名字空间:树形层次结构
    • 文件系统的逻辑视图

文件

  1. 文件名:由字母、数字及某些特殊字符组成的字符串
    • 用户根据文件名来访问文件
    • 文件扩展名:描述文件的用途
  2. 文件属性
    • 文件大小、所有者、时间戳、访问权限
    • 文件逻辑地址:0..fsize-1,指示数据在文件中的位置
  3. 文件内容:无结构
    • OS将文件视为无结构的字节数组
    • 程序开发者可以定义任意结构的文件
  4. 文件的类型
    • 常规文件、目录文件、设备文件、可执行文件
  5. 文件的访问
    • 打开文件 & 文件描述符
    • 当前位置:文件内部的逻辑地址,范围是[0,fsize-1]
    • 访问方式(Access Mode):读,写,执行
  6. 文件的访问模式(Access Pattern)
    • 顺序访问
      • 从头到尾依次访问每个文件块
      • 顺序访问文件 不等于 磁盘上顺序访问扇区
    • 随机访问
      • 每次随机访问一个文件块
    • 按关键字访问
      • 查找包含关键字的文件及段落
      • 文件系统本身不提供此功能,需要借助应用程序完成
      • 与之相比,数据库自身可以实现按关键字查找记录

目录

  1. 路径
    • 根目录 & 当前工作目录
    • . : 当前目录
    • .. : 根目录
    • 绝对路径 vs 相对路径
  2. 目录:一种特殊的文件
    • 命中 & 属性
    • 目录和文件用相同的数据结构(inode)
      • 通过一个标志(i_mode)来区分文件和目录
    • 目录内容:描述它所包含的目录和文件集合
      • 有结构:逻辑上是一张表
      • 目录项:每个成员一项
      • 不同的FS采用不同的结构
      • 由FS负责维护和解析目录内容
      • 访问目录 vs 访问文件:通过不同的syscall实现

链接

  1. 硬链接
    • 为文件共享提供的一种手段
      • 为文件创建一个新名字,无数据拷贝
      • 多个名字可以指向同一个文件
      • 一个文件可以同时拥有多个名字,甚至位于多个目录中
    • 限制
      • 不能跨文件系统
      • 不能链接目录
  2. 符号链接
    • 另一种文件共享的手段
      • 创造一个普通文件,内容为目标地址的路径(绝对路径/相对路径)

文件系统内部结构

虚拟文件系统 和 物理文件系统

  1. 虚拟文件系统
    • 同时挂载不同类型的FS
      • SUNFS访问本地的磁盘
      • SUN NFS访问远端服务器的FS
    • 实现FS接口和通用功能
  2. 物理文件系统
    • 磁盘布局、数据结构、磁盘空间管理、名字空间管理等
  3. 虚拟文件系统开关表
    • 用于物理文件系统的挂载与卸载
    • 每一种类型的文件系统有一个表项
      • 文件系统类型的名字
      • 初始化函数指针,用于 mount
      • 清除函数指针,用于 umount
    • 例子: mount -t ext4 /dev/sdb /home/os
      • 前提:
        • 文件系统类型ext4必须事先加载进内核
        • 挂载目录 /home/os 必须要已经创建好
      • 步骤
        • 根据文件系统类型,查VFS开关表,找到该ext4类型FS的初始化函数,即ext4_mount()
        • 调用ext4_mount
          • 读取superblock
          • 读取根目录i-node
        • 初始化一些内存数据结构

文件系统主要数据结构

i-node

inode:描述文件/目录,也成为文件元数据

  1. 每个文件用一个i-node来描述
  2. 文件元数据
    • mode: 文件类型和访问权限
    • size: 文件大小
    • nlinks: 硬链接数
    • uid: 所有者的user id
    • gid: 所有者的group id
    • ctime: 文件创建的时间戳
    • atime: 上一次访问文件的时间戳
    • mtime: 上一次修改文件的时间戳
  3. ino:inode number,即i-node的ID,唯一标识一个文件(在一个FS内)
  4. 文件块的索引信息:文件块的磁盘位置信息
    • <offset,count> -> 磁盘上的位置 (文件块# -> 磁盘逻辑块# LBN)
    • 不同的FS采取不同的索引机制

目录项(dentry)

dentry: 目录项,记录文件和inode的对应关系

  1. 目录内容为它所包含的所有子目录和文件的名字及其ino
    • 不包含子目录的内容
  2. 逻辑上,目录是一张映射表
    • 目录项(dentry): 文件名 -> ino
  3. 物理上,目录项是一个字节数组
    • 文件名不等长,数组每一项不等长
  4. 路径解析
    • 根据路径名,获得其ino
    • 逐级目录查找
    • 例子: /home/os/fs01.ppt
      • 从根目录开始,查找/home的ino
      • home目录下查找os的ino
      • os目录下查找fs01.ppt的ino
      • 根据fs01.ppt的ino,找到其数据块,进行读写操作

打开文件表(Open-file table)

打开文件表:记录进程打开的文件信息

  1. 打开文件,通过 fd = open(path,flags,mode)实现
  2. 打开文件表: Open-file table
    • 通过打开文件表(在内存中)把进程与文件的i-node进行关联
    • 路径名解析和权限检查,得到path的ino,读出它的inode(保存在磁盘上)
    • 将磁盘i-node拷贝到一个内存i-node结构中,在打开文件表中增加一项,包含以下内容
      • 文件的Reference Count
      • 当前文件的偏移量
      • 文件的访问模式
      • 内存inode结构的指针

文件描述符表:File Descriptor Table

  1. 每个进程有一个文件描述符表
    • 指针数组,每个指针指向打开文件表中的一项,表示一个打开文件
    • 该指针在文件描述符表中的下表,即文件描述符fd

超级块(superblock)

superblock: 描述文件系统基本信息

  1. 定义一个文件系统
    • 数据块的大小
    • i-node的大小
    • 数据块总数
    • i-node总数
    • 根目录ino
    • i-node表的起始地址
    • Block Bitmap的起始地址
    • i-node Bitmap的起始地址
  2. 当前状态
    • 数据块的使用状态:已使用的块数、预留的块数、剩余的块数...
    • i-node的使用状态:已使用的i-node数、预留的i-node数、剩余的i-node数...

文件系统的磁盘布局

Boot Block | Superblock | Block Bitmap | i-node Bitmap | I-node Array | Data Blocks

  1. 引导块
    • 启动OS的代码
  2. Superblock:定义一个FS
    • FS的相关信息
  3. 空闲空间管理相关的信息
    • Block Bitmap
    • i-node Bitmap
  4. i-node表
    • 每个i-node描述一个文件或目录
  5. 数据块
    • 文件块或目录块