Linux内核追踪(一):proc/sys/debugfs

简介: Linux内核追踪(一):proc/sys/debugfs

Linux内核追踪

最近因为需要,需要跟踪调试内核,但是这个玩意一直是在使用,我从来是不报错是不会研究日志的。

当然这样的习惯已经不能用戳字来形容了,是非常的差劲的行为。今天来学习学习内核里面几个非正规的文件系统,实现特定的功能。

本文的全部内容来自飞哥的—>《奔跑吧,linux内核》入门篇

1、前言

很多内核开发者最喜欢的调试工具之一是printk。

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

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

但是其实就是我们平时调试一些逻辑的时候,我想知道这个代码到这一步的状态和功能,那就在这里整个printf。这个是异曲同工之妙

那为什么有了prink还需要整这些呢,这是因为你打印吧,你得在内核编译运行之前固定,这就不动态。因为我内核的东西在用户态我是确定和看不到的。

2、proc

2.1 理论

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

**这个虚拟文件系统可以让用户和内核内部数据结构进行交互,**比如获取进程的有用信息、系统的有用信息等。可以查看某个进程的相关信息,也可以查看系统的信息,比如/proc/meminfo 用来查看内存的管理信息,/proc/cpuinfo用来观察CPU的信息。

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

如ps、top等很多shell命令正是从proc系统中读取信息,且更具可读性。

(原来这些命令是从这里来的,学习底层的东西会让你对很多事情的工作和原理有个了解,知其所以然)

2.2 实操

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

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

