Windows XP Windows 7 Windows 2003 Windows Vista Windows 綜合教學 Linux 系統教學
Windows 10 Windows 8 Windows 2008 Windows NT Windows Server 電腦軟體教學
您现在的位置: Windows教程網 >> Windows教程 >  >> Linux 系統教學 >> Linux 教學

深度解析 Linux 根文件系統掛載流程:從啟動到切換

編輯:Linux 教學

前言

Linux 內核啟動過程中,根文件系統的掛載是最關鍵、最複雜的環節之一。本文從內核源碼角度,系統性剖析 rootfs 的類型、掛載流程、虛擬文件系統初始化,以及最終切換到真實根文件系統的完整鏈路。

根文件系統分類

類型特徵典型場景
虛擬根文件系統運行於記憶體,內核啟動早期提供最小環境initramfs、initrd、嵌入式系統
真實根文件系統持久化儲存於磁碟/Flash/網路,包含完整用戶空間ext4/xfs/btrfs、NFS、SquashFS

虛擬根文件系統演進

  1. initrd (初始 RAM 磁碟):傳統映像檔格式(ext2/minix),固定大小,需文件系統驅動編譯進內核
  2. cpio-initrd:cpio 歸檔格式,支援壓縮,靈活性較好
  3. initramfs (現代標準):內核 2.5+ 引入,內嵌於內核映像,基於 cpio,無固定大小限制,支援動態擴展,掛載為 rootfs (ramfs/tmpfs)

核心掛載流程源碼追蹤

階段一:VFS 與 rootfs 初始化 (start_kernel → mnt_init)


void __init mnt_init(void)
{
    ...
    init_rootfs();      // 註冊 rootfs 文件系統類型
    init_mount_tree();  // 掛載 rootfs 並建立初始命名空間
}

init_rootfs() - 註冊 rootfs


int __init init_rootfs(void)
{
    int err = bdi_init(&ramfs_backing_dev_info);
    if (err) return err;
    err = register_filesystem(&rootfs_fs_type);  // 向 VFS 註冊
    if (err) bdi_destroy(&ramfs_backing_dev_info);
    return err;
}

rootfs_fs_type 定義於 fs/ramfs/inode.c,實際掛載 ramfs(或配置為 tmpfs)。

init_mount_tree() - 建立初始掛載樹


static void __init init_mount_tree(void)
{
    struct vfsmount *mnt = do_kern_mount("rootfs", 0, "rootfs", NULL);
    // 建立掛載命名空間
    struct mnt_namespace *ns = kmalloc(sizeof(*ns), GFP_KERNEL);
    // 設定 init_task 的根目錄與當前工作目錄為 "/"
    set_fs_pwd(current->fs, &root);
    set_fs_root(current->fs, &root);
}

此時 / 指向記憶體中的 rootfs,**尚未**掛載真實磁碟分區。

階段二:initramfs 釋放 (kernel_init → populate_rootfs)


static int __init populate_rootfs(void)
{
    char *err = unpack_to_rootfs(__initramfs_start, __initramfs_end - __initramfs_start, 0);
    if (err) panic(err);
    if (initrd_start) {
        // 處理傳統 initrd 映像
        ...
    }
    return 0;
}

unpack_to_rootfs() 將內核映像附帶的 cpio 歸檔解壓至 rootfs,釋放 /init、驅動模組、啟動腳本等。

階段三:真實根文件系統掛載與切換 (prepare_namespace → mount_root)

核心邏輯位於 init/do_mounts.c:

  1. 解析啟動參數:root=、rootfstype=、rootflags=、rootdelay=
  2. 等待設備就緒:輪詢 /dev/、udev 事件、rootdelay 超時
  3. 掛載真實根文件系統:sys_mount() 掛載至 /root 或 /sysroot
  4. 切換根目錄:sys_chdir("/root") + sys_mount(".", "/", NULL, MS_MOVE, NULL) + sys_chroot(".")
  5. 啟動 init 進程:run_init_process("/sbin/init")

關鍵數據結構


// fs/namespace.c
struct mount {
    struct hlist_node mnt_hash;
    struct mount *mnt_parent;    // 父掛載點
    struct dentry *mnt_mountpoint; // 掛載點目錄項
    struct vfsmount mnt;         // VFS 掛載結構
    ...
};

// include/linux/fs.h
struct vfsmount {
    struct dentry *mnt_root;     // 根目錄項
    struct super_block *mnt_sb;  // 超級塊
    int mnt_flags;
    ...
};

嵌入式系統特殊流程

對於 Flash 直啟系統(無 initramfs):

  1. Bootloader 將內核 + DTB 載入記憶體
  2. 內核解析 root=/dev/mtdblock2 rootfstype=jffs2
  3. MTD 驅動初始化,掛載 JFFS2/UBIFS 分區
  4. 直接切換根目錄,啟動 /sbin/init (通常為 BusyBox)

常見故障與診斷

現象可能原因診斷方法
Kernel panic: VFS: Unable to mount root fsroot= 參數錯誤、驅動缺失、initramfs 損壞檢查 bootloader 參數、確認驅動編譯內建 (*=y)
掛載後進入 initramfs shell真實根分區未就緒、UUID 不匹配、fstab 錯誤blkid 核對 UUID、檢查 /proc/cmdline
切換根失敗/sbin/init 缺失、動態鏈接庫缺失、SELinux 阻擋ls -l /root/sbin/init、ldd /root/sbin/init

調試技巧


# 1. 內核命令行加入調試參數
rd.debug rd.shell rd.break=pre-mount

# 2. 在 initramfs 中手動檢查
blkid
ls /dev/mapper/
cat /proc/cmdline
mount /dev/sda2 /mnt && ls /mnt

# 3. 重新生成 initramfs
dracut -f -v  # RHEL/CentOS/Fedora
update-initramfs -u -k all  # Debian/Ubuntu
mkinitcpio -P  # Arch
Copyright © Windows教程網 All Rights Reserved