Linux tracing之基于uprobe/kprobe的调试调优浅析

news2024/10/6 4:01:06

经过长期的发展, kprobes/uprobes 机制在事件(events)的基础上分别为内核态和用户态提供了追踪调试的功能, 这也构成了 tracepoint 机制的基础, 后期的很多工具, 比如 perf_eventsftrace 等都是在其基础上演化而来. 参考由 Brendan Gregg 提供的资料来看, kprobes/uprobes 在 Linux 动态追踪层面起到了基石的作用, 如下所示:

uprobe与krobe对应,动态附加到用户态调用函数的切入点称为uprobe,相比如kprobe 内核函数的稳定性,uprobe 的函数由开发者定义。uprobe是用户态的探针,它和kprobe是相对应的,kprobe是内核态的探针。uprobe需要制定用户态探针在执行文件中的位置,插入探针的原理和kprobe类似。

下面是对uprobe使用方法的简单介绍。比如跟踪下面程序中的callee函数调用:

#include <stdio.h>

int callee(void)
{
    printf("hello world.\n");

    return 0;
}

int main(void)
{    
    callee();

    return 0;
}

Makefile

分别编译地址加载无关和地址相关两个版本的应用程序,分别抓取其PROBE结果。

all:
	gcc -O0 -no-pie -fno-pic -g main.c -o main-nopie
	gcc -O0 -g main.c -o main
clean:
	rm -fr main main-nopie

增加一个新的uprobe event,命令如下(在可执行文件main的0x63a偏移处增加一个uprobe探针),当callee函数被调用时,截获调用事件信息:

$ readelf -s main|grep callee
    64: 000000000000063a    23 FUNC    GLOBAL DEFAULT   14 callee
$ 
# echo 'p:callee /home/zlcao/uprobe/main:0x63a' > /sys/kernel/debug/tracing/uprobe_events

增加一个返回事件信息:

echo 'r:callee_ret /home/zlcao/uprobe/main:0x63a' >> /sys/kernel/debug/tracing/uprobe_events

之后使用如下命令查看注册的EVENT事件

cat /sys/kernel/debug/tracing/uprobe_events

定义以后,使能所有的events:

echo 1 > /sys/kernel/debug/tracing/events/uprobes/enable

之后执行测试用例,执行完毕后,通过如下命令查看探测记录。

cat /sys/kernel/debug/tracing/trace

可以看到,callee函数的调用和返回事件都被触发了,输出显示给我们uprobe被触发时:main-27731、程序PC 0x55f1b22cb63a,uretprobe被触发时:PC从函数入口0x55f1b22cb63a返回0x55f1b22cb65a。

之后,通过如下命令关闭探测。

echo 0 > /sys/kernel/debug/tracing/events/uprobes/enable

最后,使用如下命令清除掉所有注册的events。

echo > /sys/kernel/debug/tracing/uprobe_events

添加探测点的步骤比较麻烦,perf很贴心地添加了一键添加探测点的功能,只需要执行一个简单的命令即可:

# perf probe -x ./main-nopie callee
# perf probe -x ./main-nopie callee%return

之后使能探测,运行用例。

# echo 1 > /sys/kernel/debug/tracing/events/probe_main/enable
# ./main-nopie

或者直接执行如下指令运行:

root@zlcao-Vostro-3268:/home/zlcao/uprobe# perf record -e probe_main:callee -aR ./main-nopie 
hello world.
[ perf record: Woken up 1 times to write data ]
[ perf record: Captured and wrote 1.537 MB perf.data (1 samples) ]
root@zlcao-Vostro-3268:/home/zlcao/uprobe# 

使用命令perf report查看生成的perf.data文件

查看当前所有的EVENT 探测点

