【Linux】Linux根據文件路徑查找索引節點

根據文件路徑查找索引節點

操作系統的文件管理系統的主要作用就是,當用戶需要訪問一個文件時,系統可以通過用戶給出的文件路徑找到文件的索引節點,從而找到文件,並以文件對象的實例交付給用戶進程。下面就以系統調用open()爲例來說明文件的查找過程,以加深對文件系統的理解和認識。

系統調用open()的內核函數爲sys_open(),下圖描述了用戶進程調用系統調用open()的整個流程:

sys_open()系統調用打開或創建一個文件,成功後,返回該文件的文件描述符。下圖是sys_open()實現代碼中主要的函數調用關係圖:

sys_open()

從sys_open()的函數調用關係圖可以看出,sys_open()在做了一些簡單的參數檢驗後,就接着調用do_sys_open(),在該函數中:

  • get_unused_fd()得到一個可用的文件描述符。通過該函數,可知文件描述符實質上是進程打開文件列表中對應某個文件對象的索引值;
  • do_filp_open()打開文件,返回一個file對象,代表由該進程打開的一個文件。進程通過這樣的一個數據結構對物理文件進行讀寫操作;
  • fd_install()建立文件描述符與file對象的聯繫,以後進程對文件的讀寫都是通過操作該文件描述符而進行的。

do_filp_open()

do_filp_open()用於打開文件,返回一個file對象;而打開之前需要先找到該文件。

open_namei()用於根據文件路徑名查找文件,藉助一個持有路徑信息的數據結構nameidata而進行;

查找結束後,將填充有路徑信息的nameidata返回給接下來的函數nameidata_to_filp(),從而得到最終的file對象。當達到目的後,nameidata這個數據結構會馬上被釋放。

open_namei()

open_namei()用於查找一個文件。

path_lookup_open()實現文件的查找工作。要打開的文件若不存在,還需要一個新建的過程,則調用path_lookup_create(),後者和前者封裝的是同一個實際的路徑查找函數,只是參數不一樣,使它們在處理細節上有所偏差;

當以創建文件的方式打開文件時,即設置了O_CREAT標識時,需要創建一個新的索引節點,代表創建一個文件。由vfs_create()裏面的一句核心語句:

dir->i_op->create(dir, dentry, mode, nd);

它調用了具體的文件系統所提供的創建索引節點的方法。注意,這裏的索引節點的概念,還只是位於內存中。只有把它寫入磁盤纔是一個物理文件的真正創建;

path_to_nameidata()填充nameidata數據結構;

may_open()檢查是否可以打開該文件。

__path_lookup_intent_open()

不管是path_lookup_open()還是path_lookup_create(),最終都是調用__path_lookup_intent_open()來實現查找文件的功能。

查找時,會遍歷路徑的過程中,會逐層地將各個路徑組成部分解析成目錄項對象。如果此目錄項對象在目錄項緩存中,則直接從緩存中獲取;如果該目錄項在緩存中不存在,則進行一次實際的讀盤操作,從磁盤中讀取該目錄項所對應的索引節點。得到索引節點之後,則建立索引節點與該目錄項的聯繫。如此循環,直到找到目標文件對於的目錄項,也就找到了索引節點,而由索引節點找到對應的超級塊對象,就可知道該文件所在的文件系統的類型。

知道了文件系統的類型,VFS就能調用這個文件系統相對應的索引節點操作函數集來進行操作。

從磁盤中讀取該目錄項對應的索引節點;將引發VFS和實際的文件系統的一次交互。

 

進程創建時文件的複製與共享

之前講到:當一個進程系統調用fork()創建一個子進程時,fork()將調用內核函數do_fork()對父進程的進程控制塊進行復制,並將這個副本作爲子進程的控制塊。如果父進程有已經打開的文件,那麼子進程理所當然的按某種方式來繼承這些文件。爲此,do_fork()中有以下這樣的一段決定子進程在文件方面的繼承方式:

if(copy files(clone_flags, p))
        goto bad_fork_clcanup;
if(copy fs(clone_flags, p))
        goto bad_fork_clcanup_files;

其中,copy files()就是用來處理父進程已打開文件的函數。該函數根據參數clone_flags的設置位來決定子進程以何種方式來繼承父進程的打開文件。

  • 當clone_flags中的CLONE_FILES標誌爲0時,函數copy files()將複製父進程控制塊中已打開文件的整個控制結構。這是雖然父子進程使用同一組被打開文件,但各自在自己的文件上下文中工作;
  • 當clone_flags中的CLONE_FILES標誌非0時,函數copy files()只是簡單地把父進程控制塊中的files指針複製到子進程控制塊,同時將file_struct結構中的共享計數成員加1,以表明文件又多了一個使用者,即子進程只是通過指針與父進程共享同一組打開文件。

函數copy fs()只是用來處理fs_struct結構的,類似的,這個結構也是根據其參數clone_flags決定子進程是以複製還是共享方式繼承父進程的fs_struct結構的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章