自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

深入理解Linux文件系統(tǒng)之文件系統(tǒng)掛載(上)

系統(tǒng) Linux
Linux系統(tǒng)中我們經(jīng)常將一個塊設(shè)備上的文件系統(tǒng)掛載到某個目錄下才能訪問這個文件系統(tǒng)下的文件,但是你有沒有思考過:為什么塊設(shè)備掛載之后才能訪問文件?掛載文件系統(tǒng)Linux內(nèi)核到底為我們做了哪些事情?

[[402508]]

本文轉(zhuǎn)載自微信公眾號「Linux內(nèi)核遠航者」,作者Linux內(nèi)核遠航者。轉(zhuǎn)載本文請聯(lián)系Linux內(nèi)核遠航者公眾號。

1.開場白

  • 環(huán)境:

處理器架構(gòu):arm64

內(nèi)核源碼:linux-5.11

ubuntu版本:20.04.1

代碼閱讀工具:vim+ctags+cscope

我們知道,Linux系統(tǒng)中我們經(jīng)常將一個塊設(shè)備上的文件系統(tǒng)掛載到某個目錄下才能訪問這個文件系統(tǒng)下的文件,但是你有沒有思考過:為什么塊設(shè)備掛載之后才能訪問文件?掛載文件系統(tǒng)Linux內(nèi)核到底為我們做了哪些事情?是否可以不將文件系統(tǒng)掛載到具體的目錄下也能訪問?下面,本文將詳細(xì)講解Linxu系統(tǒng)中,文件系統(tǒng)掛載的奧秘。

注:本文主要講解文件系統(tǒng)掛載核心邏輯,暫不涉及掛載命名空間和綁定掛載等內(nèi)容(后面的內(nèi)容可能會涉及),且以ext2磁盤文件系統(tǒng)為例講解掛載。本專題文章分為上下兩篇,上篇主要介紹掛載全貌以及具體文件系統(tǒng)的掛載方法,下篇介紹如何通過掛載實例關(guān)聯(lián)掛載點和超級塊。

2. vfs 幾個重要對象

在這里我們不介紹整個IO棧,只說明和文件系統(tǒng)相關(guān)的vfs和具體文件系統(tǒng)層。我們知道在Linux中通過虛擬文件系統(tǒng)層VFS統(tǒng)一所有具體的文件系統(tǒng),提取所有具體文件系統(tǒng)的共性,屏蔽具體文件系統(tǒng)的差異。VFS既是向下的接口(所有文件系統(tǒng)都必須實現(xiàn)該接口),同時也是向上的接口(用戶進程通過系統(tǒng)調(diào)用最終能夠訪問文件系統(tǒng)功能)。

下面我們來看下,vfs中幾個比較重要的結(jié)構(gòu)體對象:

2.1 file_system_type

這個結(jié)構(gòu)來描述一種文件系統(tǒng)類型,一般具體文件系統(tǒng)會定義這個結(jié)構(gòu),然后注冊到系統(tǒng)中;定義了具體文件系統(tǒng)的掛載和卸載方法,文件系統(tǒng)掛載時調(diào)用其掛載方法構(gòu)建超級塊、跟dentry等實例。

文件系統(tǒng)分為以下幾種:

1)磁盤文件系統(tǒng)

文件在非易失性存儲介質(zhì)上(如硬盤,flash),掉電文件不丟失。

如ext2,ext4,xfs

2)內(nèi)存文件系統(tǒng)

文件在內(nèi)存上,掉電丟失。

如tmpfs

3)偽文件系統(tǒng)

是假的文件系統(tǒng),是利用虛擬文件系統(tǒng)的接口(可以對用戶可見如proc、sysfs,也可以對用戶不可見內(nèi)核可見如sockfs,bdev)。

如proc,sysfs,sockfs,bdev

4)網(wǎng)絡(luò)文件系統(tǒng)

這種文件系統(tǒng)允許訪問另一臺計算機上的數(shù)據(jù),該計算機通過網(wǎng)絡(luò)連接到本地計算機。