root@zlcao-Vostro-3268:/home/zlcao/uprobe# perf probe -l
  kprobes:myprobe      (on _do_fork)
  kprobes:myretprobe   (on _do_fork%return with arg1)
  probe_libc:memcpy    (on __new_memcpy_ifunc@x86_64/multiarch/memcpy.c in /lib/x86_64-linux-gnu/libc-2.27.so)
  probe_main:callee    (on callee@/home/zlcao/uprobe/main.c in /home/zlcao/uprobe/main-nopie)
  probe_main:callee__return (on callee%return@/home/zlcao/uprobe/main.c in /home/zlcao/uprobe/main-nopie)
root@zlcao-Vostro-3268:/home/zlcao/uprobe# 

PIE和NO-PIE应用的区别

通过上面的例子可以看到,默认编译的PIE应用和非PIE应用都可以被事件机制探测调试,那么它们的区被是什么呢?通过下面几幅图可以看出,PIE应用的符号地址是相对的,加载地址是随机的,而非PIE应用的加载地址和运行地址完全是由应用符号表提供的,运行时加载器必须遵守,不能更改。

通过traceing_pipe查看探测结果,/sys/kernel/debug/tracing/trace_pipe文件为同步阻塞式读取文件,执行cat /sys/kernel/debug/tracing/trace_pipe后控制台处于阻塞状态,当运行测试用例时,实时更新探测结果。

通过内核模块截获uprobe事件
#include <linux/module.h>
#include <linux/ptrace.h>
#include <linux/uprobes.h>
#include <linux/namei.h>
#include <linux/moduleparam.h>

MODULE_AUTHOR("john doe");
MODULE_LICENSE("GPL v2");

static char *filename;
module_param(filename, charp, S_IRUGO);

static long offset;
module_param(offset, long, S_IRUGO);

static int handler_pre(struct uprobe_consumer *self, struct pt_regs *regs)
{
	pr_info("handler: arg0 = %d arg1 =%d \n", (int)regs->di, (int)regs->si);
	return 0;
}

static int handler_ret(struct uprobe_consumer *self,
                       unsigned long func,
                       struct pt_regs *regs)
{
	pr_info("ret_handler ret = %d \n", (int)regs->ax);
	return 0;
}

static struct uprobe_consumer uc = {
	.handler = handler_pre,
	.ret_handler = handler_ret,
};


static struct inode *inode;

static int __init uprobe_init(void)
{
	struct path path;
	int ret;

	ret = kern_path(filename, LOOKUP_FOLLOW, &path);
	if (ret < 0) {
		pr_err("kern_path failed, returned %d\n", ret);
		return ret;
	}

	inode = igrab(path.dentry->d_inode);
	path_put(&path);

	ret = uprobe_register(inode, offset, &uc);
	if (ret < 0) {
		pr_err("register_uprobe failed, returned %d\n", ret);
		return ret;
	}

	return 0;
}

static void __exit uprobe_exit(void)
{
	uprobe_unregister(inode, offset, &uc);
}

module_init(uprobe_init);
module_exit(uprobe_exit);

测试用例和MAKEFILE

#include <stdio.h>

int callee(int a, int b)
{
    printf("hello world %d.\n", a + b);

    return a+b;
}

int main(void)
{    
    callee(8, 9);

    return 0;
}
ifneq ($(KERNELRELEASE),)
obj-m:=uprobe.o
else
KERNELDIR:=/lib/modules/$(shell uname -r)/build
PWD:=$(shell pwd)
all:
	$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
	gcc -O0 -no-pie -fno-pic -g main.c -o main-nopie
	gcc -O0 -g main.c -o main
 
clean:
	rm -rf *.o *.mod.c *.mod.o *.ko *.symvers *.mod .*.cmd *.order
format:
	astyle --options=linux.astyle *.[ch]
endif

测试

uprobe原理

uprobe基于int3 debug指令实现,以下是回调CALLSTACK。

设置uprobe,通过GDB查看callee函数入口,发现其指令已经变为INT3。

探测过程如下图所示,指定位置上的指令,头部修改为软件中断指令(同时原指令存档他处):

  1. 当执行到该位置时,触发软件中断,陷入内核
  2. 在内核,执行以 注入的 Handler
  3. 单步执行原指令
  4. 修正寄存器和栈,回到原有指令流

