Linux内核学习(九):linux内核的特殊文件系统-debugfs、ftrace、sys

简介: Linux内核学习(九):linux内核的特殊文件系统-debugfs、ftrace、sys

Linux内核学习(九):linux内核的特殊文件系统-debugfs、ftrace、sys

在内核跑起来之前,有些前置知识需要了解一下,这些可以作为我们的工具,更加帮助我们以后查看内核的信息与调试。

文章内容全部来自《奔跑吧 Linux内核》

1、prink()

在内核中有个经典的打印函数prink(),很多问题定位与追踪都有用到这个工具,这是很多内核开发者最喜欢的调试工具之一是printk。

printk是内核提供的格式化打印函数,它和C库所提供的printf()函数类似。

printk()函数和printf()函数的一个重要区别是前者提供打印等级,内核根据这个等级来判断是否在终端或者串口中打印输出。

**动态输出(Dynamic Printk)是内核子系统开发者最喜欢的输出手段之一。**在系统运行时,**动态输出可以由系统维护者动态打开那些内核子系统的输出,也可以有选择性地打开某些模块的输出,而printk是全局的,只能设置输出等级。

**要使用动态输出,必须在内核配置时打开CONFIG_DYNAMIC_DEBUG宏。**内核代码里使用了大量的pr_debug()/dev_dbg()函数来输出信息,这些就使用了动态输出技术,**另外还需要系统挂载debugfs文件系统。(其实这里就设计到了debugfs)

(动态输出的意思就是你可以想打开看谁就看谁,但是对于全局的来说,你设置了这个函数,它就肯定会打印,不够灵活。)

动态输出在debugfs文件系统中有一个control文件节点。文件节点记录了系统中所有使用动态输出技术的文件名路径、输出所在的行号、模块名字和要打印的语句。

2、proc

在早期的Linux内核中是没有proc,调试参数时显得特别麻烦,只能靠个人对代码的理解程度。后来社区开发了一套虚拟的文件系统,也就是内核和内核模块用来向进程发送消息的机制,这个机制叫作proc。

这个虚拟文件系统可以让用户和内核内部数据结构进行交互,比如获取进程的有用信息、系统的有用信息等。

可以查看某个进程的相关信息,也可以查看系统的信息,比如/proc/meminfo 用来查看内存的管理信息,/proc/cpuinfo用来观察CPU的信息。

proc文件系统并不是真正意义上的文件系统,它存在内存中,并不占用磁盘空间。它包含一些结构化的目录和虚拟文件,向用户呈现内核中的一些信息,也可以用作一种从用户空间向内核发送信息的手段。

这些虚拟文件使用查看命令查看时会返回大量信息,但文件本身的大小却显示为0字节。

此外,这些特殊文件中大多数文件的时间及日期属性通常为当前系统时间和日期。事实上,如ps、top等很多shell命令正是从proc系统中读取信息,且更具可读性。

proc文件系统常用的一些节点如下。

  • /proc/cpuinfo:CPU 的信息(型号、家族、缓存大小等)。
  • /proc/meminfo:物理内存、交换空间等的信息。
  • /proc/mounts:已加载的文件系统的列表。
  • /proc/filesystems:被支持的文件系统。
  • /proc/modules:已加载的模块。
  • /proc/version:内核版本。
  • /proc/cmdline:系统启动时输入的内核命令行参数。
  • /proc//:表示进程的pid,这些子目录中包含可以提供有关进程的状态和环境的重要细节信息的文件。
  • /proc/interrupts:中断使用情况。
  • /proc/kmsg:内核日志信息。
  • /proc/devices:可用的设备,如字符设备和块设备。
  • /proc/ slabinfo:slab系统的统计信息。
  • /proc/uptime:系统正常运行时间。

进程常见的信息如下

  • attr:提供安全相关的属性。
  • cgroup:进程所属的控制组。
  • cmdline:命令行参数。
  • environ:环境变量值。
  • fd:一个包含所有文件描述符的目录。
  • mem:进程的内存被利用情况。
  • stat:进程状态。
  • status:进程当前状态,以可读的方式显示。
  • cwd:当前工作目录的链接。
  • exe:指向该进程的执行命令文件。
  • maps:内存映射信息。
  • statm:进程内存使用信息。
  • root:链接此进程的root目录。
  • oom_adj、oom_score、oom_score_adj:用于OOM killer。

可以看出proc是一个与进程相关的文件系统。

2.1、使用:

procfs文件系统提供了一些常用的API,这些API函数定义在fs/proc/internal.h文件中。

proc_mkdir()可以在 parent 父目录中创建一个名字为 name 的目录,如果 parent 指定为NULL,则在/proc的根目录下面创建一个目录。

struct proc_dir_entry *proc_mkdir(const char *name,struct proc_dir_entry *parent)

proc_create()函数会创建一个新的文件节点。

struct proc_dir_entry *proc_create(const char *name, umode_t mode, struct proc_dir_entry *parent,const struct file_operations *proc_fops)

其中:

  • name是该节点的名称,
  • mode是该节点的访问权限,以UGO的模式来表示;
  • parent和proc_mkdir()函数中的parent类型,指向父进程的proc_dir_entry对象;
  • proc_fops指向该文件的操作函数。

2.2、使用栗子:

比如misc驱动在初始化时就创建了一个名为“misc”的文件。

proc_fops会指向该文件的操作函数集,比如misc驱动中会定义misc_proc_fops函数集,里面有open、read、llseek、release等文件操作函数。

(这个misc文件正是我们自己创造的)

至于进一步的操作,这些文件的操作的韩式是你自定义实现的。

3、sys

为什么有了proc目录还要一个sys目录呢?

其实在Linux内核的开发阶段,很多内核模块,特别是驱动开发向proc目录中乱添加节点和目录,导致proc目录下面显得杂乱无章。另一个原因是,Linux 2.5开发期间设计了一套统一的设备驱动模型,这就诞生了sys这个新的虚拟文件系统。

sys–>管理设备驱动的文件系统

这个新的设备模型是为了对计算机上的所有设备进行统一地表示和操作,包括设备本身和设备之间的连接关系。

这个模型建立在 PCI 和 USB 的总线枚举过程的分析之上,这两个总线类型能代表当前系统中的大多数设备类型。

现在很多子系统、设备驱动程序已经将sysfs作为与用户空间友好的接口。

因此,系统中整体信息可通过procfs来获取,设备模型相关信息可通过sysfs来获取。

3.1、使用:

kobject_create_and_add()函数会动态生成一个struct kobject数据结构,然后将其注册到sysfs文件系统中。

其中,name就是要创建的文件或者目录的名称,parent指向父目录的kobject数据结构,若parent为NULL,说明父目录就是/sys目录。

struct kobject *kobject_create_and_add(const char *name, struct kobject*parent)

sysfs_create_group()函数会在参数1的kobj目录下面创建一个属性集合,并且显示该集合的文件。

static inline int sysfs_create_group(struct kobject *kobj,const struct attribute_group *grp)

参数2中描述的是一组属性类型,其数据结构定义如下。

struct attribute数据结构用于描述文件的属性。

/sys/kernel目录建立在内核源代码的kernel/ksysfs.c文件中。

这里 kobject_create_and_add()在/sys 目录下建立一个名为“kernel”的目录,然后sysfs_create_group()函数在该目录下面创建一些属性集合。

以profiling文件为例,这里实现profiling_show()和profiling_store()两个函数,分别对应读和写操作。

(源码还是自己在本地读者舒服,当你不知道这个是什么意思的时候,就点进去看看)

4、debugfs

debugfs是一种用来调试内核的内存文件系统,内核开发者可以通过debugfs和用户空间交换数据,有点类似于前文提到的procfs和sysfs。

debugfs文件系统也并不是存储在磁盘中,而是建立到内存中。

内核调试所使用的最原始的调试手段是添加打印语句,但是有时我们需要在运行中修改某些内核的数据,这时printk就显得无能为力了。

一个可行的办法就是修改内核代码并编译,然后重新运行,但这种办法低效并且有些场景下系统还不能重启,那就需要一个临时的文件系统可以把关心的数据映射到用户空间。

之前内核实现的procfs和sysfs可以达到这个目的,但是procfs是为了反映系统以及进程的状态信息,sysfs用于Linux设备驱动模型,把私有的调试信息加入这两个虚拟文件系统不太合适,因此内核多添加了一个虚拟文件系统,也就是debugfs。

debugfs一般会挂载到/sys/kernel/debug目录,可以通过mount命令来实现。# mount -t debugfs none /sys/kernel/debug

其实使用的方式和proc那些都很相似

4.1、举个栗子

my_debugTest = debugfs_create_dir("debugTest", NULL);
debugfs_create_u8("debugTestFs", 0644, my_debugTest,NULL, &fileop);

其实关键的信息传输功能在于fileop这个结构体对应的的对文件操作的函数,这两步只是建立好这个用户与内核调试的媒介,进一步的具体读写,在于对文件操作方法的实现。

目录
相关文章
|
6月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
622 1
|
6月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
6月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
6月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
413 0
|
6月前
|
Web App开发 缓存 Rust
|
6月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
5月前
|
Linux 应用服务中间件 Shell
二、Linux文本处理与文件操作核心命令
熟悉了Linux的基本“行走”后,就该拿起真正的“工具”干活了。用grep这个“放大镜”在文件里搜索内容,用find这个“探测器”在系统中寻找文件,再用tar把东西打包带走。最关键的是要学会使用管道符|,它像一条流水线,能把这些命令串联起来,让简单工具组合出强大的功能,比如 ps -ef | grep 'nginx' 就能快速找出nginx进程。
627 1
二、Linux文本处理与文件操作核心命令
|
5月前
|
Linux
linux命令—stat
`stat` 是 Linux 系统中用于查看文件或文件系统详细状态信息的命令。相比 `ls -l`,它提供更全面的信息,包括文件大小、权限、所有者、时间戳(最后访问、修改、状态变更时间)、inode 号、设备信息等。其常用选项包括 `-f` 查看文件系统状态、`-t` 以简洁格式输出、`-L` 跟踪符号链接,以及 `-c` 或 `--format` 自定义输出格式。通过这些选项,用户可以灵活获取所需信息,适用于系统调试、权限检查、磁盘管理等场景。
402 137