從編程視角看 Linux 文件系統

一、引言

Linux 文件系統是 Linux 操作系統的核心組件之一,它爲用戶和應用程序提供了統一的文件訪問接口,屏蔽了底層存儲設備的差異。從編程視角來看,理解 Linux 文件系統的結構和原理對於開發高效、可靠的文件操作程序至關重要。

POSIX 接口介紹

POSIX(Portable Operating System Interface)接口是 Linux 系統中用於文件操作的一組標準接口,它爲應用程序提供了統一的文件訪問方式。以下是一些常用的 POSIX 接口:

1. open() 接口

open() 函數用於打開一個文件,其函數原型爲:

int open(const char *pathname, int flags, mode_t mode);

2. close() 接口

close() 函數用於關閉一個已經打開的文件,其函數原型爲:

int close(int fd);

3. read() 接口

read() 函數用於從文件中讀取數據,其函數原型爲:

ssize_t read(int fd, void *buf, size_t count);

4. write() 接口

write() 函數用於向文件中寫入數據,其函數原型爲:

ssize_t write(int fd, const void *buf, size_t count);

三、Linux 文件編程示例

以下是一個簡單的文件讀寫示例,展示瞭如何使用 POSIX 接口進行文件操作:

#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

intmain() {
    int fd;
    char *filename = "example.txt";
    char buf[128];

    // 打開文件
    fd = open(filename, O_RDWR | O_CREAT, 0644);
    if (fd < 0) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }

    // 寫入數據
    constchar *data = "Hello, Linux file system!";
    ssize_t written = write(fd, data, strlen(data));
    if (written < 0) {
        perror("Failed to write to file");
        close(fd);
        exit(EXIT_FAILURE);
    }

    // 讀取數據
    ssize_t read_bytes = read(fd, buf, sizeof(buf));
    if (read_bytes < 0) {
        perror("Failed to read from file");
        close(fd);
        exit(EXIT_FAILURE);
    }

    buf[read_bytes] = '\0';
    printf("Read from file: %s\n", buf);

    // 關閉文件
    close(fd);
    return0;
}

四、文件 IO Stack 介紹

Linux 文件 IO Stack 是一個分層的結構,從用戶空間到內核空間再到硬件設備,主要包括以下幾個層次:

1. LibC 層

LibC 是用戶空間的標準 C 庫,它是 GNU C Library 的一部分,封裝了 POSIX 接口,爲應用程序提供方便的文件操作函數。例如,fopen()、fread() 和 fwrite() 等函數都是 LibC 提供的。

2. POSIX 接口層

POSIX 接口層定義了標準的文件操作接口,如 open()、close()、read() 和 write() 等。這些接口在用戶空間和內核空間之間起到了橋樑作用。

3. VFS(虛擬文件系統)層

VFS 是 Linux 內核中的一個抽象層,它爲各種具體的文件系統(如 ext4、XFS 等)提供了統一的接口。

4. 具體文件系統層(XFS)

XFS 是一種高性能的基於塊的(Block-based)文件系統。

5. 塊設備層

塊設備層負責與磁盤等存儲設備進行交互,實現文件數據的讀寫操作。它使用塊設備驅動程序(Block Device Driver)來管理磁盤設備。

五、VFS/XFS/Disks 原理介紹

1. VFS 數據結構

VFS 使用以下關鍵數據結構來管理文件系統:

關係

2. XFS 原理

XFS 是一種高性能的文件系統,它具有以下特點:

XFS 在磁盤上的 layout

XFS 文件系統在磁盤上的佈局通常包括以下幾個部分:

  1. 1. 超級塊(Superblock)

    struct xfs_super_block {
        __be32 sb_magicnum;       /* 魔術數,用於標識文件系統 */
        __be32 sb_blocksize;      /* 文件系統的塊大小 */
        __be64 sb_dblocks;        /* 文件系統中的總塊數 */
        __be64 sb_rblocks;        /* 預留塊數 */
        __be64 sb_rextents;       /* 預留空間的總擴展數 */
        __u8 sb_uuid[16];         /* 文件系統的 UUID */
        __be32 sb_logstart;       /* 日誌區域的起始塊號 */
        /* 其他字段 */
    };
  1. 2. 日誌區域(Log)
  1. 3. 可變長度數據區域(AGF and AGFL)
  1. 4. B+ 樹索引區域(B+ Tree Indexes)
  1. 5. 用戶數據區域(User Data Area)

3. 磁盤(Disks)原理

磁盤是一種塊設備,它使用塊作爲基本的存儲單位。磁盤的物理結構包括盤片、磁頭、磁道和扇區。磁盤的尋址方式包括 CHS(Cylinder-Head-Sector)地址和 LBA(Logical Block Address)地址。

六、IO Stack 的讀寫流程

1. read 操作流程

  1. 1. 用戶空間發起 read 請求:應用程序調用 read() 函數,請求從文件中讀取數據。

  2. 2. LibC 庫處理:LibC 庫對 read() 請求進行初步封裝和處理,如參數檢查、緩衝區管理等。

  3. 3. 進入內核 POSIX 接口層:進入內核後,POSIX 接口層將請求轉交給 VFS 層。

  4. 4. VFS 層解析和轉發:VFS 層通過文件系統的掛載點信息,確定目標文件所屬的具體文件系統類型(如 XFS)。

  5. 5. 具體文件系統處理讀請求:XFS 文件系統根據請求的文件偏移量和大小,從磁盤上讀取相應的數據塊,並通過緩衝區管理機制將數據傳遞給 VFS 層。文件系統可能會使用緩存(如頁緩存)來提高讀取性能。

  6. 6. VFS 層返回數據:VFS 層將數據返回給 POSIX 接口層,再由 POSIX 接口層返回給用戶空間的 LibC 庫。

  7. 7. LibC 庫返回數據:LibC 庫將讀取到的數據返回給應用程序,完成整個 read 操作流程。

2. write 操作流程

  1. 1. 用戶空間發起 write 請求:應用程序調用 write() 函數,將數據寫入文件。

  2. 2. LibC 庫處理:LibC 庫對 write() 請求進行初步封裝和處理,如參數檢查、緩衝區管理等。

  3. 3. 進入內核 POSIX 接口層:進入內核後,POSIX 接口層將請求轉交給 VFS 層。

  4. 4. VFS 層解析和轉發:VFS 層通過文件系統的掛載點信息,確定目標文件所屬的具體文件系統類型(如 XFS)。

  5. 5. 具體文件系統處理寫請求:XFS 文件系統接收寫入請求,將數據寫入緩衝區,並根據需要同步到磁盤。文件系統可能會使用緩存(如頁緩存)來提高寫入性能。

  6. 6. VFS 層處理完成並返回寫入結果:VFS 層將寫入結果返回給 POSIX 接口層,再由 POSIX 接口層返回給用戶空間的 LibC 庫。

  7. 7. LibC 庫返回結果:LibC 庫將寫入結果返回給應用程序,完成整個 write 操作流程。

七、Linux Storage IO Stack

網址:https://www.thomas-krenn.com/en/wiki/Linux_Storage_Stack_Diagram

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/tH-xhZ9JXcfAVw_X9tc_9Q