在这里插入图片描述

如果指令地址对应的页面还没有映射,会通过:

uprobe_write_opcode->get_user_pages_remote->__get_user_pages_locked->__get_user_pages->faultin_page->handle_mm_fault ...

进行PAGE FAULT的处理,之后在写入INT3指令。

Kprobe实践

root@zlcao-Vostro-3268:~# echo 'p:myprobe _do_fork' > /sys/kernel/debug/tracing/kprobe_events
root@zlcao-Vostro-3268:~# echo 'r:myretprobe _do_fork $retval' >> /sys/kernel/debug/tracing/kprobe_events
root@zlcao-Vostro-3268:~# echo 1 > /sys/kernel/debug/tracing/events/kprobes/myprobe/enable
root@zlcao-Vostro-3268:~# echo 1 > /sys/kernel/debug/tracing/events/kprobes/myretprobe/enable
root@zlcao-Vostro-3268:~# cat /sys/kernel/debug/tracing/kprobe_events
p:kprobes/myprobe _do_fork
r4:kprobes/myretprobe _do_fork arg1=$retval
root@zlcao-Vostro-3268:~# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 4/4   #P:4
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
            bash-8783    [002] .... 150455.854930: myprobe: (_do_fork+0x0/0x3e0)
            bash-8783    [002] d... 150455.855143: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2322
            bash-8783    [001] .... 150464.091940: myprobe: (_do_fork+0x0/0x3e0)
            bash-8783    [001] d... 150464.092151: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2323