如nfs文件系統(tǒng)

結(jié)構(gòu)體定義源碼路徑:include/linux/fs.h +2226

2.2 super_block

超級塊,用于描述塊設(shè)備上的一個文件系統(tǒng)總體信息(如文件塊大小,最大文件大小,文件系統(tǒng)魔數(shù)等),一個塊設(shè)備上的文件系統(tǒng)可以被掛載多次,但是內(nèi)存中只能有個super_block來描述(至少對于磁盤文件系統(tǒng)來說)。

結(jié)構(gòu)體定義源碼路徑:include/linux/fs.h +1414

2.3 mount

掛載描述符,用于建立超級塊和掛載點等之間的聯(lián)系,描述文件系統(tǒng)的一次掛載,一個塊設(shè)備上的文件系統(tǒng)可以被掛載多次,每次掛載內(nèi)存中有一個mount對象描述。

結(jié)構(gòu)體定義源碼路徑:fs/mount.h +39

2.4 inode

索引節(jié)點對象,描述磁盤上的一個文件元數(shù)據(jù)(文件屬性、位置等),有些文件系統(tǒng)需要從塊設(shè)備上讀取磁盤上的索引節(jié)點,然后在內(nèi)存中創(chuàng)建vfs的索引節(jié)點對象,一般在文件第一次打開時創(chuàng)建。

結(jié)構(gòu)體定義源碼路徑:include/linux/fs.h +610

2.5 dentry

目錄項對象,用于描述文件的層次結(jié)構(gòu),從而構(gòu)建文件系統(tǒng)的目錄樹,文件系統(tǒng)將目錄當(dāng)作文件,目錄的數(shù)據(jù)由目錄項組成,而每個目錄項存儲一個目錄或文件的名稱和索引節(jié)點號等內(nèi)容。每當(dāng)進程訪問一個目錄項就會在內(nèi)存中創(chuàng)建目錄項對象(如ext2路徑名查找中,通過查找父目錄數(shù)據(jù)塊的目錄項,找到對應(yīng)文件/目錄的名稱,獲得inode號來找到對應(yīng)inode)。

結(jié)構(gòu)體定義源碼路徑:include/linux/dcache.h +90

2.6 file

文件對象,描述進程打開的文件,當(dāng)進程打開文件時會創(chuàng)建文件對象加入到進程的文件打開表,通過文件描述符來索引文件對象,后面讀寫等操作都通過文件描述符進行(一個文件可以被多個進程打開,會由多個文件對象加入到各個進程的文件打開表,但是inode只有一個)。

結(jié)構(gòu)體定義源碼路徑:include/linux/fs.h +915

3. 掛載總體流程

3.1系統(tǒng)調(diào)用處理

用戶執(zhí)行掛載是通過系統(tǒng)調(diào)用路徑進入內(nèi)核處理,拷貝用戶空間傳遞參數(shù)到內(nèi)核,掛載委托do_mount。

//fs/namespace.c

