linux内核更换与patch等常识

linux内核更换

内核映像bzImage的组成:
在这里插入图片描述
**setup.bin:**类似于火箭的一级推进子系统,这部分负责将内核加载进内存,并为后面内核保护模式运行建立基本的环境,但是后来加载内核的功能被剥离到Bootloader中,setup.bin则退化为辅助Bootloader将内核加载到内存。
uncompressed:类似于 火箭的二级推进子系统,包围在32位保护模式部分外的非解压缩部分,负责将压缩的内核解压缩到合适的位置,并进行内核重定位,完成从内核映像脱离
**内核32位保护模式部分vmlinux:**这部分相当于航天器的有效载荷,即类似于运行的卫星或宇宙飞船,只有这部分最后留在轨道内(内存中)运行,内核构建时,将有效载荷vmlinux进行压缩,然后与二级推进系统装配为 vmlinux.bin。
在编译内核时,通常只需要执行 “make bzImage”,或者make后面不接任何目标,构建的内核映像也是bzImage。

#/arch/x86/boot/Makefile
$(obj)/bzImage: $(obj)/setup.bin $(obj)/vmlinux.bin $(obj)/tools/build FORCE
	$(call if_changed,image)
	@$(kecho) 'Kernel: $@ is ready' ' (#'`cat .version`')'
vmlinux, zImage, Image等文件的区别

1.kernel镜像格式:vmlinux
vmlinuz是可引导的、可压缩的内核镜像,vm代表Virtual Memory.Linux支持虚拟内存,因此得名vm.它是由用户对内核源码编译得到,实质是elf格式的文件.也就是说,vmlinux是编译出来的最原始的内核文件,未压缩。这种格式的镜像文件多存放在PC机上,多放在源码的顶层目录下.
elf格式文件
ELF(Executable and Linkable Format),可执行可链接格式,是UNIX实验室作为应用程序二进制接口而发布的,扩展名为elf,可以简单认为,在elf格式的文件中,除二进制代码外,还包括该可执行文件的某些信息,比如符号表等。
2.kernel镜像格式:Image
Image是经过objcopy处理的只包含二进制数据的内核代码,它已经不是elf格式了,但这种格式的内核镜像还没有经过压缩。 该文件一般放在文件放在源码的 arch\arm\boot 目录下。
GNU使用工具程序 objcopy 作用是拷贝一个目标文件的内容到另一个目标文件中,也就是说,可以将一种格式的目标文件转换成另一种格式的目标文件。通过使用binary作为输出目标(-o binary),可产生一个原始的二进制文件,实质上是将所有的符号和重定位信息都将被抛弃,只剩下二进制数据
3. kernel镜像格式:zImage
zImage是ARM linux常用的一种压缩镜像文件,它是由vmlinux加上解压代码经gzip压缩而成,命令格式是#make zImage。该文件一般放在文件放在源码的 arch\arm\boot 目录下。
这种格式的Linux镜像文件多存放在NAND上.
4. kernel镜像格式:bzImage
bz表示big zImage,其格式与zImage类似,但采用了不同的压缩算法。注意,bzImage的压缩率更高.
5. kernel镜像格式:uImage
uImage是uboot专用的镜像文件,它是在zImage之前加上一个长度为0x40的头信息(tag),在头信息内说明了该镜像文件的类型、加载位置、生成时间、大小等信息。换句话说,若直接从uImage的0x40位置开始执行,则zImage和uImage没有任何区别。命令格式是#make uImage。
该文件一般放在文件放在源码的 arch\arm\boot 目录下。
这种格式的Linux镜像文件多存放在NAND上.
6. kernel镜像格式:xipImage
这种格式的Linux镜像文件多存放在NorFlash上,且运行时不需要拷贝到内存SDRAM中,可以直接在NorFlash中运行.

Linux内核镜像的产生过程(嵌入式编译过程,arm处理器)