root@zlcao-Vostro-3268:~# cat /sys/kernel/debug/tracing/trace
# tracer: nop
#
# entries-in-buffer/entries-written: 80/80   #P:4
#
#                                _-----=> irqs-off
#                               / _----=> need-resched
#                              | / _---=> hardirq/softirq
#                              || / _--=> preempt-depth
#                              ||| /     delay
#           TASK-PID     CPU#  ||||   TIMESTAMP  FUNCTION
#              | |         |   ||||      |         |
            bash-8783    [002] .... 150455.854930: myprobe: (_do_fork+0x0/0x3e0)
            bash-8783    [002] d... 150455.855143: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2322
            bash-8783    [001] .... 150464.091940: myprobe: (_do_fork+0x0/0x3e0)
            bash-8783    [001] d... 150464.092151: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2323
  gsd-media-keys-2620    [003] .... 150466.748575: myprobe: (_do_fork+0x0/0x3e0)
  gsd-media-keys-2620    [003] d... 150466.749024: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2324
  gsd-media-keys-8996    [001] .... 150466.749133: myprobe: (_do_fork+0x0/0x3e0)
  gsd-media-keys-8996    [001] d... 150466.749647: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2325
  gsd-media-keys-2620    [003] .... 150466.750599: myprobe: (_do_fork+0x0/0x3e0)
  gsd-media-keys-2620    [003] d... 150466.750610: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2326
           gdbus-2656    [000] .... 150466.750718: myprobe: (_do_fork+0x0/0x3e0)
           gdbus-2656    [000] d... 150466.750743: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2327
  gnome-terminal-8997    [001] .... 150466.797071: myprobe: (_do_fork+0x0/0x3e0)
  gnome-terminal-8997    [001] d... 150466.797090: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2328
  gnome-terminal-8997    [001] .... 150466.797825: myprobe: (_do_fork+0x0/0x3e0)
  gnome-terminal-8997    [001] d... 150466.798023: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2329
 gnome-terminal.-9001    [003] .... 150466.812982: myprobe: (_do_fork+0x0/0x3e0)
 gnome-terminal.-9001    [003] d... 150466.813005: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232a
 gnome-terminal.-9001    [003] .... 150466.813730: myprobe: (_do_fork+0x0/0x3e0)
 gnome-terminal.-9001    [003] d... 150466.813742: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232b
 gnome-terminal.-9001    [003] .... 150466.834816: myprobe: (_do_fork+0x0/0x3e0)
 gnome-terminal.-9001    [003] d... 150466.834839: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232c
 gnome-terminal--3324    [000] .... 150466.852493: myprobe: (_do_fork+0x0/0x3e0)
 gnome-terminal--3324    [000] d... 150466.852528: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232d
 gnome-terminal--3324    [000] .... 150466.852532: myprobe: (_do_fork+0x0/0x3e0)
 gnome-terminal--3324    [000] d... 150466.852544: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232e
            pool-9006    [003] .... 150466.853913: myprobe: (_do_fork+0x0/0x3e0)
            pool-9006    [003] d... 150466.854893: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x232f
 xdg-desktop-por-2796    [003] .... 150466.858576: myprobe: (_do_fork+0x0/0x3e0)
 xdg-desktop-por-2796    [003] d... 150466.858605: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2330
 xdg-desktop-por-2796    [003] .... 150466.858609: myprobe: (_do_fork+0x0/0x3e0)
 xdg-desktop-por-2796    [003] d... 150466.858617: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2331
            bash-9007    [001] .... 150466.859319: myprobe: (_do_fork+0x0/0x3e0)
            bash-9007    [001] d... 150466.859386: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2332
            bash-9010    [002] .... 150466.859621: myprobe: (_do_fork+0x0/0x3e0)
            bash-9010    [002] d... 150466.859678: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2334
        lesspipe-9012    [001] .... 150466.860217: myprobe: (_do_fork+0x0/0x3e0)
        lesspipe-9012    [001] d... 150466.860247: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2335
        lesspipe-9012    [002] .... 150466.861003: myprobe: (_do_fork+0x0/0x3e0)
        lesspipe-9012    [002] d... 150466.861039: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2336
        lesspipe-9014    [003] .... 150466.864089: myprobe: (_do_fork+0x0/0x3e0)
        lesspipe-9014    [003] d... 150466.864147: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2337
            bash-9007    [001] .... 150466.865518: myprobe: (_do_fork+0x0/0x3e0)
            bash-9007    [001] d... 150466.865572: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2338
            bash-9016    [002] .... 150466.865788: myprobe: (_do_fork+0x0/0x3e0)
            bash-9016    [002] d... 150466.865841: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x2339
            bash-9007    [000] .... 150467.633920: myprobe: (_do_fork+0x0/0x3e0)
            bash-9007    [000] d... 150467.634127: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x233a
             vim-9018    [000] .... 150467.760802: myprobe: (_do_fork+0x0/0x3e0)
             vim-9018    [000] d... 150467.760936: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x233b
            bash-9019    [001] .... 150467.761927: myprobe: (_do_fork+0x0/0x3e0)
            bash-9019    [001] d... 150467.761959: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x233c
             vim-9018    [000] .... 150468.007578: myprobe: (_do_fork+0x0/0x3e0)
             vim-9018    [000] d... 150468.007916: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x233d
             vim-9018    [000] .... 150468.069323: myprobe: (_do_fork+0x0/0x3e0)
             vim-9018    [000] d... 150468.069689: myretprobe: (__x64_sys_clone+0x84/0xb0 <- _do_fork) arg1=0x233e


参考资料

Linux内核文档,Documentation/trace/uprobetracer.rst

Uprobe-tracer: Uprobe-based Event Tracing — The Linux Kernel documentation

Linux uprobe: User-Level Dynamic Tracing

在kernel中如何实现应用层程序执行时候的指令监控和打印 - 简书

Linux 系统动态追踪技术介绍 | arstercz’s blog

Linux K/Uprobe 使用指南 · GitBook

深入ftrace uprobe原理和功能介绍_uprobe 原理_奇小葩的博客-CSDN博客

结束

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Minecraft我的世界服务器搭建之Linux系统,我的世界服务器推荐