SYSCALL_DEFINE5(mount

參數(shù):

dev_name 要掛載的塊設(shè)備

dir_name 掛載點目錄

type 文件系統(tǒng)類型名

flags 掛載標(biāo)志

data 掛載選項

-> kernel_type = copy_mount_string(type); //拷貝文件系統(tǒng)類型名到內(nèi)核空間

-> kernel_dev = copy_mount_string(dev_name) //拷貝塊設(shè)備路徑名到內(nèi)核空間 -> options = copy_mount_options(data) //拷貝掛載選項到內(nèi)核空間

-> do_mount(kernel_dev, dir_name, kernel_type, flags, options) //掛載委托do_mount

3.2 掛載點路徑查找

掛載點路徑查找,掛載委托path_mount

do_mount

-> user_path_at(AT_FDCWD, dir_name, LOOKUP_FOLLOW, &path) //掛載點路徑查找 查找掛載點目錄的 vfsmount和dentry 存放在 path

-> path_mount(dev_name, &path, type_page, flags, data_page) //掛載委托path_mount

3.3 參數(shù)合法性檢查

參數(shù)合法性檢查, 新掛載委托do_new_mount

path_mount

-> 參數(shù)合法性檢查

-> 根據(jù)掛載標(biāo)志調(diào)用不同函數(shù)處理 這里講解是默認(rèn) do_new_mount

3.4 調(diào)用具體文件系統(tǒng)掛載方法

  1. do_new_mount 
  2. -> type = get_fs_type(fstype)  //根據(jù)傳遞的文件系統(tǒng)名  查找已經(jīng)注冊的文件系統(tǒng)類型 
  3. -> fc = fs_context_for_mount(type, sb_flags) //為掛載分配文件系統(tǒng)上下文 struct fs_context 
  4.  -> alloc_fs_context 
  5.    -> 分配fs_context fc = kzalloc(sizeof(struct fs_context), GFP_KERNEL) 
  6.    ->  設(shè)置 ...  
  7.    ->  fc->fs_type     = get_filesystem(fs_type);  //賦值相應(yīng)的文件系統(tǒng)類型 
  8.    ->  init_fs_context = **fc->fs_type->init_fs_context**;  //新內(nèi)核使用fs_type->init_fs_context接口  來初始化文件系統(tǒng)上下文 
  9.     if (!init_fs_context)   //init_fs_context回掉 主要用于初始化 
  10.         init_fs_context = **legacy_init_fs_context**;    //沒有 fs_type->init_fs_context接口  
  11.    -> init_fs_context(fc)  //初始化文件系統(tǒng)上下文 (初始化一些回掉函數(shù),供后續(xù)使用) 

來看下文件系統(tǒng)類型沒有實現(xiàn)init_fs_context接口的情況:

  1. //fs/fs_context.c 
  2. init_fs_context = legacy_init_fs_context 
  3. ->  fc->ops = &legacy_fs_context_ops   //設(shè)置文件系統(tǒng)上下午操作 
  4.                     ->.get_tree               = legacy_get_tree  //操作方法的get_tree用于  讀取磁盤超級塊并在內(nèi)存創(chuàng)建超級塊,創(chuàng)建跟inode, 跟dentry 
  5.                         -> root = fc->fs_type->mount(fc->fs_type, fc->sb_flags, 
  6.                                          ¦     fc->source, ctx->legacy_data)  //調(diào)用文件系統(tǒng)類型的mount方法來讀取并創(chuàng)建超級塊 
  7.                         -> fc->root = root  //賦值創(chuàng)建好的跟dentry 
  8.  
  9.  
  10. 有一些文件系統(tǒng)使用原來的接口(fs_type.mount  = xxx_mount):如ext2,ext4等 
  11. 有一些文件系統(tǒng)使用新的接口(fs_type.init_fs_context =  xxx_init_fs_context):xfs, proc, sys 
  12.  
  13. 無論使用哪一種,都會在xxx_init_fs_contex中實現(xiàn) fc->ops =  &xxx_context_ops 接口,后面會看的都會調(diào)用fc->ops.get_tree 來讀取創(chuàng)建超級塊實例 

繼續(xù)往下走:

  1. do_new_mount 
  2.     -> ... 
  3.     ->  fc = fs_context_for_mount(type, sb_flags) //分配 賦值文件系統(tǒng)上下文 
  4.     -> parse_monolithic_mount_data(fc, data)  //調(diào)用fc->ops->parse_monolithic  解析掛載選項 
  5.     -> mount_capable(fc) //檢查是否有掛載權(quán)限 
  6.     -> vfs_get_tree(fc)  //fs/super.c 掛載重點   調(diào)用fc->ops->get_tree(fc) 讀取創(chuàng)建超級塊實例 
  7.     ... 

3.5 掛載實例添加到全局文件系統(tǒng)樹

  1. do_new_mount 
  2.     ... 
  3.     ->  do_new_mount_fc(fc, path, mnt_flags)  //創(chuàng)建mount實例 關(guān)聯(lián)掛載點和超級塊  添加到命名空間的掛載樹中 

下面主要看下vfs_get_tree和do_new_mount_fc:

4.具體文件系統(tǒng)掛載方法

1)vfs_get_tree

  1. //以ext2文件系統(tǒng)為例 
  2. vfs_get_tree  //fs/namespace.c 
  3. -> fc->ops->get_tree(fc) 
  4.  -> legacy_get_tree   //上面分析過 fs_type->init_fs_context == NULL使用舊的接口(ext2為NULL
  5.   ->fc->fs_type->mount 
  6.    -> ext2_mount  //fs/ext2/super.c  調(diào)用到具體文件系統(tǒng)的掛載方法 

