Linux内核技术面试出现频率比较高问题???
-
Kdump工作原理?
-
在x86_64架构里函数参数是如何传递?
-
在X86_64构架当中,MOV指令和LEA指令有什么区别?
-
Softlockup/Hardlockup/Hung_task机制的实现原理是什么?
原文地址:深度剖析Linux内核性能调优与宕机解决方案 - 知乎 (zhihu.com)
一、解决x86_64宕机难题
- 在x86_64架构中解决宕机问题,大家可以搭建一个实战环境:
1.操作系统:Ubuntu 18.04
2.内核版本:Linux 4.12
3.处理器:Intel x86_64处理器
4.Kdump和Crash工具
- Kexec可以快速启动一个新的内核,它直接跳过bootloader或BIOS等引导程序的初始化阶段。通过这个特性可以让系统崩溃时快速切换到另一个备份的内核,第一个内核的内存就得到保留。第二个内核中可以对第一个内核产生的崩溃数据信息继续分析。通过如下图所示就更好理解Kdump工作原理。
-
我们在使用Kdump+Crash工具之前,大家必须要知道它们适用范围:
-
Linux运维工程师(服务器管理员)、Linux内核嵌入式开发工程师。Linux物理机或者Linux虚拟机。Kdump主要用来分析黑屏、没有响应、宕机等等。使用工具前提条件是系统能够热启动,内存中的内容不会丢失。
5、x86_64架构知识
-
通用寄存器
-
32位x86处理器支持8个32位的通用寄存器:EAX、EBX、ECX、EDX、ESI、EDI、ESP、EBP。32位的x86处理器还有6个16位段寄存器、1个32位EFLAGS寄存器及1个32位EIP寄存器。
-
64位的x86处理器通用寄存器扩展到16个。原来以E开头字母的寄存器换为R开头的字母。原E字母开头寄存器仍然可以使用,表示低32位寄存器,以R字母开头的寄存器表示64位,还新增R8-R15通用寄存器。
-
64位x86处理器寄存组织结构:
-
16个64位通用寄存器
-
1个RIP寄存器(指令指针)
-
1个64位RFLAGS寄存器
-
6个128位XMM寄存器
-
补充一下:
-
x86_64:RSP(SP寄存器),RBP(栈寄存器),RAX(临时寄存器)。平时我们所写函数代码调用的时候跟栈有什么关系,主要依赖栈的结构、RSP、RBP。比如函数调用关系main()-->FuncTest1()->FucnTest1(),在栈结构当中如何实现。
6、寻址方式
- 寻址指令(有两条常用的指令:MOV指令和LEA指令)。MOV指令:数据搬移指令。LEA指令:加载有效地址指令。
-
直接寻址(通过地址来实现):mov address,%rax
-
间接寻址(通过寄存器指定的地址加载值):MOV (%rax),%rbx
-
基址寻址(偏移量的值(可以为正数也可以为负数)和寄存器的值相加之后再用寻址):MOV 12(%rax),%rbx
-
LEA指令和MOV指令区别
-
LEA指令用来加载有效地址,而MOV指令用来搬移数据。
MOV 20(%rbp),%rax
C伪代码如下:
long *px=%rbp+20
%rax=*px
LEA 20(%rbp),%rax
%rax-%rbp+20
7、工程项目实战宕机案例分析如下(云服务器、线上服务器、嵌入式系统)
-
想到利用Crash工具来分析宕机问题
-
通过栈来获取参数或者局部变量的值
-
我们要分析和推导出来那个进程持有锁
-
我们要分析和推导出来那个进程在等待这个锁
具体案例源码分析如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define DECS_NAME "my_decs_dev"
struct mydecs_priv
{
struct device *dev;
struct miscdevice *miscdev;
struct mutex lock;
char *name;
};
static struct mydecs_priv *g_mydev;
/* 设计虚拟FIFO设备的缓冲区存储器 */
static char *device_buffer;
#define MAX_DEVICE_BUFFER_SIZE (100*PAGE_SIZE)
#define MYDEV_CMD_GET_BUFFSIZE 1
static int demodrv_open(struct inode*inode,struct file *file)
{
struct mydecs_priv *priv=g_mydev;
int major=MAJOR(inode->i_rdev);
int minor=MINOR(inode->i_rdev);
struct task_struct *task=current;
struct mm_struct *mm=task->mm;
down_read(&mm->mmap_sem);
printk("%s : major=%d,minor=%d,name=%s\n",__func__,major,priv->name);
return 0;
}