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

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

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

淺析Linux kernel的閱讀方法

Linux閱碼場(chǎng) ? 來(lái)源:Linux閱碼場(chǎng) ? 2023-03-25 16:49 ? 次閱讀

l 帶著課題

分析任何代碼都要都要帶著課題,如果只是走馬觀花很難有具體的收獲?!罢n題”可大、可小,大課題有大收獲閱讀分析時(shí)間也比較長(zhǎng)。比如“搞清楚Linux是如何收發(fā)數(shù)據(jù)的”“Linux是如何分配內(nèi)存的”,這些都是比較大的題目;再比如“IP數(shù)據(jù)包如何被重組的”這就是比較具體的問(wèn)題,屬于“小課題”。

“大課題”一般是由多個(gè)彼此關(guān)聯(lián)的“小課題”組成的,所以最終我們還是會(huì)去在內(nèi)核中挨個(gè)尋找某個(gè)具體問(wèn)題的具體答案,然后再回頭來(lái)看整個(gè)問(wèn)題?!靶≌n題”是指某個(gè)具體問(wèn)題,我們通常需要先找到一個(gè)切入點(diǎn),然后順藤摸瓜理出一個(gè)頭緒來(lái)。

源代碼的分析工具比較簡(jiǎn)單,一個(gè)編輯器(語(yǔ)法加亮)一個(gè)快捷的查找工具(比如grep)就可以開始干活了。通過(guò)查找工具找到切入點(diǎn),然后分析代碼的邏輯。如果代碼量比較大,一般我們會(huì)選擇一個(gè)IDE工具或者專門的代碼閱讀工具(Source Insight、Understand)來(lái)分析、閱讀代碼。

l 觀察數(shù)據(jù)流向

成熟的代碼通常都很復(fù)雜,考慮的事情也比較全面,所以一個(gè)函數(shù)可能有幾十行代碼。閱讀代碼的時(shí)候我們要把握數(shù)據(jù)流向,比如我們知道函數(shù)的返回值是我們關(guān)注的數(shù)據(jù),那么我們觀察它在哪里執(zhí)行了賦值語(yǔ)句,這樣就可以理出個(gè)主脈絡(luò)來(lái)。

l 分析總結(jié)

我喜歡用兩幅圖來(lái)表示分析代碼之后的收獲,函數(shù)調(diào)用關(guān)系圖、數(shù)據(jù)結(jié)構(gòu)圖。調(diào)用關(guān)系可以從宏觀上告訴我們整個(gè)過(guò)程分成哪些步驟,步驟里面分為哪些子步驟;數(shù)據(jù)結(jié)構(gòu)輔助說(shuō)明了這些過(guò)程涉及到的數(shù)據(jù)操作。

l分析實(shí)戰(zhàn)

代碼分析

“萬(wàn)物皆文件(everything is a file)”,Unix/Linux的一條著名的設(shè)計(jì)哲學(xué)。在Unix/Linux中很多硬件設(shè)備、進(jìn)程運(yùn)行信息、系統(tǒng)狀態(tài)都被映射成文件系統(tǒng)中的某個(gè)文件,這種設(shè)計(jì)極大的簡(jiǎn)化了系統(tǒng)模型。

在Linux中每個(gè)文件都由“struct file”和“一個(gè)int類型的變量——file descriptor(文件描述符)”組成。下面通過(guò)分析Kernel代碼來(lái)剖析file descriptor的分配過(guò)程。

我們是要探究file descriptor的分配過(guò)程,問(wèn)題非常明確,切入點(diǎn)也比較好找——什么時(shí)候執(zhí)行fd的分配?答案是執(zhí)行`open`函數(shù)的時(shí)候。所以我們通過(guò)查找工具定位到`open`系統(tǒng)調(diào)用的代碼(fs/open.c)

c3e28d06-cae8-11ed-bfe3-dac502259ad0.jpg

Linux的代碼非常清晰,open函數(shù)實(shí)際上調(diào)用的是do_sys_open?!按蜷_文件”的過(guò)程分為:

1.分配文件描述符(fd);

2.分配struct file;

3.綁定fd和structfile。

Linux中資源分配的對(duì)象是進(jìn)程,用struct task表示進(jìn)程的數(shù)據(jù)結(jié)構(gòu)?!拔募浔保▋?nèi)核中指向某個(gè)打開文件的指針數(shù)據(jù)結(jié)構(gòu)是struct file)屬于資源申請(qǐng),所以按道理說(shuō)Linux的struct task中應(yīng)該定義一個(gè)struct file類型的數(shù)組,文件描述符則表示struct file數(shù)組中的索引。

c3fa8d84-cae8-11ed-bfe3-dac502259ad0.jpg