來看下ext2對掛載的處理:

啟動階段初始化->

  1. //fs/ext2/super.c 
  2. module_init(init_ext2_fs) 
  3. init_ext2_fs 
  4.  ->init_inodecache  //創(chuàng)建ext2_inode_cache 對象緩存 
  5.  ->register_filesystem(&ext2_fs_type) //注冊ext2的文件系統(tǒng)類型 
  6.  
  7.  
  8. static struct file_system_type ext2_fs_type = { 
  9.         .owner          = THIS_MODULE, 
  10.         .name           = "ext2"
  11.         .mount          = ext2_mount,   //掛載時調(diào)用  用于讀取創(chuàng)建超級塊實例 
  12.         .kill_sb        = kill_block_super,  //卸載時調(diào)用  用于釋放超級塊 
  13.         .fs_flags       = FS_REQUIRES_DEV,  //文件系統(tǒng)標(biāo)志為  請求塊設(shè)備,文件系統(tǒng)在塊設(shè)備上 
  14. }; 

掛載時調(diào)用->

  1. // fs/ext2/super.c 
  2. static struct dentry *ext2_mount(struct file_system_type *fs_type,            
  3.         int flags, const char *dev_name, void *data) 
  4.         return mount_bdev(fs_type, flags, dev_name, data, ext2_fill_super); 

ext2_mount通過調(diào)用mount_bdev來執(zhí)行實際文件系統(tǒng)的掛載工作,ext2_fill_super的一個函數(shù)指針作為參數(shù)傳遞給get_sb_bdev。該函數(shù)用于填充一個超級塊對象,如果內(nèi)存中沒有適當(dāng)?shù)某墘K對象,數(shù)據(jù)就必須從硬盤讀取。

mount_bdev是個公用的函數(shù),一般磁盤文件系統(tǒng)會使用它來根據(jù)具體文件系統(tǒng)的fill_super方法來讀取磁盤上的超級塊并在創(chuàng)建內(nèi)存超級塊。

我們來看下mount_bdev的實現(xiàn)(**它執(zhí)行完成之后會創(chuàng)建vfs的三大數(shù)據(jù)結(jié)構(gòu) super_block、根inode和根dentry **):

2)mount_bdev源碼分析

  1. //fs/super.c 
  2. mount_bdev 
  3. ->bdev = blkdev_get_by_path(dev_name, mode, fs_type)  //通過要掛載的塊設(shè)備路徑名 獲得它的塊設(shè)備描述符block_device(會涉及到路徑名查找和通過設(shè)備號在bdev文件系統(tǒng)查找block_device,block_device是添加塊設(shè)備到系統(tǒng)時創(chuàng)建的) 
  4. -> s = sget(fs_type, test_bdev_super, set_bdev_super, flags | sb_NOSEC,    
  5.          ¦bdev);  //查找或創(chuàng)建vfs的超級塊  (會首先在文件系統(tǒng)類型的fs_supers鏈表查找是否已經(jīng)讀取過指定的超級塊,會對比每個超級塊的s_bdev塊設(shè)備描述符,沒有創(chuàng)建一個) 
  6. ->  if (s->s_root) {   //超級塊的根dentry是否被賦值? 
  7.   ... 
  8.  } else {   //沒有賦值說明時新創(chuàng)建的sb 
  9.   ... 
  10.   -> sb_set_blocksize(s, block_size(bdev)) //根據(jù)塊設(shè)備描述符設(shè)置文件系統(tǒng)塊大小 
  11.   ->  fill_super(s, data, flags & sb_SILENT ? 1 : 0)  //調(diào)用傳遞的具體文件系統(tǒng)的填充超級塊方法讀取填充超級塊等 如ext2_fill_super 
  12.   ->  bdev->bd_super = s  //塊設(shè)備bd_super指向sb 
  13.  } 
  14. -> return dget(s->s_root)  //返回文件系統(tǒng)的根dentry 