在嵌入式Linux中,内核的启动过程分为两个阶段:
在嵌入式Linux中,内核的启动过程分为两个阶段:
第一阶段启动代码放在 arch/arm/kernel/head.S 文件中,该文件与 CPU体系 相关,与用户的开发板无关,主要是初始化ARM内核等。
第二阶段启动代码是init目录下的 main.c。
现以执行命令#make zImage为例来说明,arm-linux内核镜像的产生过程。
(1)当用户对Linux内核源码进行编译时,kernel的第1/2阶段代码会生成可执行文件 (镜像文件)vmlinux,该文件是未被压缩的镜像文件,非常大,不能直接下载到NAND中,通常放在PC机上,这也是最原始的Linux镜像文件,试验时该文件约50M。
(2)镜像文件vmlinux由于很大,肯定不能直接烧入NAND中,因此需要进行 二进制化,即经过objcopy 处理,使之只包含二进制数据的内核代码,去除不需要的文件信息等,这样就制作成了image镜像文件。该镜像文件也是未压缩,只是经过了二进制化而变小,试验时该文件约5M。
(3)一般来说,内存SDRAM中的内核镜像是经过压缩的,只是在运行时再将其解压.所以,编译时会先使用gzip将镜像文件image进行压缩(压缩比约为 2:1),**再将压缩后的镜像文件和源码中的两个文件arch/arm/boot/compressed/head.S、arch/arm/boot /compressed/misc.c一起链接生成压缩后的镜像文件compress/vmlinux.**试验时该文件约为2.5M.注意,这两个源码文件 是解压程序,用于将内存SDRAM中的压缩镜像zImage进行解压。
(4) 压缩后的镜像文件compress/vmlinux经过二进制化,最终生成镜像文件zImage,试验时该文件约为2.5M.当然,在内存 SDRAM中运行压缩镜像文件zImage时,会首先调用两个解压程序arch/arm /boot/compressed/head.S、arch/arm/boot/compressed/misc.c将自身解压,然后再执行kernel 的第一阶段启动代码arch/arm/kernel/head.S.简而言之,在内存中运行内核时,kernel先自身解压,再执行第一阶段启动代码.试 验时运行在内存中的镜像文件约为5M,与image镜像文件大小相同.
(5)生成的镜像文件image、zImage、uImage均在arch/arm/boot目录下。
**注意:**启动开发板时,在超级终端内会有许多的提示信息,其中:booting linux … /表示正在将内核从NAND拷贝到内存中/,unpressed… /表示正在解压内核/

System.map、vmlinuz、initrd.img的产生和作用

1.vmlinuz
vmlinuz是可引导的、压缩的内核。“vm”代表“Virtual Memory”。Linux支持虚拟内存,不像老的操作系统比如DOS有640KB内存的限制。Linux能够使用硬盘空间作为虚拟内存,因此得名“vm”。vmlinuz是可执行的Linux内核,它位于/boot/vmlinuz,它一般是一个软链接,产生方式:(1) 通过编译内核时"make zImage"创建, zImage适用于 小内核的情况。(2) 内核编译时"make bzImage",bzImage是压缩映像,需要注意,bzImage不是用bzip2压缩的。
zImage(vmlinuz)和bzImage(vmlinuz)都是用gzip压缩的。它们不仅是一个压缩文件,而且在这两个文件的开头部分内嵌有gzip解压缩代码。所以你不能用gunzip 或 gzip –dc解包vmlinuz。内核文件中包含一个微型的gzip用于解压缩内核并引导它。两者的不同之处在于,老的zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么可以采用zImage或bzImage之一,两种方式引导的系统运行时是相同的。大的内核采用bzImage,不能采用zImage。vmlinux是未压缩的内核,vmlinuz是vmlinux的压缩文件。
2.initrd-x.x.x.img
initrd是“initial ramdisk”的简写。initrd一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态。主要是用于加载ext3等文件系统及scsi设备的驱动。比如,使用的是scsi硬盘,而内核vmlinuz中并没有这个scsi硬件的驱动,那么在装入scsi模块之前,内核不能加载根文件系统,但scsi模块存储在根文件系统的/lib/modules下。为了解决这个问题,可以引导一个能够读实际内核的initrd内核并用initrd修正scsi引导问题,该文件是用gzip压缩的文件,initrd实现加载一些模块和安装文件系统等功能。initrd映象文件是使用mkinitrd创建的。mkinitrd实用程序能够创建initrd映象文件。这个命令是RedHat专有的。其它
Linux发行版或许有相应的命令。这是个很方便的实用程序。具体情况请看帮助:man mkinitrd下面的命令创建initrd映象文件。initrd是linux在系统引导过程中使用的一个临时的根文件系统,用来支持两阶段的引导过程。
  直白一点,initrd就是一个带有根文件系统的虚拟RAM盘,里面包含了根目录‘/’,以及其他的目录,比如:bin,dev,proc,sbin,sys等linux启动时必须的目录,以及在bin目录下加入了一下必须的可执行命令。PC或者服务器linux内核使用这个initrd来挂载真正的根文件系统,然后将此initrd从内存中 卸掉,这种情况下initrd其实就是一个过渡使用的东西。 在现在的许多简单嵌入式linux中一般是不卸载这个initrd的,而是直接将其作为根文件系统使用,在这之前就需要把所需要的程序,命令还有其它文件 都安装到这个文件系统中。其实现在的大多数嵌入式系统也是有自己的磁盘的,所以,initrd在现在大多数的嵌入式系统中也和一般的linux中的作用一 样只是起过渡使用。
  Initrd的引导过程:‘第二阶段引导程序’常用的是grub将内核解压缩并拷贝到内存中,然后内 核接管了CPU开始执行,然后内核调用init()函数,注意,此init函数并不是后来的init进程!!!然后内核调用函数 initrd_load()来在内存中加载initrd根文件系统。Initrd_load()函数又调用了一些其他的函数来为RAM磁盘分配空间,并计 算CRC等操作。然后对RAM磁盘进行解压,并将其加载到内存中。现在,内存中就有了initrd的映象。
  然后内核会
调用mount_root()函数来创建真正的根分区文件系统
,然后调用sys_mount()函数来加载真正的根文件系统,然后chdir到这个真正的根文件系统中。
  最后,init函数调用run_init_process函数,利用execve来启动init进程,从而进入init的运行过程。

System.map

内核符号映射表,顾名思义就是将内核中的符号(也就是内核中的函数)和它的地址能联系起来的一个列表。是所有符号及其对应地址的一个列表。之所以这样就使为了用户编程方便,直接使用函数符号就可以了,而不用去记要使用函数的地址。  当你编译一个新内核时,原来的System.map中的符号信息就不正确了。随着每次内核的编译,就会产生一个新的 System.map文件,并且需要用该文件取代原来的文件
System.map是一个特定内核的内核符号表。它是你当前运行的内核的System.map的链接。
内核符号表是怎么创建的呢? System.map是由“nm vmlinux”产生并且不相关的符号被滤出。

cat /boot/System.map-5.15.0-43-generic
0000000000000000 D __per_cpu_start
0000000000000000 D fixed_percpu_data
00000000000001d9 A kexec_control_code_size
0000000000001000 D cpu_debug_store
0000000000002000 D irq_stack_backing_store
0000000000006000 D cpu_tss_rw
000000000000b000 D gdt_page
000000000000c000 d exception_stacks
0000000000018000 d entry_stack_storage
0000000000019000 D espfix_waddr
0000000000019008 D espfix_stack
0000000000019010 D cpu_llc_id
0000000000019020 d mce_banks_array
0000000000019420 D mce_num_banks
0000000000019440 D cpu_llc_shared_map
0000000000019448 D cpu_die_map
0000000000019450 D cpu_core_map
0000000000019458 D cpu_sibling_map
0000000000019460 D cpu_info
0000000000019568 D cpu_number
0000000000019570 D this_cpu_off
0000000000019578 D x86_bios_cpu_apicid
000000000001957c D x86_cpu_to_acpiid

Linux 符号表使用到2个文件:
/proc/ksyms
System.map
/proc/ksyms是一个**“proc file”**,在内核引导时创建。实际上,它并不真正的是一个文件,它只不过是内核数据的表示,却给人们是一个磁盘文件的假象,这从它的文件大小是0可以看出来。然而,System.map是存在于你的文件系统上的实际文件。当你编译一个新内核时,各个符号名的地址要发生变化,你的老的System.map具有的是错误的符号信息。每次内核编译时产生一个新的System.map,你应当用新的System.map来取代老的System.map。
虽然内核本身并不真正使用System.map,但其它程序比如klogd,lsof和ps等软件需要一个正确的System.map。如果你使用错误的或没有System.map,klogd的输出将是不可靠的,这对于排除程序故障会带来困难。没有System.map,你可能会面临一些令人烦恼的提示信息。另外少数驱动需要System.map来解析符号,没有为你当前运行的特定内核创建的System.map它们就不能正常工作。
Linux的内核日志守护进程klogd为了执行名称-地址解析,klogd需要使用System.map。System.map应当放在使用它的软件能够找到它的地方。执行:manklogd可知,如果没有将System.map作为一个变量的位置给klogd,那么它将按照下面的顺序,在三个地方查找System.map:
/boot/System.map
/System.map
/usr/src/linux/System.map
System.map也有版本信息,klogd能够智能地查找正确的映象(map)文件。

内核编译安装

make menuconfig #生成.config文件
make bzImage / make -j20 #  单编译镜像或编译内核
make modules #编译动态模块
make modules_install #安装动态模块,将编译好的modules拷贝到lib/modules相应的内核目录里面
make headers_install #安装头文件,可以追加INSTALL_HDR_PATH=/usr
make install #安装内核,很关键

查看内核安装情况:

grep menuentry /boot/grub/grub.cfg
if [ x"${feature_menuentry_id}" = xy ]; then
  menuentry_id_option="--id"
  menuentry_id_option=""
export menuentry_id_option
menuentry 'Ubuntu' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-simple-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
submenu 'Ubuntu 的高级选项' $menuentry_id_option 'gnulinux-advanced-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu,Linux 5.15.0-43-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-43-generic-advanced-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu, with Linux 5.15.0-43-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-43-generic-recovery-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu,Linux 5.15.0-41-generic' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-41-generic-advanced-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu, with Linux 5.15.0-41-generic (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.15.0-41-generic-recovery-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu,Linux 5.11.0-20220228' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.11.0-20220228-advanced-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
	menuentry 'Ubuntu, with Linux 5.11.0-20220228 (recovery mode)' --class ubuntu --class gnu-linux --class gnu --class os $menuentry_id_option 'gnulinux-5.11.0-20220228-recovery-9b3b2ea0-494d-4d19-810f-ea05cf121c93' {
menuentry 'UEFI Firmware Settings' $menuentry_id_option 'uefi-firmware' {
vim /etc/default/grub
GRUB_DEFAULT=0;#手动换内核GRUB_DEFAULT="Advanced options for Ubuntu>Ubuntu,Linux 5.15.0-43-generic"
GRUB_TIMEOUT_STYLE=hidden #隐藏菜单的效果,一般采用这样的设置,这样虽然不会等待,可以通过按住shift键或者esc键进入
GRUB_TIMEOUT=0 #则跳过等待,不再显示grub菜单,起到隐藏菜单的效果
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT="quiet splash"
GRUB_CMDLINE_LINUX=""

# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef
update-grub #更新,grub是bootloader
安装cpufrequtils工具
#自动安装apt install cpufrequtils
cd ./linux/linux-5.11/tools
make cpupower_install perfix=/usr
vim /etc/ld.so.conf #系统中的文件 追加+/usr/lib64--->>>64位库
ldconfig  #重载config配置文件
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor #查看模式:performance,powersave,ondeamand等模式
cpupower frequency_set  -g performance #设置cpu模式
echo performance >> scaling_governor
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq #有必要时可以对scaling_max_freq修改
首先要搞清楚物理CPU、核心数、逻辑CPU数的概念:
① 物理CPU数量(physical id):主板上实际插入的CPU数量,有几个可以通过不重复物理id来统计。
② CPU核数(cpu cores):单个CPU上可以处理数据的芯片组数量,如双核、四核等。
③ 逻辑CPU数量:一般来说,
  逻辑CPU = 物理CPU数 × 核心数              # 不支持超线程技术
  逻辑CPU = 物理CPU数量 × 每个CPU核心数量 * 2  # 表示服务器的CPU支持超线程技术(简单来说就是可以让处理器中的1个核心成为操作系统中的2个核心。这样,操作系统可用的执行资源翻了一番,大大提高了系统的整体性能)
processor:系统中逻辑处理核心的数量。对于单核处理器,该类将其视为 CPU 编号,对于多核处理器,它可以是物理内核,也可以是使用超线程技术的虚拟逻辑内核。(processor内核内部使用的对象,不一定绑定到物理设备,它们可能都具有相同的 physical id)
vendor_id:CPU制造商。
cpu family:CPU 产品系列代号。
mode:cpu属于其系列中的哪一代。
model name:CPU的名称及其编号,标称频率。
stepping:CPU属于生产更新版本。
cpu MHz:实际CPU频率。
cache size:CPU二级缓存的大小。
physical id:单个物理CPU标号。
siblings:单个物理 CPU 的逻辑 CPU 数量。siblings = cpu 核心 * [2]。
core id:当前所在CPU中的物理内核id。
cpu cores:逻辑核所在CPU的物理核数。比如这里有2个cpu core,对应的core id是0、1。
apicid:用于区分不同逻辑核心的编号。系统中每个逻辑核的编号必须不同,编号不一定是连续的。
fpu:是否有浮点单元。(Floating Point Unit)
fpu_exception:是否支持浮点计算异常。
cpuid level:在执行cpuid指令之前,eax寄存器中的值会根据不同的值返回不同的内容。
wp:表示当前CPU是否支持内核态用户空间写保护。(Write Protection)
flags:当前CPU支持的功能,例如浮点单元 (FPU) 的存在和处理 MMX 指令的能力。。
bogomips:粗略测量的 CPU 速度(每秒百万条指令)。
clflush size:每个flush缓存的大小单位。
cache_alignment:缓存地址对齐单元。
address sizes:可访问地址空间的数量。
power management:支持电源管理。
cat /proc/cpuinfo  /proc目录下提供很多文件来显示系统的软硬件信息。
processor	: 0
vendor_id	: AuthenticAMD
cpu family	: 23
model		: 96
model name	: AMD Ryzen 5 4600U with Radeon Graphics
stepping	: 1
microcode	: 0x8600104
cpu MHz		: 1400.000
cache size	: 512 KB
physical id	: 0
siblings	: 12
core id		: 0
cpu cores	: 6
apicid		: 0
initial apicid	: 0
fpu		: yes
fpu_exception	: yes
cpuid level	: 16
wp		: yes
安装perf
sudo apt install -y systemtap-sdt-dev libaudit-common libaudit-dev libaudit1 libssl-dev libiberty-dev binutils-dev liblzma-dev zlib1g zlib1g-dev libzstd1-dev libcap-dev libnuma-dev libbabeltrace-ctf-dev libbabeltrace-dev
cd ./linux-5.4.128/tools
sudo make perf_install prefix=/usr/
sudo su && echo 0 > /proc/sys/kernel/kptr_restrict
perf record -C xxxxxxxxxx(用户运行的程序)
perf report

patch用法

diff/命令及常用选项

命令格式:

diff [选项] old_file new_file #old_file和new_file可以是文件,也可以是文件夹

常用选项

选项说明
-r递归比较各子目录下的文件
-N将不存在的文件当作空文件
-u默认输出每个修改前后的3行,也可以用-u5等指定输出更多上下文。1
-B忽略对空行的比较
-w忽略所有空格和制表符。例如,if ( a == b ) 与 if(a==b) 相等。

制作补丁

一般-Nu 是一直使用的参数,而-r如果含子目录就使用,不含则不使用。

#实例
diff -Nur linux-5.11 linux-5.11_ok > linux-5.11.patch #生成补丁文件

案例

创建实现目录和文件

创建一个实验目录demo

mkdir demo

进入demo

cd demo

模拟一个项目目录src

mkdir -p src/a/b/c/d

创建一个文件

vim src/a/b/c/d/file

内容是

line1
line2
line3

假设我们发现项目src需要修改,那么拷贝src并命名为src_new

cp -r src src_new

并且修改src_new/a/b/c/d/file的内容为

new_line1
new_line2
new_line3

此时,demo目录下用tree命令的结果是:

.
├── src
│   └── a
│       └── b
│           └── c
│               └── d
│                   └── file
└── src_new
    └── a
        └── b
            └── c
                └── d
                    └── file

10 directories, 2 files

在demo目录下用diff命令打补丁,不要使用绝对路径,而应该使用相对路径。

 diff -Nur src src_new >src.patch
 vim src.patch
 diff -Nur src/a/b/c/d/file src_new/a/b/c/d/file
--- src/a/b/c/d/file    2022-08-13 20:20:35.794931503 +0800
+++ src_new/a/b/c/d/file        2022-08-13 20:30:39.320713472 +0800
@@ -1,3 +1,3 @@
-line1
-line2
-line3
+new_line1
+new_line2
+new_line3

补丁制作完成

打补丁

在demo目录下,试试下面命令:

patch -p0 <src.patch
patching file src/a/b/c/d/file #注意文件

这里的p0是什么含义呢?
看一下补丁文件中的路径信息:

--- src/a/b/c/d/file    2022-08-13 20:20:35.794931503 +0800
+++ src_new/a/b/c/d/file        2022-08-13 20:30:39.320713472 +0800

p0表示不跳过任何目录(使用完整路径)。即从当前目录中查找src/a/b/c/d/file.
因为是在demo目录下使用patch命令,src目录就在demo目录下,不必跳过任何目录,所以此时使用的是p0。(都在demo目录下)
此时查看src/a/b/c/d/file,你会发现内容已经修改成

new_line1
new_line2
new_line3

这时候如果再次使用patch命令,系统会问你是否想还原,输入y 还原:

patch -p0 <src.patch
patching file src/a/b/c/d/file
Reversed (or previously applied) patch detected!  Assume -R? [n] y
vim src/a/b/c/d/file
line1
line2
line3

如果你想指定还原文件, 可以使用-R参数:

patch -Rp0 <src.patch

已经明白了p0,那么p1、p2呢?
我们把路径切换到src目录下。

cd src

此时就应该是p1,而不是p0了; 另外引用src.patch文件的路径也要适当变一下,因为当前目录已经是src了

patch -p1 <../src.patch 

再看看补丁文件中的路径信息:

--- src/a/b/c/d/file    2022-08-13 20:20:35.794931503 +0800
+++ src_new/a/b/c/d/file        2022-08-13 20:30:39.320713472 +0800

此时我们是在src目录下使用patch命令,p1表示忽略第一个斜杠及左边,即寻找a/b/c/d/file,而a就在当前目录下,所以使用p1.为了继续测试,我们还原一下:

patch -Rp1 <../src.patch #再选择y

继续变换路径,测试p2参数:

cd a

然后

patch -p2 <../../src.patch 

因为补丁文件中的路径信息是:

--- src/a/b/c/d/file    2022-08-13 20:20:35.794931503 +0800
+++ src_new/a/b/c/d/file        2022-08-13 20:30:39.320713472 +0800

此时我们是在a目录下使用patch命令,p2表示忽略第2个斜杠及左边,即寻找b/c/d/file,而b就在当前目录下,所以使用p2.
还原后继续实验,我们进入到d目录

patch -p5 <../../../../../src.patch

依然观察补丁文件中的路径信息:

--- src/a/b/c/d/file    2022-08-13 20:20:35.794931503 +0800
+++ src_new/a/b/c/d/file        2022-08-13 20:30:39.320713472 +0800

此时我们是在d目录下使用patch命令,p5表示忽略第5个斜杠及左边,即寻找file,而file就在当前目录下,所以使用p5.
有人会问,不使用p参数会有什么结果呢?
不使用p参数 时候,patch命令会忽略所有斜杠,直接使用文件,即本文中的file
所以在d目录下也可以用命令

patch  <../../../../../src.patch

为什么使用diff命令时最好不要使用绝对路径,而应该使用相对路径?
答:如果使用绝对路径,那么补丁文件里的路径信息会类似下面的样子:

--- /x/xx/xxx/src/a/b/c/d/file  2017-07-02 18:41:19.269641100 +0800
+++ /x/xx/xxx/src_new/a/b/c/d/file  2017-07-02 18:32:06.687035200 +0800

如此一来,当别人想应用你的补丁时,因为目录结构肯定有差异,所以就不得不费力判断到底使用p几。这样一来就容易出错.
相反,如果使用相对路径的话,大多数时候,p0或者p1就足够了,不易出错。

patch用法总结

假如补丁头是

--- src/a/b/c/d/file    2017-07-02 18:41:19.269641100 +0800
+++ src_new/a/b/c/d/file    2017-07-02 18:32:06.687035200 +0800

使用p0 表示在当前目录下查找src/a/b/c/d/file
使用p1 表示在当前目录下查找a/b/c/d/file
使用p2 表示在当前目录下查找b/c/d/file
使用p3 表示在当前目录下查找c/d/file
使用p4 表示在当前目录下查找d/file
使用p5 表示在当前目录下查找file
不使用pn表示忽略所有斜杠,在当前目录下查找file

打补丁的命令格式是:
patch -pn < 补丁文件
还原的命令格式是
patch -Rpn < 补丁文件  #选择y可以还原

(n=0,1,2,3…)

附录

TSO、GSO、LRO、GRO 卸载技术

网络功能卸载:
TSO(TCP Segmentation Offload)
GSO(Generic Segmentation Offload)
LRO(Large Receive Offload)
GRO (Generic Receive Offload)
网络功能卸载
为适应高速网络,现代网卡中普遍卸载了部分 L3-L4 层的处理逻辑(e.g. 校验和计算、传输层分片重组等),来减轻 Host CPU 的处理负担。**甚至有些网卡(e.g. RDMA 网卡)还将整个 L4 层的处理都卸载到硬件上,以完全解放 Host CPU。**得益于这些硬件卸载技术,Host OS 的网络协议栈处理才能与现有的高速网络相匹配。
**TSO(TCP Segmentation Offload):**是一种利用网卡对大数据包进行分片,从而减小 CPU 负荷的一种技术。

  • TSO off 和 GSO off:
    在这里插入图片描述 * TSO on:
    在这里插入图片描述
    GSO(Generic Segmentation Offload:是一种延缓分片技术。它比 TSO 更通用,原因在于它不需要硬件的支持就可以进行分片。
    其过程是:首先查询网卡是否支持 TSO 功能,如果硬件支持 TSO 则使用网卡的硬件分片能力执行分片;如果网卡不支持 TSO 功能,则将分片的执行,延缓到了将数据推送到网卡的前一刻执行。

  • TSO off and GSO on:一个大的网络包直到进入网卡前的最后一步才进行了分片。
    在这里插入图片描述
    **LRO(Large Receive Offload:**将网卡接收到的多个数据包合并成一个大的数据包,然后再传递给网络协议栈处理的技术。这样提系统接收数据包的能力,减轻 CPU 负载。

  • LRO off and GRO off
    在这里插入图片描述* LRO on:数据一进入网卡立刻进行了合并。
    在这里插入图片描述
    **GRO (Generic Receive Offload):**是 LRO 的软实现,GRO 的合并条件更加的严格和灵活。

  • GRO on
    在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值