1. 程式人生 > >[置頂] 《Linux啟動過程分析》核心掛載根檔案系統 http://blog.csdn.net/tankai19880619/article/details/12093239

[置頂] 《Linux啟動過程分析》核心掛載根檔案系統 http://blog.csdn.net/tankai19880619/article/details/12093239

說明:本文基於Linux2.6.29核心分析;其他核心版本僅供參考。

  前邊通過原始碼情景分析,看過了匯流排、裝置、驅動及其發現機制,Linux2.6核心udev裝置節點建立相關;對於檔案系統,一直望而生畏,但核心學習、這部分又不可能繞的過去。目前對VFS中使用的hash表還未做研究,它在dentry和vfsmount下查詢節點起關鍵作用;後邊在做分析。下邊將根檔案系統掛載過程做簡單分析:

一、rootfs的誕生

引子:

Linux一切皆檔案的提出:在Linux中,普通檔案、目錄、字元裝置、塊裝置、套接字等都以檔案被對待;他們具體的型別及其操作不同,但需要向上層提供統一的操作介面。

虛擬檔案系統VFS就是Linux核心中的一個軟體層,向上給使用者空間程式提供檔案系統操作介面;向下允許不同的檔案系統共存。所以,所有實際檔案系統都必須實現VFS的結構封裝。

矛盾的提出:

Linux系統中任何檔案系統的掛載必須滿足兩個條件:掛載點和檔案系統。

直接掛載nfs或flash檔案系統有如下兩個問題必須解決:

1.誰來提供掛載點?我們可以想象自己建立一個超級塊(包含目錄項和i節點),這時掛載點不是就有了嗎;很可惜,linux引入VFS(一切皆檔案,所有型別檔案系統必須提供一個VFS的軟體層、以向上層提供統一介面)後該問題不能這麼解決,因為掛載點必須關聯到檔案系統、也就是說掛載點必須屬於某個檔案系統。

2.怎樣訪問到nfs或flash上的檔案系統?我們可以說直接訪問裝置驅動讀取其上邊的檔案系統(裝置上的檔案系統是掛載在自己的根目錄),不就可以了嗎;別忘了還是Linux的VFS,裝置訪問也不例外。因為訪問裝置還是需要通過檔案系統來訪問它的掛載點,不能直接訪問(要滿足Linux的VFS架構,一切皆檔案)。

所以,一句話:rootfs之所以存在,是因為需要在VFS機制下給系統提供最原始的掛載點。

如此矛盾,需要我們引入一種特殊檔案系統:

1.它是系統自己建立並載入的第一個檔案系統;該檔案系統的掛載點就是它自己的根目錄項。

2.該檔案系統不能存在於nfs或flash上,因為如此將會陷入之前的矛盾。

rootfs的誕生:

上述問題需要我們建立具有如下三個特點的特殊檔案系統:

1.它是系統自己建立並載入的第一個檔案系統;

2.該檔案系統的掛載點就是它自己的根目錄項物件;

3.該檔案系統僅僅存在於記憶體中。

  由以上分析可以看出,rootfs是Linux的VFS(一切皆檔案,所有型別檔案系統必須提供一個VFS的軟體層、以向上層提供統一介面)存在的基石;二者關係密切。如果沒有VFS機制,rootfs也就沒有存在的必要;同樣,如果沒有rootfs、VFS機制也就不能實現。

  這就是兩者之間的真正關係,之前看網上什麼說法都有:有的只說關係密切,沒有指明具體關係;有的乾脆誤人子弟,說VFS就是rootfs。

  其實,VFS是一種機制、是Linux下每一種檔案系統(包括剛才說的rootfs,還有常見的ext3、yaffs等)都必須按照這個機制去實現的一種規範;而rootfs僅僅是符合VFS規範的而且又具有如上3個特點的一個檔案系統。

  VFS是Linux檔案系統實現必須遵循的一種機制,rootfs是一種具體實現的檔案系統、Linux下所有檔案系統的實現都必須符合VFS的機制(符合VFS的介面);這就是二者的真正關係。

以下分析基於Android模擬器Linux2.6.29核心:

二、相關資料結構

Linux核心中current指標作為全域性變數,使用非常廣泛;例如:程序上下文中獲取當前程序ID、任務排程,以及open等檔案系統呼叫中路徑搜尋等;首先介紹下current結構體:

