跳转至

File System Implementation

Layered File System

  • Logical file system

    • Keep all the meta-data necessary for the file system
    • It stores the directory structure
    • It stores a data structure that stores the file description (File Control Block - FCB)
    • Input from above:
      • Open/Read/Write filepath
    • Output to below:
      • Read/Write logical blocks
  • File-organization module

    • Knows about logical file blocks (from 0 to N) and corresponding physical file blocks: it performs translation

      把逻辑块映射到物理块。输入是逻辑块号,输出是物理块号。

    • It also manages free space

  • Basic file system

    • Allocates/maintains various buffers that contain file-system, directory, and data blocks.

      提供 buffer,用于缓存文件系统、目录和数据块。在 Linux 中称为 IO buffer。

  • I/O Control

    Device drivers and interrupt handlers.

    I/O control 将上层的指令转换为 low-level, hardware-specific 的指令来实现相关操作。同时也可以发中断。

分层是为了降低复杂度,通过接口来隔离不同层。但也降低了性能。

File System Data Structures

on-disk 的是可持久化的(persisitant),in-memory 的是易失的(volatile)。

  • On-disk structures

    • An optional boot control block
    • A volume control block
    • A directory
    • A per-file File Control Block (FCB)
  • In-memory structures

    • A mount table with one entry per mounted volume
    • A directory cache for fast path translation (performance)
    • A global open-file table
    • A per-process open-file table
    • Various buffers holding disk blocks “in transit” (performance)

File Control Block

在 UNIX 中,FCB 被称为 inode;在 NTFS 中,每个 FCB 是一个叫 master file table 的结构的一行。

Example

这里前面的是 metadata,后面存有数据块的指针。

File Creation

逻辑文件系统为这个新的文件分配一个新的 FCB(与文件一对一映射),随后把它放到一个目录里,将对应的 directory 读到内存,并用 filename 和 FCB 更新 directory。

File Open & Close

系统调用 open() 将文件名传给 logical file system,后者搜索 system-wide open-file table 以确定该文件是否正在被其他进程使用。

  • 如果有,则直接在当前进程的 per-process open-file table 中新建一个 entry,指向 system-wide open-file table 中的对应项即可。
  • 否则,需要在 directory 中找到这个 file name,并将其 FCB 从磁盘加载到内存中,并将其放在 system-wide open-file table 中。然后,在当前进程的 per-process open-file table 中新建一个 entry,指向 system-wide open-file table 中的对应项。

(这里的 index 就是 file descriptor)

打开文件之后就拿到了一个 pointer,指向这个文件。

如果要关闭文件,per-process open-file table 中对应 entry 将被删除,system-wide open-file table 中的 counter 将被 -1;如果该 counter 清零,则更新的 metadata 将被写会磁盘上的 directory structure 中,system-wide open-file table 的对应 entry 将被删除。

在 Unix 里面(UFS)System-Wide Open-File Table 会放设备、网络,所以我们的设备也是用文件来表示的,读写文件相当于读写设备。

Virtual File Systems

操作系统可以同时支持多种类型的文件系统。

VFS provides an object-oriented way of implementing file systems.

  • OS defines a common interface for FS, all fses implement them.
  • System call is implemented based on this common interface.

Example

VFS Implementation
Write syscall -> vfs_write -> indirect call -> ext4_file_write_iter

在需要调用某个函数时,去对应 FS 的函数表的约定位置找到函数指针就可以访问了。这和 C++ 中多态的虚函数表是类似的。

在我们创建这个文件的时候,file->f_op 就被设为了对应的函数表的地址(f_op 是指针)。

struct file 里存了文件的 file_operations,但没有存文件的 type,因为我们有知道操作对应 fs 的文件,就不需要知道文件的类型了。

Directory Implementation

Directory is a special file, storing the mapping from file name to inode.

他的数据块有自己的名字(目录项 dir_entry),每一个目录项有一个 inode、目录项长度、名字长度。

最简单的实现方式是 linear list,即维护 dir_entry[]。这种方案的缺点是查找文件很费时。

使用有序数据结构(有序表、平衡树、B+ 树等)能够优化这一问题。

使用 hash table 也可以解决这一问题。

创建一个文件:首先找到当前目录的 inode,在其指向的数据块里加上一个目录项。(在之前要先分配一个 inode 随后才能放入目录项)

Disk Block Allocation

Files need to be allocated with disk blocks to store data.

这里介绍 3 种不同的 policy。

Contiguous Allocation

Each file is in a set of contiguous blocks.

优点是顺序访问很快,同时目录也只需要维护文件的起始 block 及其长度;缺点是会带来碎片(磁盘通常够大,我们可能不在意这个问题),文件可能会增大,需要重新分配空间。

Example

Linked Allocation

Linked allocation: each file is a linked list of disk blocks.

允许块分布在磁盘上的任何地方,只需要维护每个块的下一个块的地址即可。这样就没有外部碎片了。缺点是定位某个块需要遍历链表,需要很多 IO。而且 reliablity 也不好,如果某个块的指针坏掉,后面的块就都访问不到了。而且这种实现方式不支持 random access。

解决方案之一是,将多个块组成 cluster。这种方案会增加内部碎片。

Example

FAT

Indexed Allocation

Indexed allocation: each file has its own index blocks of pointers to its data blocks.

用一个块只做 index,里面存放指向数据块的指针。这样可以支持 random access。缺点是 reliability 不好,如果 index 块坏了,文件就访问不到了;浪费空间(需要一个块做 index)。

Example

需要一个方法分配 index block 的大小(太大会浪费,太小那么指向的空间小)。我们可以把 index block 链接起来,或者用多级索引。

Example

如果 block size 为 4KB,那么 Linux 中能创建的最大文件大小为 4TB+4GB+4MB+48KB。如果我们有一个 10KB 的文件,那么只需要前 3 个 direct pointer 就可以,后面的指针都是 NULL,不需要展开。

Free-Space Management

  • Bitmap

    每一个 block 都用一个比特记录分配状态。容易找到连续的空闲空间,但是占用额外空间。

    Example

  • Linked Free Space

    Keep free blocks in linked list.

    好处是不会浪费空间,但是不能快速找到连续的空闲空间,效率低。

    Example

  • Grouping

    Use indexes to group free blocks. Store address of n-1 free blocks in the first free block, plus a pointer to the next index block.

    维护若干个 block 形成的链表,每个 block 保存若干空闲块的地址。

  • Counting

    a link of clusters (starting block + # of contiguous blocks).

    维护的是连续的空闲块的链表,即链表的每个结点是连续的空闲块的首块指针和连续空虚块的数量。

File System Performance

To improve file system performance

  • Keeping data and metadata close together
  • Use cache: separate section of main memory for frequently used blocks
  • Use asynchronous writes, it can be buffered/cached, thus faster
  • Free-behind and read-ahead

Takeaway

Takeaway

  • File system layers
  • File system implementation
    • On-disk structure, in-memory structure
    • inode
  • File creation(), open()
  • VFS
  • Directory Implementation
  • Allocation Methods
    • Contiguous, linked, indexed
  • Free-Space Management

最后更新: 2024年1月7日 14:20:35
创建日期: 2024年1月7日 14:20:35

评论