Minecraft 是一个流行的沙箱独立游戏&#xff0c;由瑞典程序员 Markus “Notch” Perssion 首先创造&#xff0c;后来由 Mojang 开发并发布。这是一款关于打碎和放置砖块的游戏。首先&#xff0c;人们建造建筑物来抵抗夜晚的怪物&#xff0c;随着游戏的发展&#xff0c;玩家一起…

Spark Stream操作Kafka总结

kafka集群搭建 搭建参考 https://www.toutiao.com/article/6496743889053942286/?log_fromd5d6394cf75d_1687599146327 zk下载位置 国内&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/apache/zookeeper/ 国外&#xff1a;Apache ZooKeeper kafka位置 国内&#xff…

Kubernetes(k8s)容器编排Pod介绍和使用

目录 1 Pod 特点1.1 网络1.2 存储 2 使用方式2.1 自主式Pod2.2 控制器管理的Pod 3 自主运行Pod3.1 创建资源清单3.1.1 参数描述 3.2 创建Pod3.3 Pod操作3.3.1 查看Pod列表3.3.2 查看描述信息3.3.3 访问pod3.3.4 删除Pod 4 控制器运行Pod4.1 创建资源清单4.2 参数描述4.2.1 Repl…

【IDEA】Directory创建多级目录的正确写法

在resource下创建包的时候&#xff0c;右键resourcenew的时候并没有Package,只有Directory 我们也可以用Directory创建包&#xff0c;但写法与在Package下创建包的写法会不一样 例如&#xff1a; 在directory创建包 我们在去看文件的时候 如果是用&#xff08; com.dao.m…

【数据结构】树以及堆的讲解

(这里写自定义目录标题) 提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、树的概念&#xff1f;二、树的表示方法三、树的实际应用四、二叉树概念以及结构1.概念2.特殊的二叉树3.二叉树的性质4.二叉树的存储…

指针与数组--动态数组(2)[1、长度可变的一维动态数组 2、长度可变的二维动态数组]

目录 一、长度可变的一维动态数组 二、长度可变的二维动态数组 由上篇文章的理论&#xff0c;接下来使用例题来阐述。 一、长度可变的一维动态数组 例题1、编程输入某班学生的某门课成绩&#xff0c;计算并输出平均值。学生人数由键盘输入。 #include <stdio.h> #i…

Apache服务器

文章目录 Apache服务器Linux安装ApacheApache文件结构Apache主配置文件案例 配置一台Web服务器 启动用户的个人网站虚拟主机的设定基于IP的虚拟主机基于域名的虚拟主机基于端口的虚拟主机 rewrite重写rewrite使用详解使用案例 域名跳转单个域名跳转多个域名跳转 status状态页ap…

“插入排序:小数据量排序的王者“

文章目录 &#x1f50d;什么是插入排序&#xff1f;&#x1f511;插入排序的优缺点&#x1f680;实现插入排序 &#x1f50d;什么是插入排序&#xff1f; 插入排序是一种简单的排序算法&#xff0c;它的基本思想是&#xff1a;将待排序的元素&#xff0c;从第二个元素开始&…

阿里架构师整理的Java经典面试题1220道(附答案)

学习如逆水行舟&#xff0c;尤其是 IT 行业有着日新月异的节奏&#xff0c;我们更要抓紧每一次可以学习和进步的机会。所以&#xff0c;没有撤退可言 即使是面试跳槽&#xff0c;那也是一个学习的过程。只有全面的复习&#xff0c;才能让我们更好的充实自己&#xff0c;武装自…

内网隧道代理技术(五)之 Netcat反弹Shell

Netcat反弹Shell Netcat简称NC,是一个简单、可靠的网络工具,被誉为网络界的瑞士军刀。通NC可以进行端口扫描、反弹Shell、端口监听和文件传输等操作,常用参数如下&#xff1a; 参数作用-c指定连接后要执行的shell命令-e指定连接后要执行的文件名-k配置 Socket一直存活(若不想…

一文了解远程桌面连接