可以看到mount_bdev主要是:1.根據(jù)要掛載的塊設(shè)備文件名查找到對應(yīng)的塊設(shè)備描述符(內(nèi)核后面操作塊設(shè)備都是使用塊設(shè)備描述符);2.首先在文件系統(tǒng)類型的fs_supers鏈表查找是否已經(jīng)讀取過指定的vfs超級塊,會對比每個超級塊的s_bdev塊設(shè)備描述符,沒有創(chuàng)建一個vfs超級塊; 3.新創(chuàng)建的vfs超級塊,需要調(diào)用具體文件系統(tǒng)的fill_super方法來讀取填充超級塊。

那么下面主要集中在具體文件系統(tǒng)的fill_super方法,這里是ext2_fill_super:

分析重點代碼如下:

3)ext2_fill_super源碼分析

  1. //fs/ext2/super.c 
  2. static int ext2_fill_super(struct super_block *sb, void *data, int silent)                
  3. {                                                                                                           
  4.         struct buffer_head * bh;    //緩沖區(qū)頭  記錄讀取的磁盤超級塊                                                      
  5.         struct ext2_sb_info * sbi;   //內(nèi)存的ext2 超級塊信息                                                     
  6.         struct ext2_super_block * es;  //磁盤上的  超級塊信息                                                
  7.            ... 
  8.                                                          
  9.         sbi = kzalloc(sizeof(*sbi), GFP_KERNEL);     //分配 內(nèi)存的ext2 超級塊信息結(jié)構(gòu)                                    
  10.         if (!sbi)                                                                         
  11.                 goto failed;                                                              
  12.                                                                                           
  13.          ...                                                   
  14.         sb->s_fs_info = sbi;     //vfs的超級塊 的s_fs_info指向內(nèi)存的ext2 超級塊信息結(jié)構(gòu)                                                    
  15.         sbi->s_sb_block = sb_block;                                                       
  16.                                                         
  17.       if (!(bh = sb_bread(sb, logic_sb_block))) {  // 讀取磁盤上的超級塊到內(nèi)存的 使用buffer_head關(guān)聯(lián)內(nèi)存緩沖區(qū)和磁盤扇區(qū)                                    
  18.               ext2_msg(sb, KERN_ERR, "error: unable to read superblock");                  
  19.               goto failed_sbi;                                                             
  20.       }                                                                                    
  21.                     
  22.       es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);  //轉(zhuǎn)換為struct ext2_super_block 結(jié)構(gòu)                  
  23.       sbi->s_es = es; //  內(nèi)存的ext2 超級塊信息結(jié)構(gòu)的 s_es指向真正的ext2磁盤超級塊信息結(jié)構(gòu)                                                                  
  24.       sb->s_magic = le16_to_cpu(es->s_magic); //獲得文件系統(tǒng)魔數(shù)   ext2為0xEF53                                         
  25.                                                                                            
  26.       if (sb->s_magic != EXT2_SUPER_MAGIC)    //驗證 魔數(shù)是否正確                                            
  27.               goto cantfind_ext2; 
  28.  
  29.     blocksize = BLOCK_SIZE << le32_to_cpu(sbi->s_es->s_log_block_size); //獲得磁盤讀取的塊大小    
  30.  
  31.                                                                                            
  32.         /* If the blocksize doesn't match, re-read the thing.. */                          
  33.         if (sb->s_blocksize != blocksize) {  //塊大小不匹配 需要重新讀取超級塊                                               
  34.                 brelse(bh);                                                                
  35.                                                                                            
  36.                 if (!sb_set_blocksize(sb, blocksize)) {                                    
  37.                         ext2_msg(sb, KERN_ERR,                                             
  38.                                 "error: bad blocksize %d", blocksize);                     
  39.                         goto failed_sbi;                                                   
  40.                 }                                                                          
  41.                                                                                            
  42.                 logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;                        
  43.                 offset = (sb_block*BLOCK_SIZE) % blocksize;                                
  44.                 bh = sb_bread(sb, logic_sb_block); //重新 讀取超級塊                                        
  45.                 if(!bh) {                                                                  
  46.                         ext2_msg(sb, KERN_ERR, "error: couldn't read"                      
  47.                                 "superblock on 2nd try");                                  
  48.                         goto failed_sbi;                                                   
  49.                 }                                                                          
  50.                 es = (struct ext2_super_block *) (((char *)bh->b_data) + offset);          
  51.                 sbi->s_es = es;                                                            
  52.                 if (es->s_magic != cpu_to_le16(EXT2_SUPER_MAGIC)) {                        
  53.                         ext2_msg(sb, KERN_ERR, "error: magic mismatch");                   
  54.                         goto failed_mount;                                                 
  55.                 }                                                                          
  56.         }                                                                                  
  57.                                                                                            
  58.         sb->s_maxbytes = ext2_max_size(sb->s_blocksize_bits);  //設(shè)置最大文件大小                             
  59.         ...                                                            
  60.         
  61.        //讀取或設(shè)置 inode大小和第一個inode號                                                                         
  62.        if (le32_to_cpu(es->s_rev_level) == EXT2_GOOD_OLD_REV) {                    
  63.                sbi->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;                       
  64.                sbi->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;                         
  65.        } else {                                                                    
  66.                sbi->s_inode_size = le16_to_cpu(es->s_inode_size);                  
  67.                sbi->s_first_ino = le32_to_cpu(es->s_first_ino);                    
  68.               ...                           
  69.        }                                                                           
  70.                                                                                    
  71.       ...              
  72.                                                                                    
  73.        sbi->s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);    //賦值每個塊組 塊個數(shù)           
  74.        sbi->s_frags_per_group = le32_to_cpu(es->s_frags_per_group);                
  75.        sbi->s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);  //賦值每個塊組 inode個數(shù)              
  76.                                                                                    
  77.        sbi->s_inodes_per_block = sb->s_blocksize / EXT2_INODE_SIZE(sb);    //賦值每個塊 inode個數(shù)        
  78.        ...                      
  79.        sbi->s_desc_per_block = sb->s_blocksize /                                   
  80.                                        sizeof (struct ext2_group_desc);    //賦值每個塊 塊組描述符個數(shù)      
  81.        sbi->s_sbh = bh;  //賦值讀取的超級塊緩沖區(qū)                                                           
  82.        sbi->s_mount_state = le16_to_cpu(es->s_state);    //賦值掛載狀態(tài)                            
  83.      ...                                    
  84.                                                                                 
  85.     if (sb->s_magic != EXT2_SUPER_MAGIC)                                        
  86.             goto cantfind_ext2;                                                 
  87.     
  88.    //一些合法性檢查 
  89.      ...     
  90.      
  91.   //計算塊組描述符 個數(shù) 
  92.   sbi->s_groups_count = ((le32_to_cpu(es->s_blocks_count) -                
  93.                           le32_to_cpu(es->s_first_data_block) - 1)         
  94.                                   / EXT2_BLOCKS_PER_GROUP(sb)) + 1;        
  95.   db_count = (sbi->s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) /         
  96.           ¦  EXT2_DESC_PER_BLOCK(sb);                                      
  97.   sbi->s_group_desc = kmalloc_array(db_count,                              
  98.                                   ¦  sizeof(struct buffer_head *),         
  99.                                   ¦  GFP_KERNEL);  //分配塊組描述符 bh數(shù)組                        
  100.     
  101.      
  102.     for (i = 0; i < db_count; i++) {      //讀取塊組描述符                                  
  103.           block = descriptor_loc(sb, logic_sb_block, i);                 
  104.           sbi->s_group_desc[i] = sb_bread(sb, block);   //讀取的 塊組描述符緩沖區(qū)保存 到sbi->s_group_desc[i]               
  105.           if (!sbi->s_group_desc[i]) {                                   
  106.                   for (j = 0; j < i; j++)                                
  107.                           brelse (sbi->s_group_desc[j]);                 
  108.                   ext2_msg(sb, KERN_ERR,                                 
  109.                           "error: unable to read group descriptors");    
  110.                   goto failed_mount_group_desc;                          
  111.           }                                                              
  112.   }                                                                      
  113.  
  114.                                                                      
  115.   sb->s_op = &ext2_sops;   //賦值超級塊操作 
  116.   ... 
  117.  root = ext2_iget(sb, EXT2_ROOT_INO); //讀取根inode  (ext2 根根inode號為2)  
  118.  
  119.  sb->s_root = d_make_root(root);  //創(chuàng)建根dentry  并建立根inode和根dentry關(guān)系 
  120.  ext2_write_super(sb);  //同步超級塊信息到磁盤 如掛載時間等 

