open()在Linux內核的基本實現

1.基本說明

在用戶態使用open()時,必須向該函數傳入文件路徑和打開權限。這兩個參數傳入內核後,內核首先檢查這個文件路徑存在的合法性,同時還需檢查使用者是否有合法權限打開該文件。如果一切順利,那麼內核將對訪問該文件的進程創建一個file結構。

在用戶態,通常open()在操作成功時返回的是一個非負整數,即所謂的文件描述符(fd,file deor);並且,用戶態後續對文件的讀寫操作等都是通過fd來完成的。由此可見fd與file結構在內核中有一定的關聯。

具體的,內核使用進程描述符task_struct來描述一個進程,而該進程所有已打開文件對應的file結構將形成一個數組files(其爲files_struct結構),內核向用戶返回的fd便是該數組中具體file結構的索引。默認情況下,每個進程創建後都已打開了標準輸入文件、標準輸出文件、標準錯誤文件,因此他們的文件描述符依次爲0、1和2。

2.函數分析2.1.do_sys_open

明白了上述原理,那麼open系統調用在內核中的基本實現過程就很清晰。根據系統調用入口函數的命名規則,open系統調用的入口函數應該爲sys_open。不過,目前內核統一使用SYSCALL_DEFINEn宏來描述系統調用入口函數,因此可以在open.c文件中找到該入口函數,具體如下所示:

1 SYSCALL_DEFINE3(open, constchar__user *, filename, int, flags, int, mode);

該函數內部直接調用了do_sys_open函數,具體聲明如下:

1 longdo_sys_open(intdfd, constchar__user *filename, intflags, intmode);

這個函數的參數基本上與open系統調用的參數一致。

該函數可以簡單概括open系統調用的功能:

1.通過build_open_flags()將用戶態的flags和mode轉換成對應的內核態標誌;

2.由於filename是用戶態的內存緩衝區(使用了__user修飾),因此通過getname()將文件名從用戶態拷貝至內核態;

3.get_unused_fd_flags()爲即將打開的文件分配文件描述符;也就是在當前進程的files數組中尋找一個未使用的位置;

4.通過do_filp_open()爲文件創建file結構體;

5.如果創建file成功,則通過fd_install()將fd和file進行關聯;如果創建file失敗,通過put_unused_fd()將已分配的fd返回至系統,並且根據file生成錯誤的fd;

6.通過putname()釋放在內核分配的路徑緩衝區;

7.返回fd;

當open系統調用執行完畢後,fd返回用戶態,內核態新建了與其關聯的file;對於每個進程而言,通過files_struct來記錄其所打開的文件,具體通過fd_array數據保存fd和file的對應關係,fd本質爲該數組的索引。

3.總結

至此,open的基本實現過程已經分析完畢。不過do_sys_open函數沒有直接體現文件路徑的查找過程,這部分將是整個open系統調用內核實現的重要部分。如果對此感興趣,可以繼續閱讀本系列後續文章。

原文鏈接:https://www.sohu.com/a/197368455_467784

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