linux 调用栈 linux 栈大小的设置

分析linux内核崩溃信息

分析kernel比较关键的就是看三点:

1)内核会给出一个崩溃原因的猜测,这里是,CPU 0 Unable to handle kernel paging request at virtual address 00000000

2)看pc指针的值,这里是epc== 00000000

3)看调用栈Call Trace:[//可惜后面没给出来

通常是根据指针加上偏移值跟反汇编代码对照,找到出问题的指令。

这个panic的原因比较明显,应该是引用了空指针,试图执行0x00000000出的代码。

linux内核启动参数stacktrace如何使用

stacktrace是Linux内核提供的一种用于打印内核函数调用栈信息的方法。它在内核调试或应用程序故障定位时极为有用。本文将详细介绍如何使用Linux内核启动参数stacktrace来控制内核启动时是否立即输出函数调用栈信息。

在Linux内核中,可以通过dump_stack()函数获取并打印当前代码调用链信息。此外,通过内核启动参数stacktrace,可以控制内核在启动时是否立即输出函数调用栈信息。参数的使用方式为:

shell

stacktrace=[on|off]

若设置为on,系统将在启动时输出调用栈信息;设置为off则不输出。默认状态为off。

要使用该参数,有以下两种方法:

1.在引导加载程序的命令行中添加参数。

2.在内核启动命令行中添加参数。

例如,通过GRUB引导加载程序时,可编辑/boot/grub/grub.cfg文件,加入如下参数:

shell

linux/boot/vmlinuz--generic root=/dev/sda1 stacktrace=on

initrd/boot/initrd.img--generic

设置stacktrace=on后,系统会在启动过程中显示内核函数调用栈信息。例如:

shell

[ 0.579421] Call Trace:

[ 0.579421] nvidia_init_module+0x54/0x620 [nvidia]

...

这些信息对内核代码调试或程序异常排查非常有帮助,能快速定位故障点。接下来,我们将探讨stacktrace的常见使用场景、注意事项以及如何合理利用该功能。

**使用场景**:

1.**内核代码调试**:在调试复杂且难以定位的内核代码时,stacktrace能快速提供函数调用链信息,帮助快速找到故障点。

2.**程序异常排查**:当应用程序遇到异常或崩溃时,利用stacktrace可以定位出错的函数,从而分析和解决故障。

3.**性能优化**:通过查看函数调用信息,识别执行时间长或调用次数多的函数,有助于进行代码优化,提升程序效率。

**注意事项**:

1.**仅在内核启动时生效**:stacktrace参数的设置仅在内核启动阶段有效,运行时无法更改。

2.**输出信息量大**:大量输出可能影响系统性能,需合理控制输出范围和行数。

3.**保护敏感信息**:在使用stacktrace时,应避免泄露敏感数据,如用户隐私信息或密码。

4.**内存占用**:开启stacktrace可能导致内存使用增加,需要合理限制输出以防止系统过载。

总之,stacktrace是内核调试和故障定位的有力工具。正确使用stacktrace参数,结合内核启动时的信息输出,能显著提高开发和维护效率。

Linux 中断( IRQ / softirq )基础:原理及内核实现

中断(IRQ),尤其是软中断(softirq)的广泛用途之一是网络数据包的接收与发送,但其应用场景并非单一。本文将全面整理中断(IRQ)与软中断(softirq)的基础知识,这些内容与网络数据包处理虽无直接联系,但整理本文旨在更深入地理解网络数据包处理机制。

什么是中断?

CPU通过时分复用处理多任务,其中包括硬件任务,如磁盘读写、键盘输入,以及软件任务,如网络数据包处理。CPU在任何时刻只能执行一个任务。当某个硬件或软件任务当前未被执行,但希望CPU立即处理时,会向CPU发送中断请求——希望CPU暂停手头工作,优先服务“我”。中断以事件形式通知CPU,因此常看到“在XX条件下会触发XX中断事件”的表述。

中断分为两类:

管理中断的设备:Advanced Programmable Interrupt Controller(APIC)。

硬中断的中断处理流程

中断随时发生,处理流程如下:

Maskable and non-maskable

Maskable interrupts在x64_64上可以通过sti/cli指令来屏蔽(关闭)和恢复:

在屏蔽期间,这种类型的中断不会触发新的中断事件。大部分IRQ都属于这种类型。例如,网卡的收发包硬件中断。

Non-maskable interrupts不可屏蔽,因此属于更高优先级的类型。

问题:执行速度与逻辑复杂性之间的矛盾

IRQ处理器的两个特点如下:

存在内在矛盾。

解决方式:中断的推迟处理(deferred interrupt handling)

传统解决方式是将中断处理分为两部分:

这种方式称为中断的推迟处理或延后处理。现在已是一个通用术语,涵盖各种推迟执行中断处理的方式。中断分为两部分处理:

在Linux中,有三种推迟中断(deferred interrupts):

具体细节将在后续介绍。

软中断与软中断子系统

软中断是内核子系统的一部分:

每个CPU上会初始化一个ksoftirqd内核线程,负责处理各种类型的softirq中断事件;

使用cgroup ls或ps-ef都能看到:

软中断事件的handler提前注册到softirq子系统,注册方式为open_softirq(softirq_id, handler)

例如,注册网卡收发包(RX/TX)软中断处理函数:

软中断占用了CPU的总开销:可以使用top查看,第三行倒数第二个指标是系统的软中断开销(si字段):

Linux内核源码分析学习地址:ke.qq.com/course/403254...

【文章福利】小编推荐自己的Linux内核源码分析交流群:【点击1095678385加入】整理了一些个人觉得比较好的学习书籍、视频资料共享在群文件里面,有需要的可以自行添加哦!

主处理

smpboot.c类似于事件驱动的循环,会调度ksoftirqd线程执行pending的软中断。ksoftirqd内部会进一步调用到__do_softirq,

避免软中断占用过多CPU

软中断的潜在影响:推迟执行的部分(如softirq)可能会占用较长时间,在这段时间内,用户空间线程只能等待。反映在top中,si占比。

不过softirq调度循环对此有所改进,通过budget机制来避免softirq占用过多CPU时间。

硬中断-软中断调用栈

softirq是一种推迟中断处理机制,将IRQ的大部分处理逻辑推迟在这里执行。有两条路径都会执行到softirq主处理逻辑__do_softirq():

1、CPU调度到ksoftirqd线程时,会执行到__do_softirq();

2、每次IRQ handler退出时:do_IRQ()->...

do_IRQ是内核中主要的IRQ处理方式。它执行结束时,会调用exiting_irq(),这会展开成irq_exit()。后者会检查是否pending有softirq,如果有,则唤醒:

进而会使CPU执行到__do_softirq。

软中断触发执行的步骤

总结,每个软中断会经过以下阶段:

以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。

需要注意的是,虽然IRQ handler所做的工作很少,但处理这个包的softirq和IRQ在同一CPU上运行。这意味着,如果大量的包都放在同一个RX队列,虽然IRQ开销可能不多,但该CPU仍然会非常繁忙,都花费在softirq上。解决方式:RPS。它不会降低延迟,只是将包重新分配:RXQ->CPU。

三种推迟执行方式(softirq/tasklet/workqueue)

提到,Linux中的三种推迟中断执行方式:

其中:

前面已经看到,Linux在每个CPU上创建了一个ksoftirqd内核线程。

softirqs是在Linux内核编译时确定的,例如网络收包对应的NET_RX_SOFTIRQ软中断。因此是一种静态机制。如果想添加一种新softirq类型,需要修改并重新编译内核。

内部组织

内部由一个数组(或称为向量)管理,每个软中断号对应一个softirq handler。数组与注册:

在5.10中所有类型的softirq:

也就是在cat/proc/softirqs看到的哪些。

触发(唤醒)softirq

以收包软中断为例,IRQ handler并不执行NAPI,只是触发它,在内部会执行到raiseNET_RX_SOFTIRQ;真正的执行在softirq,会调用网卡的poll()方法收包。IRQ handler中会调用napi_schedule(),然后启动NAPI poll()。

如果对内核源码有一定了解,会发现softirq使用非常有限,原因之一是它是静态编译的,依赖内置的ksoftirqd线程来调度内置的9种softirq。如果想添加一种新功能,就得修改并重新编译内核,开发成本很高。

实际上,实现推迟执行的更常用方式是tasklet。它构建在softirq机制之上,具体来说就是使用了两种softirq:

换句话说,tasklet是在运行时(runtime)创建和初始化的softirq,

内核软中断子系统初始化了两个per-cpu变量:

tasklet再执行针对list的循环:

tasklet在内核中的使用非常广泛。不过,后面又出现了第三种方式:workqueue。

这也是一种推迟执行机制,与tasklet有些相似,但有显著不同。

使用场景

简而言之,workqueue子系统提供了一个接口,通过该接口可以创建内核线程来处理从其他地方enqueue过来的任务。这些内核线程称为worker threads,内置的per-cpu worker threads:

结构体

kworker线程调度workqueues,原理与ksoftirqd线程调度softirqs类似。然而,我们可以为workqueue创建新的线程,而softirq则不行。

参考资料引用链接

[1]

中断与中断处理:0xax.gitbooks.io/linux-...

作者:赵亚楠原文:arthurchiao.art/blog/li...来源:云原生实验室

阅读剩余
THE END