0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

Read系統(tǒng)調(diào)用在用戶空間中的處理過(guò)程

Linux閱碼場(chǎng) ? 來(lái)源:未知 ? 作者:李倩 ? 2018-04-02 15:53 ? 次閱讀

Read 系統(tǒng)調(diào)用在用戶空間中的處理過(guò)程

Linux 系統(tǒng)調(diào)用(SCI,system call interface)的實(shí)現(xiàn)機(jī)制實(shí)際上是一個(gè)多路匯聚以及分解的過(guò)程,該匯聚點(diǎn)就是 0x80 中斷這個(gè)入口點(diǎn)(X86 系統(tǒng)結(jié)構(gòu))。也就是說(shuō),所有系統(tǒng)調(diào)用都從用戶空間中匯聚到 0x80 中斷點(diǎn),同時(shí)保存具體的系統(tǒng)調(diào)用號(hào)。當(dāng) 0x80 中斷處理程序運(yùn)行時(shí),將根據(jù)系統(tǒng)調(diào)用號(hào)對(duì)不同的系統(tǒng)調(diào)用分別處理(調(diào)用不同的內(nèi)核函數(shù)處理)。系統(tǒng)調(diào)用的更多內(nèi)容,請(qǐng)參見參考資料

Read 系統(tǒng)調(diào)用也不例外,當(dāng)調(diào)用發(fā)生時(shí),庫(kù)函數(shù)在保存 read 系統(tǒng)調(diào)用號(hào)以及參數(shù)后,陷入 0x80 中斷。這時(shí)庫(kù)函數(shù)工作結(jié)束。Read 系統(tǒng)調(diào)用在用戶空間中的處理也就完成了。

Read 系統(tǒng)調(diào)用在核心空間中的處理過(guò)程

0x80 中斷處理程序接管執(zhí)行后,先檢察其系統(tǒng)調(diào)用號(hào),然后根據(jù)系統(tǒng)調(diào)用號(hào)查找系統(tǒng)調(diào)用表,并從系統(tǒng)調(diào)用表中得到處理 read 系統(tǒng)調(diào)用的內(nèi)核函數(shù) sys_read ,最后傳遞參數(shù)并運(yùn)行 sys_read 函數(shù)。至此,內(nèi)核真正開始處理 read 系統(tǒng)調(diào)用(sys_read 是 read 系統(tǒng)調(diào)用的內(nèi)核入口)。

在講解 read 系統(tǒng)調(diào)用在核心空間中的處理部分中,首先介紹了內(nèi)核處理磁盤請(qǐng)求的層次模型,然后再按該層次模型從上到下的順序依次介紹磁盤讀請(qǐng)求在各層的處理過(guò)程。

Read 系統(tǒng)調(diào)用在核心空間中處理的層次模型

圖1顯示了 read 系統(tǒng)調(diào)用在核心空間中所要經(jīng)歷的層次模型。從圖中看出:對(duì)于磁盤的一次讀請(qǐng)求,首先經(jīng)過(guò)虛擬文件系統(tǒng)層(vfs layer),其次是具體的文件系統(tǒng)層(例如 ext2),接下來(lái)是 cache 層(page cache 層)、通用塊層(generic block layer)、IO 調(diào)度層(I/O scheduler layer)、塊設(shè)備驅(qū)動(dòng)層(block device driver layer),最后是物理塊設(shè)備層(block device layer)

圖1 read 系統(tǒng)調(diào)用在核心空間中的處理層次

虛擬文件系統(tǒng)層的作用:屏蔽下層具體文件系統(tǒng)操作的差異,為上層的操作提供一個(gè)統(tǒng)一的接口。正是因?yàn)橛辛诉@個(gè)層次,所以可以把設(shè)備抽象成文件,使得操作設(shè)備就像操作文件一樣簡(jiǎn)單。

在具體的文件系統(tǒng)層中,不同的文件系統(tǒng)(例如 ext2 和 NTFS)具體的操作過(guò)程也是不同的。每種文件系統(tǒng)定義了自己的操作集合。關(guān)于文件系統(tǒng)的更多內(nèi)容,請(qǐng)參見參考資料。

引入 cache 層的目的是為了提高 linux 操作系統(tǒng)對(duì)磁盤訪問的性能。 Cache 層在內(nèi)存中緩存了磁盤上的部分?jǐn)?shù)據(jù)。當(dāng)數(shù)據(jù)的請(qǐng)求到達(dá)時(shí),如果在 cache 中存在該數(shù)據(jù)且是最新的,則直接將數(shù)據(jù)傳遞給用戶程序,免除了對(duì)底層磁盤的操作,提高了性能。

通用塊層的主要工作是:接收上層發(fā)出的磁盤請(qǐng)求,并最終發(fā)出 IO 請(qǐng)求。該層隱藏了底層硬件塊設(shè)備的特性,為塊設(shè)備提供了一個(gè)通用的抽象視圖。

IO 調(diào)度層的功能:接收通用塊層發(fā)出的 IO 請(qǐng)求,緩存請(qǐng)求并試圖合并相鄰的請(qǐng)求(如果這兩個(gè)請(qǐng)求的數(shù)據(jù)在磁盤上是相鄰的)。并根據(jù)設(shè)置好的調(diào)度算法,回調(diào)驅(qū)動(dòng)層提供的請(qǐng)求處理函數(shù),以處理具體的 IO 請(qǐng)求。

驅(qū)動(dòng)層中的驅(qū)動(dòng)程序?qū)?yīng)具體的物理塊設(shè)備。它從上層中取出 IO 請(qǐng)求,并根據(jù)該 IO 請(qǐng)求中指定的信息,通過(guò)向具體塊設(shè)備的設(shè)備控制器發(fā)送命令的方式,來(lái)操縱設(shè)備傳輸數(shù)據(jù)。

設(shè)備層中都是具體的物理設(shè)備。定義了操作具體設(shè)備的規(guī)范。

相關(guān)的內(nèi)核數(shù)據(jù)結(jié)構(gòu):

Dentry : 聯(lián)系了文件名和文件的 i 節(jié)點(diǎn)

inode : 文件 i 節(jié)點(diǎn),保存文件標(biāo)識(shí)、權(quán)限和內(nèi)容等信息

file : 保存文件的相關(guān)信息和各種操作文件的函數(shù)指針集合

file_operations :操作文件的函數(shù)接口集合

address_space :描述文件的 page cache 結(jié)構(gòu)以及相關(guān)信息,并包含有操作 page cache 的函數(shù)指針集合

address_space_operations :操作 page cache 的函數(shù)接口集合

bio : IO 請(qǐng)求的描述

數(shù)據(jù)結(jié)構(gòu)之間的關(guān)系:

圖2示意性地展示了上述各個(gè)數(shù)據(jù)結(jié)構(gòu)(除了 bio)之間的關(guān)系??梢钥闯觯河?dentry 對(duì)象可以找到 inode 對(duì)象,從 inode 對(duì)象中可以取出 address_space 對(duì)象,再由 address_space 對(duì)象找到 address_space_operations 對(duì)象。

File 對(duì)象可以根據(jù)當(dāng)前進(jìn)程描述符中提供的信息取得,進(jìn)而可以找到 dentry 對(duì)象、 address_space 對(duì)象和 file_operations 對(duì)象。

圖2 數(shù)據(jù)結(jié)構(gòu)關(guān)系圖:

前提條件:

對(duì)于具體的一次 read 調(diào)用,內(nèi)核中可能遇到的處理情況很多。這里舉例其中的一種情況:

要讀取的文件已經(jīng)存在

文件經(jīng)過(guò) page cache

要讀的是普通文件

磁盤上文件系統(tǒng)為 ext2 文件系統(tǒng),有關(guān) ext2 文件系統(tǒng)的相關(guān)內(nèi)容,參見參考資料

準(zhǔn)備:

注:所有清單中代碼均來(lái)自 linux2.6.11 內(nèi)核原代碼

讀數(shù)據(jù)之前,必須先打開文件。處理 open 系統(tǒng)調(diào)用的內(nèi)核函數(shù)為 sys_open 。所以我們先來(lái)看一下該函數(shù)都作了哪些事。清單1顯示了 sys_open 的代碼(省略了部分內(nèi)容,以后的程序清單同樣方式處理)

清單1 sys_open 函數(shù)代碼

代碼解釋:

get_unuesed_fd() :取回一個(gè)未被使用的文件描述符(每次都會(huì)選取最小的未被使用的文件描述符)。

filp_open() :調(diào)用 open_namei() 函數(shù)取出和該文件相關(guān)的 dentry 和 inode (因?yàn)榍疤嶂该髁宋募呀?jīng)存在,所以 dentry 和 inode 能夠查找到,不用創(chuàng)建),然后調(diào)用 dentry_open() 函數(shù)創(chuàng)建新的 file 對(duì)象,并用 dentry 和 inode 中的信息初始化 file 對(duì)象(文件當(dāng)前的讀寫位置在 file 對(duì)象中保存)。注意到 dentry_open() 中有一條語(yǔ)句:

f->f_op = fops_get(inode->i_fop);

這個(gè)賦值語(yǔ)句把和具體文件系統(tǒng)相關(guān)的,操作文件的函數(shù)指針集合賦給了 file 對(duì)象的 f _op 變量(這個(gè)指針集合是保存在 inode 對(duì)象中的),在接下來(lái)的 sys_read 函數(shù)中將會(huì)調(diào)用 file->f_op 中的成員 read 。

fd_install() :以文件描述符為索引,關(guān)聯(lián)當(dāng)前進(jìn)程描述符和上述的 file 對(duì)象,為之后的 read 和 write 等操作作準(zhǔn)備。

函數(shù)最后返回該文件描述符。

圖3顯示了 sys_open 函數(shù)返回后, file 對(duì)象和當(dāng)前進(jìn)程描述符之間的關(guān)聯(lián)關(guān)系,以及 file 對(duì)象中操作文件的函數(shù)指針集合的來(lái)源(inode 對(duì)象中的成員 i_fop)。

圖3 file 對(duì)象和當(dāng)前進(jìn)程描述符之間的關(guān)系

到此為止,所有的準(zhǔn)備工作已經(jīng)全部結(jié)束了,下面開始介紹 read 系統(tǒng)調(diào)用在圖1所示的各個(gè)層次中的處理過(guò)程。

虛擬文件系統(tǒng)層的處理:

內(nèi)核函數(shù) sys_read() 是 read 系統(tǒng)調(diào)用在該層的入口點(diǎn),清單2顯示了該函數(shù)的代碼。

清單2 sys_read 函數(shù)的代碼

代碼解析:

fget_light() :根據(jù) fd 指定的索引,從當(dāng)前進(jìn)程描述符中取出相應(yīng)的 file 對(duì)象(見圖3)。

如果沒找到指定的 file 對(duì)象,則返回錯(cuò)誤

如果找到了指定的 file 對(duì)象:

調(diào)用 file_pos_read() 函數(shù)取出此次讀寫文件的當(dāng)前位置。

調(diào)用 vfs_read() 執(zhí)行文件讀取操作,而這個(gè)函數(shù)最終調(diào)用 file->f_op.read() 指向的函數(shù),代碼如下:

if (file->f_op->read)ret = file->f_op->read(file, buf, count, pos);

調(diào)用 file_pos_write() 更新文件的當(dāng)前讀寫位置。

調(diào)用 fput_light() 更新文件的引用計(jì)數(shù)。

最后返回讀取數(shù)據(jù)的字節(jié)數(shù)。

到此,虛擬文件系統(tǒng)層所做的處理就完成了,控制權(quán)交給了 ext2 文件系統(tǒng)層。

在解析 ext2 文件系統(tǒng)層的操作之前,先讓我們看一下 file 對(duì)象中 read 指針來(lái)源。

File 對(duì)象中 read 函數(shù)指針的來(lái)源:

從前面對(duì) sys_open 內(nèi)核函數(shù)的分析來(lái)看, file->f_op 來(lái)自于 inode->i_fop 。那么 inode->i_fop 來(lái)自于哪里呢?在初始化 inode 對(duì)象時(shí)賦予的。見清單3。

清單3 ext2_read_inode() 函數(shù)部分代碼

從代碼中可以看出,如果該 inode 所關(guān)聯(lián)的文件是普通文件,則將變量 ext2_file_operations 的地址賦予 inode 對(duì)象的 i_fop 成員。所以可以知道: inode->i_fop.read 函數(shù)指針?biāo)赶虻暮瘮?shù)為 ext2_file_operations 變量的成員 read 所指向的函數(shù)。下面來(lái)看一下 ext2_file_operations 變量的初始化過(guò)程,如清單4。

清單4 ext2_file_operations 的初始化

該成員 read 指向函數(shù) generic_file_read 。所以, inode->i_fop.read 指向 generic_file_read 函數(shù),進(jìn)而 file->f_op.read 指向 generic_file_read 函數(shù)。最終得出結(jié)論: generic_file_read 函數(shù)才是 ext2 層的真實(shí)入口。

Ext2 文件系統(tǒng)層的處理

圖4 read 系統(tǒng)調(diào)用在 ext2 層中處理時(shí)函數(shù)調(diào)用關(guān)系

由圖 4 可知,該層入口函數(shù) generic_file_read 調(diào)用函數(shù) __generic_file_aio_read ,后者判斷本次讀請(qǐng)求的訪問方式,如果是直接 io (filp->f_flags 被設(shè)置了 O_DIRECT 標(biāo)志,即不經(jīng)過(guò) cache)的方式,則調(diào)用 generic_file_direct_IO 函數(shù);如果是 page cache 的方式,則調(diào)用 do_generic_file_read 函數(shù)。函數(shù) do_generic_file_read 僅僅是一個(gè)包裝函數(shù),它又調(diào)用 do_generic_mapping_read 函數(shù)。

在講解 do_generic_mapping_read 函數(shù)都作了哪些工作之前,我們?cè)賮?lái)看一下文件在內(nèi)存中的緩存區(qū)域是被怎么組織起來(lái)的。

文件的 page cache 結(jié)構(gòu)

圖5顯示了一個(gè)文件的 page cache 結(jié)構(gòu)。文件被分割為一個(gè)個(gè)以 page 大小為單元的數(shù)據(jù)塊,這些數(shù)據(jù)塊(頁(yè))被組織成一個(gè)多叉樹(稱為 radix 樹)。樹中所有葉子節(jié)點(diǎn)為一個(gè)個(gè)頁(yè)幀結(jié)構(gòu)(struct page),表示了用于緩存該文件的每一個(gè)頁(yè)。在葉子層最左端的第一個(gè)頁(yè)保存著該文件的前4096個(gè)字節(jié)(如果頁(yè)的大小為4096字節(jié)),接下來(lái)的頁(yè)保存著文件第二個(gè)4096個(gè)字節(jié),依次類推。樹中的所有中間節(jié)點(diǎn)為組織節(jié)點(diǎn),指示某一地址上的數(shù)據(jù)所在的頁(yè)。此樹的層次可以從0層到6層,所支持的文件大小從0字節(jié)到16 T 個(gè)字節(jié)。樹的根節(jié)點(diǎn)指針可以從和文件相關(guān)的 address_space 對(duì)象(該對(duì)象保存在和文件關(guān)聯(lián)的 inode 對(duì)象中)中取得(更多關(guān)于 page cache 的結(jié)構(gòu)內(nèi)容請(qǐng)參見參考資料)。

圖5 文件的 page cache 結(jié)構(gòu)

現(xiàn)在,我們來(lái)看看函數(shù) do_generic_mapping_read 都作了哪些工作, do_generic_mapping_read 函數(shù)代碼較長(zhǎng),本文簡(jiǎn)要介紹下它的主要流程:

根據(jù)文件當(dāng)前的讀寫位置,在 page cache 中找到緩存請(qǐng)求數(shù)據(jù)的 page

如果該頁(yè)已經(jīng)最新,將請(qǐng)求的數(shù)據(jù)拷貝到用戶空間

否則, Lock 該頁(yè)

調(diào)用 readpage 函數(shù)向磁盤發(fā)出添頁(yè)請(qǐng)求(當(dāng)下層完成該 IO 操作時(shí)會(huì)解鎖該頁(yè)),代碼:

1

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11329

    瀏覽量

    209969
  • Read
    +關(guān)注

    關(guān)注

    0

    文章

    10

    瀏覽量

    11117
  • 數(shù)據(jù)結(jié)構(gòu)

    關(guān)注

    3

    文章

    573

    瀏覽量

    40169

原文標(biāo)題:read 系統(tǒng)調(diào)用剖析