實(shí)際上Linux2.1之前就是這么干的,但是這種實(shí)現(xiàn)方式有一個(gè)很明顯的缺陷——files的大小是受限的,2.1之前它是一個(gè)固定的值——256。如果要突破限制那就不能使用“固定大小數(shù)組”的數(shù)字定義files,所以在后續(xù)的版本中就把“文件句柄”拆分成立兩種內(nèi)核資源——文件描述符(fd)、文件對(duì)象(struct file)。(后面會(huì)放上我們分析后的數(shù)據(jù)結(jié)構(gòu)圖——也是Linux正在用的數(shù)據(jù)結(jié)構(gòu))

回到我們的代碼,分配文件描述符的代碼是get_unused_fd_flags,我們跟蹤下去發(fā)現(xiàn)它其實(shí)是__alloc_fd函數(shù)的封裝,直接看__alloc_fd。

c40fca00-cae8-11ed-bfe3-dac502259ad0.jpg

直接讀這么一大段代碼很難理清楚頭緒,這里有個(gè)技巧推薦給大家。直接看它的返回值,它的返回值就是文件描述符,所以我們只要注意在哪里給它賦值就能理出關(guān)鍵頭緒。

__alloc_fd函數(shù)的start,end參數(shù)是指文件描述符的**可用**范圍,get_unused_fd_flags在傳遞start參數(shù)的時(shí)候是0,所以不設(shè)置下標(biāo)范圍。Linux用一個(gè)位圖記錄fd的分配狀態(tài),需要注意的是next_fd并不能直接作為fd返回,它僅僅是標(biāo)識(shí)“未使用的fd中最小值”,這是為了防止位圖中“空隙”(位圖中1、2、4、5、6都是空閑的,3已經(jīng)被使用了,我們搜索未使用fd的時(shí)候很顯然應(yīng)該從1開始搜索。所以一定要保存這個(gè)“下標(biāo)”)。

fdtable是內(nèi)核中用來(lái)表示文件描述符表格的數(shù)據(jù)結(jié)構(gòu),表示fd分配狀態(tài)的位圖就是它的成員變量(full_fds_bits),max_fds記錄的是當(dāng)前表格可用的最大文件描述符,這個(gè)值是可以通過(guò)expand_files增加的(如果你打開`expand_files`會(huì)發(fā)現(xiàn)fd最大值是不能超過(guò)`sysctl_nr_open`的,這個(gè)就是fs.nr_open的值)。

上面的代碼只是尋找可用fd而沒(méi)有修改位圖,所以代碼最后通過(guò)__set_open_fd來(lái)修改位圖。

l總結(jié)經(jīng)驗(yàn)

“一圖勝千言”,代碼分析是一件非常難“表達(dá)出來(lái)”的事情,如果是像上面的文字估計(jì)沒(méi)有多少人會(huì)有興趣看。所以我一般分析完代碼后畫兩張圖,一張表示數(shù)據(jù)結(jié)構(gòu)關(guān)系的圖,一張表示函數(shù)調(diào)用關(guān)系的圖。

c42b91fe-cae8-11ed-bfe3-dac502259ad0.jpg

do_sys_open所做的都是為了最后執(zhí)行fd_install(成功打開文件),而fd_install可以被簡(jiǎn)化為一個(gè)簡(jiǎn)單的賦值語(yǔ)句(圖中的那句賦值語(yǔ)句)。所以前面的get_unused_fd_flags其實(shí)是為了返回合適的fd、do_filp_open則是為struct file分配一塊內(nèi)存空間。

結(jié)合數(shù)據(jù)結(jié)構(gòu)圖來(lái)看

c43d295a-cae8-11ed-bfe3-dac502259ad0.jpg

get_unused_fd_flags的主要操作對(duì)象其實(shí)就是struct files_struct。






審核編輯:劉清

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

    關(guān)注

    4

    文章

    595

    瀏覽量

    27458
  • UNIX
    +關(guān)注

    關(guān)注

    0

    文章

    296

    瀏覽量

    41526
  • sys
    sys
    +關(guān)注

    關(guān)注

    0

    文章

    9

    瀏覽量

    9176
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    316

    瀏覽量

    21694

原文標(biāo)題:邢森: 淺析Linux kernel的閱讀方法

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

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    Linux kernel內(nèi)存管理模塊結(jié)構(gòu)分析

    基于上面章節(jié)的需求,Linux kernel從虛擬內(nèi)存(VM)、DMA mapping以及DMA buffer sharing三個(gè)角度,對(duì)內(nèi)存進(jìn)行管理.
    發(fā)表于 09-19 11:55 ?1802次閱讀
    <b class='flag-5'>Linux</b> <b class='flag-5'>kernel</b>內(nèi)存管理模塊結(jié)構(gòu)分析

    Linux Kernel核心中文手冊(cè)

    Linux Kernel核心中文手冊(cè):Hardware Basic( 硬件基礎(chǔ)知識(shí)) 一個(gè)操作系統(tǒng)必須和作為它的基礎(chǔ)的硬件系統(tǒng)緊密配合。操作系統(tǒng)需要使用一些只有硬件才能提供的功能。為了完整的了解 Linux
    發(fā)表于 12-08 10:15 ?39次下載
    <b class='flag-5'>Linux</b> <b class='flag-5'>Kernel</b>核心中文手冊(cè)

    Developing Linux kernel space

    This thesis introduces how to develop kernel level device drivers on Linux platform in detail.
    發(fā)表于 08-21 10:22 ?10次下載

    linux內(nèi)核kernel-api

    linux內(nèi)核kernel-api,不知道從哪兒找的了,但是你如果想要做內(nèi)核編程,這是一部api函數(shù)詳盡的工具書?。。∥逍峭扑]
    發(fā)表于 10-30 17:16 ?19次下載

    Linuxkernel_timer教程

    Linuxkernel_timer教程,很好的Linux自學(xué)資料,快來(lái)學(xué)習(xí)吧。
    發(fā)表于 04-15 17:59 ?12次下載

    linux kernel工作隊(duì)列及源碼解析

    1. 前言 工作隊(duì)列(workqueue)的Linux內(nèi)核中的定義的用來(lái)處理不是很緊急事件的回調(diào)方式處理方法。 以下代碼的linux內(nèi)核版本為2.6.19.2, 源代碼文件主要為kernel
    發(fā)表于 10-27 10:19 ?0次下載

    Linux運(yùn)行期間升級(jí)Linux系 統(tǒng)Uboot+kernel+Rootfs

    Linux運(yùn)行期間升級(jí)Linux系 統(tǒng)Uboot+kernel+Rootfs
    發(fā)表于 10-30 08:43 ?5次下載
    在<b class='flag-5'>Linux</b>運(yùn)行期間升級(jí)<b class='flag-5'>Linux</b>系 統(tǒng)Uboot+<b class='flag-5'>kernel</b>+Rootfs

    Linux-kernel-3 0的移植記錄

    Linux-kernel-3 0的移植記錄
    發(fā)表于 10-31 11:33 ?7次下載
    <b class='flag-5'>Linux-kernel</b>-3 0的移植記錄

    U-boot傳遞RAM和Linux kernel讀取RAM參數(shù)的解析

    U-boot會(huì)給Linux Kernel傳遞很多參數(shù),如:串口,RAM,videofb等。而Linux kernel也會(huì)讀取和處理這些參數(shù)。兩者之間通過(guò)struct tag來(lái)傳遞參數(shù)。
    的頭像 發(fā)表于 02-06 08:24 ?5881次閱讀
    U-boot傳遞RAM和<b class='flag-5'>Linux</b> <b class='flag-5'>kernel</b>讀取RAM參數(shù)的解析

    你知道linux kernel內(nèi)存碎片防治技術(shù)?

    Linux kernel組織管理物理內(nèi)存的方式是buddy system(伙伴系統(tǒng)),而物理內(nèi)存碎片正式buddy system的弱點(diǎn)之一,為了預(yù)防以及解決碎片問(wèn)題,kernel采取了一些實(shí)用技術(shù),這里將對(duì)這些技術(shù)進(jìn)行總結(jié)歸納。
    發(fā)表于 05-10 10:59 ?963次閱讀

    Linux Kernel 5.2.2震撼發(fā)布!

    在首個(gè)維護(hù)版本更新之后,在kernel.org官網(wǎng)上已經(jīng)將Linux Kernel 5.2分支標(biāo)記為“Stable”,意味著已經(jīng)準(zhǔn)備好大規(guī)模部署了,所有GNU/Linux發(fā)行版本都應(yīng)該
    的頭像 發(fā)表于 08-09 17:01 ?2891次閱讀

    Linux Kernel 5.6-rc7候選版本發(fā)布

    在新冠病毒爆發(fā)期間,Linus Torvalds 宣布了 Linux 5.6 的第七個(gè)每周候選版本,即 Linux Kernel 5.6-rc7 的發(fā)布。
    的頭像 發(fā)表于 03-26 15:52 ?5538次閱讀

    Linux_Kernel_Developments內(nèi)核開發(fā)

    Linux_Kernel_Developments內(nèi)核開發(fā)詳細(xì)說(shuō)明。
    發(fā)表于 04-07 14:27 ?37次下載
    <b class='flag-5'>Linux_Kernel</b>_Developments內(nèi)核開發(fā)

    Linux Kernel5.10維護(hù)周期將從2年延長(zhǎng)至6年

    經(jīng)過(guò) Linux Kernel 社區(qū)成員的共同努力,Linux Kernel 5.10 維護(hù)周期最終確定從2年延長(zhǎng)至6年。華為是第一個(gè)在 Linux
    的頭像 發(fā)表于 05-24 13:52 ?2377次閱讀

    如何選擇合適的工具來(lái)閱讀源代碼

    在做嵌入式 Linux 軟件開發(fā)的時(shí)候,經(jīng)常會(huì)閱讀大型工程源碼,比如 uboot 源代碼,Linux Kernel 源碼等。
    的頭像 發(fā)表于 03-30 14:01 ?1192次閱讀