各個平臺、各個核心版本中current的實現可能不同;但原理是一樣的。該指標一般定義在具體平臺的current.h標頭檔案中,型別為struct task_struct:

  1. #define current (get_current())
  2. staticinlinestruct task_struct *get_current(void)  

include/linux/sched.h

  1. struct task_struct {  
  2.   ......  
  3.   struct thread_info *thread_info;  
  4.   struct list_head tasks;  
  5.   pid_t pid;  
  6.   pid_t tgid;  
  7.   uid_t uid,euid,suid,fsuid;  
  8.   gid_t gid,egid,sgid,fsgid;  
  9.   struct fs_struct *fs;  //本節將大量使用這個
  10.   struct files_struct *files;  
  11.   ......  
  12. }  

1.檔案系統註冊

kernel/include/include/fs.h

  1. struct file_system_type {  
  2.   constchar *name; //檔案系統名字;如:rootfs及ext3等
  3.   int fs_flags;  
  4.   int (*get_sb) (struct file_system_type *, intconstchar *, void *, struct vfsmount *);  
  5.   //安裝/掛載檔案系統時,會呼叫;獲取超級塊。
  6.   void (*kill_sb) (struct super_block *);  
  7.   //解除安裝檔案系統時會呼叫。
  8.   struct module *owner;  
  9.   struct file_system_type * next;  
  10.   //指向下一個檔案系統型別。
  11.   struct list_head fs_supers;  
  12.   //同一個檔案系統型別中所有超級塊組成雙向連結串列。
  13.   struct lock_class_key s_lock_key;  
  14.   struct lock_class_key s_umount_key;  
  15.   struct lock_class_key i_lock_key;  
  16.   struct lock_class_key i_mutex_key;  
  17.   struct lock_class_key i_mutex_dir_key;  
  18.   struct lock_class_key i_alloc_sem_key;  
  19. };  

2.檔案系統掛載vfsmount(struct vfsmount):

  本質上,mount操作的過程就是新建一個vfsmount結構,然後將此結構和掛載點(目錄項物件)關聯。關聯之後,目錄查詢時就能沿著vfsmount掛載點一級級向下查詢檔案了。
對於每一個mount的檔案系統,都由一個vfsmount例項來表示。

kernel/include/linux/mount.h

  1. struct vfsmount {  
  2.   struct list_head mnt_hash; //核心通過雜湊表對vfsmount進行管理
  3.   struct vfsmount *mnt_parent;  //指向父檔案系統對應的vfsmount
  4.   struct dentry *mnt_mountpoint; //指向該檔案系統掛載點對應的目錄項物件dentry
  5.   struct dentry *mnt_root; //該檔案系統對應的裝置根目錄dentry
  6.   struct super_block *mnt_sb; //指向該檔案系統對應的超級塊
  7.   struct list_head mnt_mounts;   
  8.   struct list_head mnt_child;  //同一個父檔案系統中的所有子檔案系統通過該欄位連結成雙聯表
  9.   int mnt_flags;  
  10.   /* 4 bytes hole on 64bits arches */
  11.   constchar *mnt_devname;  /* Name of device e.g. /dev/dsk/hda1 */
  12.   struct list_head mnt_list;  //所有已掛載檔案系統的vfsmount結構通過該欄位連結在一起
  13.   struct list_head mnt_expire;  /* link in fs-specific expiry list */
  14.   struct list_head mnt_share;   /* circular list of shared mounts */
  15.   struct list_head mnt_slave_list;/* list of slave mounts */
  16.   struct list_head mnt_slave;   /* slave list entry */
  17.   struct vfsmount *mnt_master;  /* slave is on master->mnt_slave_list */
  18.   struct mnt_namespace *mnt_ns; /* containing namespace */
  19.   int mnt_id;           /* mount identifier */
  20.   int mnt_group_id;     /* peer group identifier */
  21.   /* 
  22.   * We put mnt_count & mnt_expiry_mark at the end of struct vfsmount 
  23.   * to let these frequently modified fields in a separate cache line 
  24.   * (so that reads of mnt_flags wont ping-pong on SMP machines) 
  25.   */
  26.   atomic_t mnt_count;  
  27.   int mnt_expiry_mark;      /* true if marked for expiry */
  28.   int mnt_pinned;  
  29.   int mnt_ghosts;  
  30.   /* 
  31.   * This value is not stable unless all of the mnt_writers[] spinlocks 
  32.   * are held, and all mnt_writer[]s on this mount have 0 as their ->count 
  33.   */
  34.   atomic_t __mnt_writers;  
  35. };  

