首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Linux 核心檔案系統開發實戰(四):umount 協載機制深度解析

     編輯:Java 綜合教學

Linux 核心檔案系統開發實戰(四):umount 協載機制深度解析

時隔多年,我在磁碟深處重新發現了當初編寫的原始碼 myfs.zip,決定重啟這個系列教學。本文基於 Linux 3.10 核心版本,從頭構建一個基於 block 設備的簡易檔案系統,與前三篇內容可能略有差異,但核心概念一脈相承。

umount 核心職責:數據落盤與資源釋放

當用戶執行 umount 協載檔案系統時,核心必須完成兩項關鍵任務:

  • 將所有 媒體數據(文件實際內容)與 元數據(inode、superblock 等結構)強制刷新回底層儲存設備
  • 釋放記憶體中佔用的核心資料結構(如 super_block、inode 緩存等)

super_operations:掛載與協載的橋樑

在 mount 階段的 fill_super 中,我們為 super_block 註冊了操作集:

sb->s_op = &dfs_sops;

若未提供此結構,雖不影響 umount 流程,但所有髒數據將永不回寫設備,導致數據丟失。dfs_sops 定義如下:

const struct super_operations dfs_sops = {
    .alloc_inode = dfs_alloc_inode,
    .put_super   = dfs_put_super,
    .sync_fs     = dfs_sync_fs,
};

除掛載必需的 alloc_inode 外,新增兩個回調:

  • put_super:協載前將超級塊元數據寫回設備
  • sync_fs:同步整個檔案系統,將所有髒 inode、頁面緩存落盤

因尚未實現文件創建/更新邏輯,本階段僅實現 put_super。

核心實現代碼走讀

dfs_put_super:超級塊持久化

static void dfs_put_super(struct super_block *sb)
{
    struct dfs_sb_info *sbi = DFS_SB(sb);
    dfs_trace("%s\n", __func__);

    if (sbi->dirty)
        return dfs_write_super(sb);
    kfree(sbi);
}

邏輯清晰:若超級塊被標記為髒(dirty),調用 dfs_write_super 寫回;否則直接釋放私有數據結構 dfs_sb_info。

dfs_sync_fs:檔案系統級同步(預留擴展)

static int dfs_sync_fs(struct super_block *sb, int wait)
{
    dfs_trace("%s\n", __func__);
    dfs_put_super(sb);
    /* todo: sync files as well */
    return 0;
}

目前僅委託給 dfs_put_super,後續需補充文件數據同步邏輯(遍歷 inode 列表、刷新 address_space 等)。

dfs_write_super:底層塊設備寫入

static void dfs_write_super(struct super_block *sb)
{
    struct dfs_sb_info *sbi = DFS_SB(sb);
    struct buffer_head *bh;
    struct dfs_super_block ds;

    dfs_trace("%s\n", __func__);
    #define DFS_SB_BLOCK 0
    if (!(bh = sb_bread(sb, DFS_SB_BLOCK)))
        return;

    /* 更新超級塊關鍵字段 */
    ds.inode_count   = sbi->inode_count;
    ds.block_size    = sbi->block_size;
    ds.total_blocks  = sbi->total_blocks;
    ds.free_blocks   = sbi->free_blocks;
    ds.used_blocks   = sbi->used_blocks;
    ds.bad_blocks    = sbi->bad_blocks;
    ds.inode_size    = sbi->inode_size;
    ds.magic         = sbi->magic;
    ds.max_inode_no  = sbi->max_inode_no;

    memcpy(bh->b_data, &ds, sizeof(struct dfs_super_block));
    mark_buffer_dirty(bh);
    sync_dirty_buffer(bh);
    brelse(bh);
}

關鍵步驟:

  1. 讀取設備第 0 塊(超級塊固定位置)
  2. 將記憶體中 dfs_sb_info 字段拷貝至磁盤格式結構 dfs_super_block
  3. mark_buffer_dirty + sync_dirty_buffer 確保數據實際寫入硬體
  4. 釋放 buffer_head 引用

實測驗證與缺失功能補充

掛載測試輸出顯示 /oem 已正常掛載為 dfs 類型。但嘗試 cd /oem 時報錯 Not a directory,原因在於未實現 lookup 操作,VFS 無法解析目錄項。補充極簡實現:

static struct dentry *dfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
{
    return NULL; // 暫不支援目錄遍歷
}

const struct inode_operations dfs_inode_operations = {
    .getattr = dfs_getattr,
    .lookup  = dfs_lookup,
};

註冊 inode_operations 後,協載流程可正常跑通,但目錄瀏覽仍需後續實現 readdir、iterate 等回調。

本章小結

  • umount 本質是 數據落盤 + 資源釋放 的原子操作
  • super_operations 中的 put_super、sync_fs 是檔案系統開發者必須正確實現的兩個鉤子
  • 超級塊寫回需使用 buffer_head 機制,配合 mark_buffer_dirty/sync_dirty_buffer 保證持久化
  • 缺少 lookup 會導致 VFS 無法解析路徑,哪怕掛載成功也無法進入目錄

下一章將著手實現 inode 分配、目錄項操作與基本讀寫路徑,敬請期待。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved