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)


目录
相关文章
|
7天前
|
安全 Linux 编译器
探索Linux内核的奥秘:从零构建操作系统####
本文旨在通过深入浅出的方式,带领读者踏上一段从零开始构建简化版Linux操作系统的旅程。我们将避开复杂的技术细节,以通俗易懂的语言,逐步揭开Linux内核的神秘面纱,探讨其工作原理、核心组件及如何通过实践加深理解。这既是一次对操作系统原理的深刻洞察,也是一场激发创新思维与实践能力的冒险。 ####
|
9天前
|
网络协议 Linux 调度
深入探索Linux操作系统的心脏:内核与系统调用####
本文旨在揭开Linux操作系统中最为核心的部分——内核与系统调用的神秘面纱,通过生动形象的语言和比喻,让读者仿佛踏上了一段奇妙的旅程,从宏观到微观,逐步深入了解这两个关键组件如何协同工作,支撑起整个操作系统的运行。不同于传统的技术解析,本文将以故事化的方式,带领读者领略Linux内核的精妙设计与系统调用的魅力所在,即便是对技术细节不甚了解的读者也能轻松享受这次知识之旅。 ####
|
6天前
|
缓存 算法 安全
深入理解Linux操作系统的心脏:内核与系统调用####
【10月更文挑战第20天】 本文将带你探索Linux操作系统的核心——其强大的内核和高效的系统调用机制。通过深入浅出的解释,我们将揭示这些技术是如何协同工作以支撑起整个系统的运行,同时也会触及一些常见的误解和背后的哲学思想。无论你是开发者、系统管理员还是普通用户,了解这些基础知识都将有助于你更好地利用Linux的强大功能。 ####
13 1
|
6天前
|
缓存 编解码 监控
深入探索Linux内核调度机制的奥秘###
【10月更文挑战第19天】 本文旨在以通俗易懂的语言,深入浅出地剖析Linux操作系统内核中的进程调度机制,揭示其背后的设计哲学与实现策略。我们将从基础概念入手,逐步揭开Linux调度策略的神秘面纱,探讨其如何高效、公平地管理系统资源,以及这些机制对系统性能和用户体验的影响。通过本文,您将获得关于Linux调度机制的全新视角,理解其在日常计算中扮演的关键角色。 ###
26 1
|
14天前
|
网络协议 Linux 芯片
Linux 内核 6.11 RC6 发布!
【10月更文挑战第12天】
77 0
Linux 内核 6.11 RC6 发布!
|
2月前
|
存储 安全 Linux
探索Linux操作系统的心脏:内核
在这篇文章中,我们将深入探讨Linux操作系统的核心—内核。通过简单易懂的语言和比喻,我们会发现内核是如何像心脏一样为系统提供动力,处理数据,并保持一切顺畅运行。从文件系统的管理到进程调度,再到设备驱动,我们将一探究竟,看看内核是怎样支撑起整个操作系统的大厦。无论你是计算机新手还是资深用户,这篇文章都将带你领略Linux内核的魅力,让你对这台复杂机器的内部运作有一个清晰的认识。
71 3
|
2月前
|
缓存 安全 Unix
Linux 内核黑客不可靠指南【ChatGPT】
Linux 内核黑客不可靠指南【ChatGPT】
|
2月前
|
Linux 开发者
Linux内核贡献成熟度模型 【ChatGPT】
Linux内核贡献成熟度模型 【ChatGPT】
|
2月前
|
网络协议 Ubuntu Linux
用Qemu模拟vexpress-a9 (三)--- 实现用u-boot引导Linux内核
用Qemu模拟vexpress-a9 (三)--- 实现用u-boot引导Linux内核
|
2月前
|
Linux
用clang编译Linux内核
用clang编译Linux内核