3.超級塊(struct super_bloc):

kernel/include/linux/fs.h

  1. struct super_block {  
  2.   struct list_head  s_list;     /* Keep this first */
  3.   dev_t         s_dev;      /* search index; _not_ kdev_t */
  4.   unsigned long     s_blocksize;  
  5.   unsigned char     s_blocksize_bits;  
  6.   unsigned char     s_dirt;  
  7.   unsigned longlong    s_maxbytes; /* Max file size */
  8.   struct file_system_type   *s_type; //檔案系統型別
  9.   //(kernel/include/linux/fs.h,struct file_system_type)
  10.   conststruct super_operations *s_op;  
  11.   struct dquot_operations   *dq_op;  
  12.   struct quotactl_ops   *s_qcop;  
  13.   conststruct export_operations *s_export_op;  
  14.   unsigned long     s_flags;  
  15.   unsigned long     s_magic;  
  16.   struct dentry     *s_root;  //超級塊要指向目錄項物件
  17.   struct rw_semaphore   s_umount;  
  18.   struct mutex      s_lock;  
  19.   int           s_count;  
  20.   int           s_need_sync_fs;  
  21.   atomic_t      s_active;  
  22. #ifdef CONFIG_SECURITY
  23.   void                    *s_security;  
  24. 相關推薦

    [] 《Linux啟動過程分析核心掛載檔案系統 http://blog.csdn.net/tankai19880619/article/details/12093239

    說明:本文基於Linux2.6.29核心分析;其他核心版本僅供參考。   前邊通過原始碼情景分析,看過了匯流排、裝置、驅動及其發現機制,Linux2.6核心udev裝置節點建立相關;對於檔案系統,一直望而生畏,但核心學習、這部分又不可能繞的過去。目前對VFS中使用的hash表還未做研究,它在dent

    linux音頻alsa-uda134x驅動文檔閱讀之一轉自http://blog.csdn.net/wantianpei/article/details/7817293

    發出 hand 增加 int chang == 音頻 set device 前言 目前,linux系統常用的音頻驅動有兩種形式:alsa oss alsa:現在是linux下音頻驅動的主要形式,與簡單的oss兼容。oss:過去的形式而我們板子上的uda1341用的就是als

    Linux串列埠程式設計教程(三)——串列埠程式設計詳(原始碼)解:http://blog.csdn.net/u011192270/article/details/48174353 Linux下的串列埠程式設計(二)----(圖文並茂,講解深刻)http://blog.csdn.net/w28252

    Linux串列埠程式設計教程(三)——串列埠程式設計詳(原始碼)解:http://blog.csdn.net/u011192270/article/details/48174353 Linux下的串列埠程式設計(二)----(圖文並茂,講解深刻)http://blog.csdn.ne

    Hibernate物件三種狀態詳細分析(轉自http://blog.csdn.net/redarmy_chen/article/details/7069482)

    在hibernate中有三種狀態:瞬時態(Transient)、 持久態(Persistent)、脫管態(Detached)。處於持久態的物件也稱為PO(Persistence Object),瞬時物件和脫管物件也稱為VO(Value Object)。通過自己在網上的搜尋,

    Linux啟動過程分析核心掛載檔案系統

    說明:本文基於Linux2.6.29核心分析;其他核心版本僅供參考。   前邊通過原始碼情景分析,看過了匯流排、裝置、驅動及其發現機制,Linux2.6核心udev裝置節點建立相關;對於檔案系統,一直望而生畏,但核心學習、這部分又不可能繞的過去。目前對VFS中使用的has

    u-boot通過nfs從伺服器下載核心,並且啟動核心,掛載檔案系統的方法

    http://www.linuxidc.com/Linux/2013-08/89154.htm http://blog.csdn.net/sinat_31500569/article/details/53120530 參考連結 首先要在電腦上安裝nfs伺服器 1.執行命令

    TBSchedule原始碼學習筆記-啟動過程 轉自https://blog.csdn.net/weiythi/article/details/78742651

    TBSchedule基本概念及原理 概念介紹 TBSchedule是一個支援分散式的排程框架,能讓一種批量任務或者不斷變化的任務,被動態的分配到多個主機的JVM中,不同的執行緒組中並行執行。基於ZooKeeper的純Java實現,由Alibaba開源。 程式碼實

    X86架構下Linux啟動過程分析

    重要 ack csdn 檢查 point article span 註意 eap 1、X86架構下的從開機到Start_kernel啟動的整體過程 這個過程簡要概述為: 開機——>BIOS——>GRUB/LILO——>Linux Kernel

    Linux啟動過程分析(十一)---da850_set_emif_clk_rate()函式分析

    /* * 雖然在bootloader中已經把emif的時鐘速率設定為允許的值,但是核心需要重新 *設定以使它支援平臺請求的特定時鐘速率。 */ ret = da850_set_emif_clk_rate()-> static __init int da850_set_emif_c

    Linux啟動過程分析(十一)-----customize_machine(註冊開發板相關硬體資訊)

    初始化過程進行到下面這一步: c0599c48 t __initcall_customize_machine3 呼叫的函式及其位置如下: Setup.c (arch\arm\kernel):arch_initcall(customize_machine) static int __in

    Linux 啟動過程分析 (SysV init啟動模式)

          本篇主要分析傳統的Linux啟動方式  SysV init啟動模式。(注:當前Linux發行版大多采用Systemd 啟動模式來替代傳統的 SysV init啟動模式。)    &nbs

    Linux 啟動過程分析

    (點選上方公眾號,可快速關注)編譯: linux中國 /  jessie-pang  英文: A

    Linux啟動過程分析》之區別Initramfs與initrd

      之前《Linux啟動過程分析》核心掛載根檔案系統一文,分析的rootfs、其實就是解決了Linux的VFS架構下初始掛載點的建立問題。   下邊說的Initramfs/initrd則是填充(僅僅是釋放檔案到rootfs根目錄)/擴充(通過掛載其他檔案系統型別到rootf

    從NFS啟動Linux掛載檔案系統

    要搞嵌入式NFS確實必不可少,否則每次都要重啟煩都煩死。這裡總結在NFS建立過程中遇到的幾個問題。 下面記錄幾個遇到的問題 VFS: Cannot open root device “

    linux 核心啟動流程(涉及到檔案系統的問題)

    Linux核心啟動及檔案系統載入過程 當u-boot開始執行bootcmd命令。就進入Linux核心啟動階段,與u-boot類似,普通Linux核心的啟動過程也能夠分為兩個階段,但針對壓縮了的核心如uImage就要包含核心自解壓過程了。本文以linux-2.6.37版原始

    Beaglebone Black——理論篇beaglebone black啟動——從串列埠獲得SPL、U-BOOT,TFTP伺服器獲得核心,NFS伺服器掛載檔案系統

              一般來講啟動一個系統所需的bootloader(SPL/MLO、u-boot.img)和根檔案系統(/boot下包含核心zImage)要麼是放在NAND Flash,或者是SD卡,或者是eMMC,或者是USB中,那麼還有一種方式,就是所需要的這些檔案全部

    怎樣從網路上核心檔案系統啟動開發板

    首先在ubuntu虛擬機器上要有nfs伺服器 1.啟動開發板uboot,輸入 下面的命令 set bootargs console=ttySAC0 root=/dev/nfs nfsroot=192.168.1.19:/work/nfs_root/tmp/fs_mini

    移植u-boot-2011.03到S3C2440(utu2440)的方法與步驟###8. u-boot引導啟動nand flash中核心檔案系統cramfs和使用者檔案系統yaffs2支援

    rivers/rtc/hctosys.c: unable to open rtc device (rtc0)uncorrectable error : <3>uncorrectable error : <3>end_request: I/O error, dev mtdblock2, 

    嵌入式linux 核心檔案系統燒寫方式簡介

    總體來說,嵌入式Linux核心和根檔案的引導與PC機差不多。嵌入式linux核心和根檔案系統可以存放在各種可能的儲存裝置中,一般情況下我們將核心和根檔案系統直接燒入到Flash中(包括NOR和NAND flash),這種方法的缺點是在核心和根檔案系統出現修改時我們就不得不得

    uboot、核心檔案系統啟動流程

      0.設定cpu為svc模式,關中斷  1. 為核心的解壓做準備(記憶體,中斷等等)  2.核心自解壓 (vmlinux.lds)  3.跳轉到入口地址執行(head.S--->main.c)start_kernel執行核心  4.硬體的初始化(初始mm  mmu  中斷(request_irq),軟