0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

浅析Linux kernel的阅读方法

Linux阅码场 来源:Linux阅码场 2023-03-25 16:49 次阅读

l 带着课题

分析任何代码都要都要带着课题,如果只是走马观花很难有具体的收获。“课题”可大、可小,大课题有大收获阅读分析时间也比较长。比如“搞清楚Linux是如何收发数据的”“Linux是如何分配内存的”,这些都是比较大的题目;再比如“IP数据包如何被重组的”这就是比较具体的问题,属于“小课题”。

“大课题”一般是由多个彼此关联的“小课题”组成的,所以最终我们还是会去在内核中挨个寻找某个具体问题的具体答案,然后再回头来看整个问题。“小课题”是指某个具体问题,我们通常需要先找到一个切入点,然后顺藤摸瓜理出一个头绪来。

源代码的分析工具比较简单,一个编辑器(语法加亮)一个快捷的查找工具(比如grep)就可以开始干活了。通过查找工具找到切入点,然后分析代码的逻辑。如果代码量比较大,一般我们会选择一个IDE工具或者专门的代码阅读工具(Source Insight、Understand)来分析、阅读代码。

l 观察数据流向

成熟的代码通常都很复杂,考虑的事情也比较全面,所以一个函数可能有几十行代码。阅读代码的时候我们要把握数据流向,比如我们知道函数的返回值是我们关注的数据,那么我们观察它在哪里执行了赋值语句,这样就可以理出个主脉络来。

l 分析总结

我喜欢用两幅图来表示分析代码之后的收获,函数调用关系图、数据结构图。调用关系可以从宏观上告诉我们整个过程分成哪些步骤,步骤里面分为哪些子步骤;数据结构辅助说明了这些过程涉及到的数据操作。

l分析实战

代码分析

“万物皆文件(everything is a file)”,Unix/Linux的一条著名的设计哲学。在Unix/Linux中很多硬件设备、进程运行信息、系统状态都被映射成文件系统中的某个文件,这种设计极大的简化了系统模型。

在Linux中每个文件都由“struct file”和“一个int类型的变量——file descriptor(文件描述符)”组成。下面通过分析Kernel代码来剖析file descriptor的分配过程。

我们是要探究file descriptor的分配过程,问题非常明确,切入点也比较好找——什么时候执行fd的分配?答案是执行`open`函数的时候。所以我们通过查找工具定位到`open`系统调用的代码(fs/open.c)

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

Linux的代码非常清晰,open函数实际上调用的是do_sys_open。“打开文件”的过程分为:

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

2.分配struct file;

3.绑定fd和structfile。

Linux中资源分配的对象是进程,用struct task表示进程的数据结构。“文件句柄”(内核中指向某个打开文件的指针数据结构是struct file)属于资源申请,所以按道理说Linux的struct task中应该定义一个struct file类型的数组,文件描述符则表示struct file数组中的索引

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

实际上Linux2.1之前就是这么干的,但是这种实现方式有一个很明显的缺陷——files的大小是受限的,2.1之前它是一个固定的值——256。如果要突破限制那就不能使用“固定大小数组”的数字定义files,所以在后续的版本中就把“文件句柄”拆分成立两种内核资源——文件描述符(fd)文件对象(struct file)。(后面会放上我们分析后的数据结构图——也是Linux正在用的数据结构)

回到我们的代码,分配文件描述符的代码是get_unused_fd_flags,我们跟踪下去发现它其实是__alloc_fd函数的封装,直接看__alloc_fd。

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

直接读这么一大段代码很难理清楚头绪,这里有个技巧推荐给大家。直接看它的返回值,它的返回值就是文件描述符,所以我们只要注意在哪里给它赋值就能理出关键头绪。

__alloc_fd函数的start,end参数是指文件描述符的**可用**范围,get_unused_fd_flags在传递start参数的时候是0,所以不设置下标范围。Linux用一个位图记录fd的分配状态,需要注意的是next_fd并不能直接作为fd返回,它仅仅是标识“未使用的fd中最小值”,这是为了防止位图中“空隙”(位图中1、2、4、5、6都是空闲的,3已经被使用了,我们搜索未使用fd的时候很显然应该从1开始搜索。所以一定要保存这个“下标”)。

fdtable是内核中用来表示文件描述符表格的数据结构,表示fd分配状态的位图就是它的成员变量(full_fds_bits),max_fds记录的是当前表格可用的最大文件描述符,这个值是可以通过expand_files增加的(如果你打开`expand_files`会发现fd最大值是不能超过`sysctl_nr_open`的,这个就是fs.nr_open的值)。

上面的代码只是寻找可用fd而没有修改位图,所以代码最后通过__set_open_fd来修改位图。

l总结经验

“一图胜千言”,代码分析是一件非常难“表达出来”的事情,如果是像上面的文字估计没有多少人会有兴趣看。所以我一般分析完代码后画两张图,一张表示数据结构关系的图,一张表示函数调用关系的图。

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

do_sys_open所做的都是为了最后执行fd_install(成功打开文件),而fd_install可以被简化为一个简单的赋值语句(图中的那句赋值语句)。所以前面的get_unused_fd_flags其实是为了返回合适的fd、do_filp_open则是为struct file分配一块内存空间。

结合数据结构图来看

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

get_unused_fd_flags的主要操作对象其实就是struct files_struct。






审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux系统
    +关注

    关注

    4

    文章

    567

    浏览量

    26923
  • UNIX
    +关注

    关注

    0

    文章

    295

    浏览量

    41061
  • sys
    sys
    +关注

    关注

    0

    文章

    8

    浏览量

    9117
  • LINUX内核
    +关注

    关注

    1

    文章

    311

    浏览量

    21389

原文标题:邢森: 浅析Linux kernel的阅读方法

文章出处:【微信号:LinuxDev,微信公众号:Linux阅码场】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    linux kernel

    linux kernel 有什么学习技巧吗?
    发表于 06-11 18:23

    Linux Kernel Panic的产生的原因?

    网友安装linux出现“Kernel panic-not syncing fatal exception in interrupt”是由于网卡驱动原因。解决方法:将选项“Onboard Lan”的选项
    发表于 06-15 06:24

    Developing Linux kernel space

    This thesis introduces how to develop kernel level device drivers on Linux platform in detail.
    发表于 08-21 10:22 10次下载

    linux内核kernel-api

    linux内核kernel-api,不知道从哪儿找的了,但是你如果想要做内核编程,这是一部api函数详尽的工具书!!!五星推荐
    发表于 10-30 17:16 19次下载

    Linuxkernel_timer教程

    Linuxkernel_timer教程,很好的Linux自学资料,快来学习吧。
    发表于 04-15 17:59 12次下载

    Linux运行期间升级Linux系 统Uboot+kernel+Rootfs

    Linux运行期间升级Linux系 统Uboot+kernel+Rootfs
    发表于 10-30 08:43 5次下载
    在<b class='flag-5'>Linux</b>运行期间升级<b class='flag-5'>Linux</b>系 统Uboot+<b class='flag-5'>kernel</b>+Rootfs

    Linux-kernel-3 0的移植记录

    Linux-kernel-3 0的移植记录
    发表于 10-31 11:33 7次下载
    <b class='flag-5'>Linux-kernel</b>-3 0的移植记录

    U-boot传递RAM和Linux kernel读取RAM参数的解析

    U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等。而Linux kernel也会读取和处理这些参数。两者之间通过struct tag来传递参数。
    的头像 发表于 02-06 08:24 5614次阅读
    U-boot传递RAM和<b class='flag-5'>Linux</b> <b class='flag-5'>kernel</b>读取RAM参数的解析

    你知道linux kernel内存碎片防治技术?

    Linux kernel组织管理物理内存的方式是buddy system(伙伴系统),而物理内存碎片正式buddy system的弱点之一,为了预防以及解决碎片问题,kernel采取了一些实用技术,这里将对这些技术进行总结归纳。
    发表于 05-10 10:59 823次阅读

    Linux Kernel 5.2.2震撼发布!

    在首个维护版本更新之后,在kernel.org官网上已经将Linux Kernel 5.2分支标记为“Stable”,意味着已经准备好大规模部署了,所有GNU/Linux发行版本都应该
    的头像 发表于 08-09 17:01 2695次阅读

    Linux Kernel 5.6-rc7候选版本发布

    在新冠病毒爆发期间,Linus Torvalds 宣布了 Linux 5.6 的第七个每周候选版本,即 Linux Kernel 5.6-rc7 的发布。
    的头像 发表于 03-26 15:52 5325次阅读

    Linux_Kernel_Developments内核开发

    Linux_Kernel_Developments内核开发详细说明。
    发表于 04-07 14:27 37次下载
    <b class='flag-5'>Linux_Kernel</b>_Developments内核开发

    Linux Kernel5.10维护周期将从2年延长至6年

    经过 Linux Kernel 社区成员的共同努力,Linux Kernel 5.10 维护周期最终确定从2年延长至6年。华为是第一个在 Linux
    的头像 发表于 05-24 13:52 2129次阅读

    如何选择合适的工具来阅读源代码

    在做嵌入式 Linux 软件开发的时候,经常会阅读大型工程源码,比如 uboot 源代码,Linux Kernel 源码等。
    的头像 发表于 03-30 14:01 983次阅读

    likely与unlikely在Linux kernel的区别

    likely() 与 unlikely() 在 Linux kernel 中随处可见,那为什么要用它们?它们之间有什么区别呢? 首先明确: if (likely(value)) 等价
    的头像 发表于 07-20 11:06 557次阅读