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这个结构体对应的的对文件操作的函数,这两步只是建立好这个用户与内核调试的媒介,进一步的具体读写,在于对文件操作方法的实现。

目录
相关文章
|
3天前
|
存储 安全 Linux
|
5天前
|
Linux Shell 数据安全/隐私保护
|
1天前
|
算法 Linux 开发者
深入探究Linux内核中的内存管理机制
本文旨在对Linux操作系统的内存管理机制进行深入分析,探讨其如何通过高效的内存分配和回收策略来优化系统性能。文章将详细介绍Linux内核中内存管理的关键技术点,包括物理内存与虚拟内存的映射、页面置换算法、以及内存碎片的处理方法等。通过对这些技术点的解析,本文旨在为读者提供一个清晰的Linux内存管理框架,帮助理解其在现代计算环境中的重要性和应用。
|
1天前
|
人工智能 算法 大数据
Linux内核中的调度算法演变:从O(1)到CFS的优化之旅###
本文深入探讨了Linux操作系统内核中进程调度算法的发展历程,聚焦于O(1)调度器向完全公平调度器(CFS)的转变。不同于传统摘要对研究背景、方法、结果和结论的概述,本文创新性地采用“技术演进时间线”的形式,简明扼要地勾勒出这一转变背后的关键技术里程碑,旨在为读者提供一个清晰的历史脉络,引领其深入了解Linux调度机制的革新之路。 ###
|
4天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
24 4
|
4天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
7天前
|
缓存 运维 Linux
深入探索Linux内核:CPU拓扑结构探测
【10月更文挑战第18天】在现代计算机系统中,CPU的拓扑结构对性能优化和资源管理至关重要。了解CPU的核心、线程、NUMA节点等信息,可以帮助开发者和系统管理员更好地调优应用程序和系统配置。本文将深入探讨如何在Linux内核中探测CPU拓扑结构,介绍相关工具和方法。
9 0
|
5天前
|
缓存 算法 Linux
Linux内核中的内存管理机制深度剖析####
【10月更文挑战第28天】 本文深入探讨了Linux操作系统的心脏——内核,聚焦其内存管理机制的奥秘。不同于传统摘要的概述方式,本文将以一次虚拟的内存分配请求为引子,逐步揭开Linux如何高效、安全地管理着从微小嵌入式设备到庞大数据中心数以千计程序的内存需求。通过这段旅程,读者将直观感受到Linux内存管理的精妙设计与强大能力,以及它是如何在复杂多变的环境中保持系统稳定与性能优化的。 ####
11 0
|
6月前
|
存储 监控 安全
《Linux 简易速速上手小册》第6章: 磁盘管理与文件系统(2024 最新版)
《Linux 简易速速上手小册》第6章: 磁盘管理与文件系统(2024 最新版)
65 1
|
3月前
|
存储 监控 Linux