可以看到ext2_fill_super主要工作為:

1.讀取磁盤上的超級塊;

2.填充并關(guān)聯(lián)vfs超級塊;

3.讀取塊組描述符;

4.讀取磁盤根inode并建立vfs 根inode;

5.創(chuàng)建根dentry關(guān)聯(lián)到根inode。

下面給出ext2_fill_super之后ext2相關(guān)圖解:

 

有了這些信息,雖然能夠獲得塊設(shè)備上的文件系統(tǒng)全貌,內(nèi)核也能通過已經(jīng)建立好的block_device等結(jié)構(gòu)訪問塊設(shè)備,但是用戶進程不能真正意義上訪問到,用戶一般會通過open打開一個文件路徑來訪問文件,但是現(xiàn)在并沒有關(guān)聯(lián)掛載目錄的路徑,需要將文件系統(tǒng)關(guān)聯(lián)到掛載點,以至于路徑名查找的時候查找到掛載點后,在轉(zhuǎn)向文件系統(tǒng)的根目錄,而這需要通過do_new_mount_fc來去關(guān)聯(lián)并加入全局的文件系統(tǒng)樹中,下一篇我們將做詳細(xì)講解。

 

責(zé)任編輯:武曉燕 來源: Linux內(nèi)核遠航者
相關(guān)推薦

