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)


目录
相关文章
|
9天前
|
算法 Linux 调度
深入理解Linux内核调度器:从基础到优化####
本文旨在通过剖析Linux操作系统的心脏——内核调度器,为读者揭开其高效管理CPU资源的神秘面纱。不同于传统的摘要概述,本文将直接以一段精简代码片段作为引子,展示一个简化版的任务调度逻辑,随后逐步深入,详细探讨Linux内核调度器的工作原理、关键数据结构、调度算法演变以及性能调优策略,旨在为开发者与系统管理员提供一份实用的技术指南。 ####
41 4
|
13天前
|
缓存 算法 Linux
深入理解Linux内核调度器:公平性与性能的平衡####
真知灼见 本文将带你深入了解Linux操作系统的核心组件之一——完全公平调度器(CFS),通过剖析其设计原理、工作机制以及在实际系统中的应用效果,揭示它是如何在众多进程间实现资源分配的公平性与高效性的。不同于传统的摘要概述,本文旨在通过直观且富有洞察力的视角,让读者仿佛亲身体验到CFS在复杂系统环境中游刃有余地进行任务调度的过程。 ####
33 6
|
3天前
|
算法 Linux 开发者
Linux内核中的锁机制:保障并发控制的艺术####
本文深入探讨了Linux操作系统内核中实现的多种锁机制,包括自旋锁、互斥锁、读写锁等,旨在揭示这些同步原语如何高效地解决资源竞争问题,保证系统的稳定性和性能。通过分析不同锁机制的工作原理及应用场景,本文为开发者提供了在高并发环境下进行有效并发控制的实用指南。 ####
|
11天前
|
缓存 资源调度 安全
深入探索Linux操作系统的心脏——内核配置与优化####
本文作为一篇技术性深度解析文章,旨在引领读者踏上一场揭秘Linux内核配置与优化的奇妙之旅。不同于传统的摘要概述,本文将以实战为导向,直接跳入核心内容,探讨如何通过精细调整内核参数来提升系统性能、增强安全性及实现资源高效利用。从基础概念到高级技巧,逐步揭示那些隐藏在命令行背后的强大功能,为系统管理员和高级用户打开一扇通往极致性能与定制化体验的大门。 --- ###
38 9
|
10天前
|
缓存 负载均衡 Linux
深入理解Linux内核调度器
本文探讨了Linux操作系统核心组件之一——内核调度器的工作原理和设计哲学。不同于常规的技术文章,本摘要旨在提供一种全新的视角来审视Linux内核的调度机制,通过分析其对系统性能的影响以及在多核处理器环境下的表现,揭示调度器如何平衡公平性和效率。文章进一步讨论了完全公平调度器(CFS)的设计细节,包括它如何处理不同优先级的任务、如何进行负载均衡以及它是如何适应现代多核架构的挑战。此外,本文还简要概述了Linux调度器的未来发展方向,包括对实时任务支持的改进和对异构计算环境的适应性。
31 6
|
11天前
|
缓存 Linux 开发者
Linux内核中的并发控制机制:深入理解与应用####
【10月更文挑战第21天】 本文旨在为读者提供一个全面的指南,探讨Linux操作系统中用于实现多线程和进程间同步的关键技术——并发控制机制。通过剖析互斥锁、自旋锁、读写锁等核心概念及其在实际场景中的应用,本文将帮助开发者更好地理解和运用这些工具来构建高效且稳定的应用程序。 ####
30 5
|
11天前
|
算法 Unix Linux
深入理解Linux内核调度器:原理与优化
本文探讨了Linux操作系统的心脏——内核调度器(Scheduler)的工作原理,以及如何通过参数调整和代码优化来提高系统性能。不同于常规摘要仅概述内容,本摘要旨在激发读者对Linux内核调度机制深层次运作的兴趣,并简要介绍文章将覆盖的关键话题,如调度算法、实时性增强及节能策略等。
|
12天前
|
存储 监控 安全
Linux内核调优的艺术:从基础到高级###
本文深入探讨了Linux操作系统的心脏——内核的调优方法。文章首先概述了Linux内核的基本结构与工作原理,随后详细阐述了内核调优的重要性及基本原则。通过具体的参数调整示例(如sysctl、/proc/sys目录中的设置),文章展示了如何根据实际应用场景优化系统性能,包括提升CPU利用率、内存管理效率以及I/O性能等关键方面。最后,介绍了一些高级工具和技术,如perf、eBPF和SystemTap,用于更深层次的性能分析和问题定位。本文旨在为系统管理员和高级用户提供实用的内核调优策略,以最大化Linux系统的效率和稳定性。 ###
|
11天前
|
Java Linux Android开发
深入探索Android系统架构:从Linux内核到应用层
本文将带领读者深入了解Android操作系统的复杂架构,从其基于Linux的内核到丰富多彩的应用层。我们将探讨Android的各个关键组件,包括硬件抽象层(HAL)、运行时环境、以及核心库等,揭示它们如何协同工作以支持广泛的设备和应用。通过本文,您将对Android系统的工作原理有一个全面的认识,理解其如何平衡开放性与安全性,以及如何在多样化的设备上提供一致的用户体验。
|
14天前
|
Linux 数据库
Linux内核中的锁机制:保障并发操作的数据一致性####
【10月更文挑战第29天】 在多线程编程中,确保数据一致性和防止竞争条件是至关重要的。本文将深入探讨Linux操作系统中实现的几种关键锁机制,包括自旋锁、互斥锁和读写锁等。通过分析这些锁的设计原理和使用场景,帮助读者理解如何在实际应用中选择合适的锁机制以优化系统性能和稳定性。 ####
31 6