一文了解远程桌面连接 一、引言1.1、远程桌面连接的概述1.2、远程桌面连接的应用场景 二、远程桌面连接的基本原理2.1、远程桌面连接的工作方式2.2、远程桌面连接的安全性 三、远程桌面连接的实现方法3.1、Windows自带的远程桌面连接3.2、第三方远程桌面连接工具 四、远程桌面连…

一阶低通滤波器(CODESYS FC和FB应用介绍)

一阶RC低通滤波器详细算法介绍请参看下面文章链接: PLC信号处理系列之一阶低通(RC)滤波器算法_plc计算滤波频率_RXXW_Dor的博客-CSDN博客1、先看看RC滤波的优缺点 优点:采用数字滤波算法来实现动态的RC滤波,则能很好的克服模拟滤波器的缺点; 1、在模拟常数要求较大的场合这…

数据挖掘——甘肃省县(区)域农业综合实力研究(论文)

《数据挖掘与分析》课程论文 题目&#xff1a;甘肃省县&#xff08;区&#xff09;域农业综合实力研究 xx学院xx专业xx班&#xff1a;xx 2023年6月 甘肃省县&#xff08;区&#xff09;域农业综合实力研究 xx (xx学院 xx学院) 摘要&#xff1a;本文主要研究甘肃省各县&#…

C语言数组指针和指针数组

文章目录 1 数组指针和指针数组的区别2 数组首地址和数组首元素地址的区别参考 1 数组指针和指针数组的区别 对指针数组和数组指针的概念&#xff0c;相信很多C程序员都会混淆。下面通过两个简单的语句来分析一下二者之间的区别&#xff0c;示例代码如下所示&#xff1a; int…

C/C++的发展历程和未来趋势

文章目录 C/C的起源C/C的应用C/C开发的工具C/C未来趋势 C/C的起源 C语言 C语言是一种通用的高级编程语言&#xff0c;由美国计算机科学家Dennis Ritchie在20世纪70年代初期开发出来。起初&#xff0c;C语言是作为操作系统UNIX的开发语言而创建的。C语言的设计目标是提供一种功…

虚拟文件系统的数据结构

文章目录 虚拟文件系统的数据结构超级快挂载描述符文件系统类型索引节点目录项文件的打开实例和打开文件表 虚拟文件系统的数据结构 虽然不同文件系统类型的物理结构不同&#xff0c;但是虚拟文件系统定义了一套统一的数据结构。 &#xff08;1&#xff09;超级块。文件系统的…

【网络2】MII MDC/MDIO

文章目录 1.MII&#xff1a;ISO网络模型中物理层&#xff08;phy&#xff09;和数据链路层&#xff08;mac&#xff09;属于硬件&#xff0c;其余都属于软件kernel2.MDC/MDIO&#xff1a;不仅管phy&#xff0c;只要支持mdio协议都可以管2.1 BMC速率适配&#xff1a;phy和switch…

二层MAC地址介绍

目录 MAC地址介绍 MAC地址的组成 MAC地址分类 MAC地址的作用 二层交换机介绍 MAC地址表的定义 MAC地址表项类型 二层交换机对数据帧的处理动作 MAC地址介绍 MAC地址&#xff08;Media Access Control Address)&#xff0c;直译为媒体存取控制位地址 MAC地址的组成 MA…

【四、基本shell命令】

1 帮助命令 man 获取帮助信息 [root@redis100 a]# man lshelp 获得shell内置命令的帮助信息 [root@redis100 a]# help cd常用快捷键 2 文件目录类 pwd 显示当前工作目录的绝对路径 pwd:print working directory [root@redis100 ~]# pwd /rootls 列出目录的内容 ls: list…

Hyper-V虚拟机安装和使用

目录 什么是虚拟化技术虚拟化技术有以下几个关键概念&#xff1a;虚拟化技术的优点&#xff1a; 什么是Hyper-V虚拟机Hyper-V虚拟机的关键特点和优势&#xff1a;使用Hyper-V虚拟机我们能做什么 安装Hyper-V系统要求启用Hyper-V功能创建虚拟机安装操作系统 最近在研究人工智能A…