2018-09-12 15:48:35

ext4Linux文件系統(tǒng)

2023-09-27 23:19:04

Linuxmount

2020-10-12 17:40:44

lsofLinux虛擬文件

2022-04-21 14:09:17

lsofLinux虛擬文件

2011-01-11 10:29:35

Linux文件

2021-05-27 07:12:20

Ext2路徑Linux

2020-07-22 14:53:06

Linux系統(tǒng)虛擬文件

2011-01-13 14:10:30

Linux文件系統(tǒng)

2009-12-22 13:15:59

Linux ueven

2022-04-15 08:00:00

FUSE開發(fā)Android

2010-01-26 13:41:50

Android文件系統(tǒng)

2021-06-06 16:55:22

Linux文件系統(tǒng)

2021-04-12 05:44:44

Linux文件系統(tǒng)

2010-03-02 13:27:17

LinuxXFS文件系

2018-08-24 10:10:25

Linux文件系統(tǒng)技術(shù)

2019-09-20 10:04:45

Linux系統(tǒng)虛擬文件

2010-03-02 15:09:26

Linux mount

2013-10-09 11:07:31

日志文件系統(tǒng)

2023-12-06 09:32:35

Linux系統(tǒng)

2017-04-25 15:50:02

sparse傳輸處理
點贊
收藏

51CTO技術(shù)棧公眾號