(这个玩意要是你不执行,它就直接创建在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指向该文件的操作函数。

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

<driver/char/misc.c>
static int __init misc_init(void)
{
  int err;
  #ifdef CONFIG_PROC_FS
  proc_create("misc", 0, NULL,&misc_proc_fops);
  #endif
}

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

static const struct file_operations misc_proc_fops = {
  .owner   = THIS_MODULE,
  .open  = misc_seq_open,
  .read  = seq_read,
  .llseek = seq_lseek,
  .release = seq_release,
};

3、sys

3.1 理论

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

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

(sys统一管理驱动设备?)

3.2 实操参考

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

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

其中,

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

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

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

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

<include/linux/sysfs.h>
struct attribute_group {
  const char    *name;
  umode_t      (*is_visible)(struct kobject *,
  struct attribute *, int);
  struct attribute  **attrs;
  struct bin_attribute  **bin_attrs;
  };

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

举个栗子

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

static int __init ksysfs_init(void){
kernel_kobj 
kobject_create_and_add("kernel", NULL);
error = sysfs_create_group(kernel_kobj,&kernel_attr_group);
return 0;
}

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

static struct attribute * kernel_attrs[] = {
&fscaps_attr.attr,
&uevent_seqnum_attr.attr,
&profiling_attr.attr,
NULL
};
static struct attribute_group kernel_attr_group = {
.attrs = kernel_attrs,
};

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

static ssize_t profiling_show(struct kobject *kobj,struct kobj_attribute *attr, char *buf){
  return sprintf(buf, "%d\n", prof_on);
}
static ssize_t profiling_store(struct kobject *kobj,struct kobj_attribute *attr,const char *buf, size_t count){
int ret;
profile_setup((char *)buf);
ret = profile_init();
return count;
}
KERNEL_ATTR_RW(profiling);

其中KERNEL_ATTR_RW宏定义如下。

#define KERNEL_ATTR_RO(_name) \
static struct kobj_attribute _name##_attr =__ATTR_RO(_name)
#define KERNEL_ATTR_RW(_name) \
static struct kobj_attribute _name##_attr =\
__ATTR(_name, 0644, _name##_show,_name##_store)

上面是/sys/kernel 的一个例子,Linux 内核源代码里还有很多设备驱动的例子。

4、debufs

4.1 理论

debugfs是一种用来调试内核的内存文件系统,内核开发者可以通过debugfs和用户空间交换数据,有点类似于前文提到的procfs和sysfs。debugfs文件系统也并不是存储在磁盘中,而是建立到内存中。

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

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

之前内核实现的procfs和sysfs可以达到这个目的,但是procfs是为了反映系统以及进程的状态信息sysfs用于Linux设备驱动模型,

把私有的调试信息加入这两个虚拟文件系统不太合适,因此内核多添加了一个虚拟文件系统,也就是debugfs。

所以说有了这个玩意。要知道为什么诞生的。

(到了这里你可能还会有点疑惑,什么东西啊,这个动态,我觉得就是配置参数,就是对于内核的东西可以通过这个写的方式去修改一些内核相关的参数与数据,然后达到我们的目的。调试调试那不得多试试。)

4.2 实操参考

debufs文件系统中有不少API函数可以使用,它们定义在include/linux/debugfs.h头文件中。

struct dentry *debugfs_create_dir(const char *name,struct dentry *parent)
void debugfs_remove(struct dentry *dentry)
struct dentry *debugfs_create_blob(const char *name, umode_t mode,struct dentry *parent,struct debugfs_blob_wrapper *blob)
struct dentry *debugfs_create_file(const char *name, umode_t mode,struct dentry *parent, void *data,const struct file_operations *fops)


目录
相关文章
|
4月前
|
安全 网络协议 Linux
深入理解Linux内核模块:加载机制、参数传递与实战开发
本文深入解析了Linux内核模块的加载机制、参数传递方式及实战开发技巧。内容涵盖模块基础概念、加载与卸载流程、生命周期管理、参数配置方法,并通过“Hello World”模块和字符设备驱动实例,带领读者逐步掌握模块开发技能。同时,介绍了调试手段、常见问题排查、开发规范及高级特性,如内核线程、模块间通信与性能优化策略。适合希望深入理解Linux内核机制、提升系统编程能力的技术人员阅读与实践。
477 1
|
4月前
|
Ubuntu Linux
Ubuntu 23.04 用上 Linux 6.2 内核,预计下放到 22.04 LTS 版本
Linux 6.2 带来了多项内容更新,修复了 AMD 锐龙处理器设备在启用 fTPM 后的运行卡顿问题,还增强了文件系统。
|
4月前
|
Ubuntu Linux
Ubuntu 23.10 现在由Linux内核6.3提供支持
如果你想在你的个人电脑上测试一下Ubuntu 23.10的最新开发快照,你可以从官方下载服务器下载最新的每日构建ISO。然而,请记住,这是一个预发布版本,所以不要在生产机器上使用或安装它。
|
4月前
|
传感器 监控 Ubuntu
10 月发布,Ubuntu 23.10 已升级到 Linux Kernel 6.3 内核
硬件方面,Linux 6.3 引入了在 HID 中引入了原生的 Steam Deck 控制器接口,允许罗技 G923 Xbox 版赛车方向盘在 Linux 上运行;改善 8BitDo Pro 2 有线控制器的行为;并为一系列华硕 Ryzen 主板添加传感器监控。
|
4月前
|
Ubuntu Linux
Ubuntu24.04LTS默认采用Linux 6.8内核,实验性版本可通过PPA获得
IT之家提醒,当下的 Ubuntu 23.10 也是一个“短期支持版本”,该版本将在今年 7 月终止支持,而今年 4 月推出的 Ubuntu 24.04 LTS 长期支持版本将获得 5 年的更新支持。
|
4月前
|
监控 Ubuntu Linux
什么Linux,Linux内核及Linux操作系统
上面只是简单的介绍了一下Linux操作系统的几个核心组件,其实Linux的整体架构要复杂的多。单纯从Linux内核的角度,它要管理CPU、内存、网卡、硬盘和输入输出等设备,因此内核本身分为进程调度,内存管理,虚拟文件系统,网络接口等4个核心子系统。
360 0
|
4月前
|
Web App开发 缓存 Rust
|
4月前
|
Ubuntu 安全 Linux
Ubuntu 发行版更新 Linux 内核,修复 17 个安全漏洞
本地攻击者可以利用上述漏洞,攻击 Ubuntu 22.10、Ubuntu 22.04、Ubuntu 20.04 LTS 发行版,导致拒绝服务(系统崩溃)或执行任意代码。
|
4月前
|
Ubuntu 机器人 物联网
Linux Ubuntu 22.04 LTS 测试版实时内核已可申请
请注意,在启用实时内核后您需要手动配置 grub 以恢复到原始内核。更多内容请参考: