時隔多年,我在磁碟深處重新發現了當初編寫的原始碼 myfs.zip,決定重啟這個系列教學。本文基於 Linux 3.10 核心版本,從頭構建一個基於 block 設備的簡易檔案系統,與前三篇內容可能略有差異,但核心概念一脈相承。
當用戶執行 umount 協載檔案系統時,核心必須完成兩項關鍵任務:
super_block、inode 緩存等)在 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。
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。
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 等)。
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);
}
關鍵步驟:
dfs_sb_info 字段拷貝至磁盤格式結構 dfs_super_blockmark_buffer_dirty + sync_dirty_buffer 確保數據實際寫入硬體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 分配、目錄項操作與基本讀寫路徑,敬請期待。