文章出處:【微信號(hào):LinuxDev,微信公眾號(hào):Linux閱碼場(chǎng)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    什么是Linux系統(tǒng)調(diào)用,包括哪些內(nèi)容

    上,邏輯上是相互隔離的。因此,用戶進(jìn)程在通常情況下不允許訪問內(nèi)核數(shù)據(jù),也無(wú)法使用內(nèi)核函數(shù),它們只能在用戶空間操作用戶數(shù)據(jù),調(diào)用用戶
    發(fā)表于 08-23 11:55

    vison assistant中的圖像處理過(guò)程

    新手求教!在vision assistant中驗(yàn)證圖片時(shí)在圖像處理畫面可以看到圖像的處理過(guò)程,但完成退回到labview中后,為什么在顯示的 圖片中看不到處理過(guò)程呢?
    發(fā)表于 06-24 15:55

    用NI Vision Assistant生成的vi運(yùn)行時(shí)不顯示處理過(guò)程

    大家好,我最近在用vision assistant時(shí)遇到了問題,在assistant里處理過(guò)程可以顯示,但當(dāng)我選擇好要顯示的數(shù)據(jù),導(dǎo)出成vi后,這些選擇的測(cè)試數(shù)據(jù)是有的也是正常的,但是輸出圖像里沒有處理過(guò)程還是一張?jiān)紙D像。大家
    發(fā)表于 06-08 10:49

    單片機(jī)中斷的處理過(guò)程是怎樣進(jìn)行的?

    單片機(jī)中斷系統(tǒng)的優(yōu)點(diǎn)是什么?單片機(jī)中斷的處理過(guò)程是怎樣進(jìn)行的?
    發(fā)表于 09-23 06:57

    CPU的內(nèi)部處理過(guò)程是怎樣的

    CPU是什么?CPU主要由哪幾部分構(gòu)成?CPU的內(nèi)部處理過(guò)程是怎樣的?
    發(fā)表于 10-19 09:21

    用戶空間如何訪問內(nèi)核空間?

    訪問。嵌入式Linux:C開發(fā)“會(huì)看使用說(shuō)明書”用戶空間不能隨便訪問內(nèi)核空間3、用戶空間如何訪問內(nèi)核空間
    發(fā)表于 12-27 06:15

    ARM中斷向量表異常處理過(guò)程解析

    中斷向量表|異常處理過(guò)程中斷隨機(jī)產(chǎn)生之后,怎么跳轉(zhuǎn)到中斷的處理程序中去(中斷向量表)SWI軟中斷指令:模擬CPU外面的某個(gè)硬件的管腳產(chǎn)生中斷信號(hào)4. 軟中斷處理程序?qū)嵗髡撸何鞫熘改?/div>
    發(fā)表于 05-05 10:16

    污水處理過(guò)程儀表技術(shù)的研究現(xiàn)狀

    污水處理過(guò)程固有的非線性、時(shí)變性特征對(duì)傳感器的可靠性、適應(yīng)性提出了很高的要求。污水處理過(guò)程涉及多種傳感器,多數(shù)傳感器是污水處理過(guò)程所特有的,分別為人們提供所監(jiān)
    發(fā)表于 12-20 15:11 ?10次下載

    污水處理過(guò)程儀表技術(shù)的研究現(xiàn)狀

    污水處理過(guò)程固有的非線性、時(shí)變性特征對(duì)傳感器的可靠性、適應(yīng)性提出了很高的要求。污水處理過(guò)程涉及多種傳感器,多數(shù)傳感器是污水處理過(guò)程所特有的,分別為人們提供所監(jiān)
    發(fā)表于 01-07 15:39 ?15次下載

    數(shù)字電視的典型的處理過(guò)程

    典型的處理過(guò)程 下面介紹數(shù)字電視的幾個(gè)典型的處理過(guò)程。
    發(fā)表于 07-31 14:23 ?1545次閱讀
    數(shù)字電視的典型的<b class='flag-5'>處理過(guò)程</b>

    淺析單片機(jī)中斷處理過(guò)程

    中斷處理過(guò)程可分為中斷響應(yīng)、中斷處理和中斷返回三個(gè)階段。
    的頭像 發(fā)表于 11-06 14:31 ?1.8w次閱讀
    淺析單片機(jī)中斷<b class='flag-5'>處理過(guò)程</b>

    mmap系統(tǒng)調(diào)用和vmalloc獲取地址空間

    mmap()系統(tǒng)調(diào)用在用戶進(jìn)程與內(nèi)核之間共享內(nèi)存區(qū)域的常用方法。我們最近有個(gè)程序,需要應(yīng)用進(jìn)程能夠讀取內(nèi)核驅(qū)動(dòng)獲取的數(shù)據(jù),經(jīng)過(guò)簡(jiǎn)單的調(diào)研,決定采用mmap方式。
    的頭像 發(fā)表于 02-02 16:13 ?4379次閱讀

    linux drivers中的mmap實(shí)現(xiàn)

    將設(shè)備驅(qū)動(dòng)內(nèi)核空間的內(nèi)存映射到用戶空間里,可以通過(guò)用戶空間中的mmap系統(tǒng)
    發(fā)表于 05-15 10:31 ?1610次閱讀

    系統(tǒng)調(diào)用具體是如何實(shí)現(xiàn)的

    返回給應(yīng)用程序。如此才能保證系統(tǒng)的穩(wěn)定和安全。本文采用 的實(shí)例來(lái)講解系統(tǒng)調(diào)用具體是如何實(shí)現(xiàn)的。 系統(tǒng)調(diào)用是給
    的頭像 發(fā)表于 09-29 11:10 ?3735次閱讀

    雙核系統(tǒng)調(diào)用(ipipe)

    為什么需要系統(tǒng)調(diào)用?現(xiàn)代操作系統(tǒng)中,處理器的運(yùn)行模式一般分為兩個(gè)空間:內(nèi)核空間
    的頭像 發(fā)表于 05-06 11:11 ?2135次閱讀