linux内核IMQ源码实现分析
Linux 内核2.4版源代码分析大全

4.4.4 如何使传统管理方式依然有效
4.4.5 内核实现综述
4.4.6 核心结构与变量
4.4.7 devfs节点注册函数
4.4.8 编写采用devfs的设备驱动程序
4,5 块设备的请求队列
4.5.1 相关结构及请求队列的初始化
4.6.1 构造ioctl命令字
4.6.2 ioctl的实现过程
4.6.3 ioctl的上层处理函数
4.6.4 ioctl的底层处理函数
4.7 I/O端口的资源分配与操作
4.7.1 I/O端口概述
4.7.2 Linux系统中的I/O空间分配
4.7.3 端口操作函数
4.9.4 设备的使用
4.9.5 驱动程序编写实例
4.10 块设备驱动程序的实现
4.10.1 设备功能
4.10.2 编写块设备的函数接口fops
4.10.3 设备接口注册与初始化
第5章 Linux系统初始化
5.1 系统引导
1,13 系统调用
1.13.1 与系统调用有关的数据结构和
函数
1.13.2 进程的系统调用命令是如何转换为
INT0x80中断请求的
1.13.3 系统调用功能模块的初始化
1.13.4 Linux内部是如何分别为各种系统
调用服务的
4.1.2 与外设的数据交流方
4.1.3 字符设备与块设备
4.1.4 主设备号和次设备号
4.1.5 本章内容分配
4.2 设备文件
4.2.1 基本设备文件的设备访问流程
4.2.2 设备驱动程序接口
4.2.3 块设备文件接口
Linux内核源码分析--内核启动之zImage自解压过程

Linux内核源码分析--内核启动之zImage⾃解压过程阅读⽬录(Content)参考:⽂档下载地址:关于内核⾃解压完毕后,执⾏start_kernel的分析,参见:内核版本:3.0.8相关⽂件:arch/arm/boot/compressed/head.Sarch/arm/boot/compressed/vmlinux.ldsarch/arm/boot/compressed/piggy.gzip这⾥仅对内核⾃解压进⾏简要分析,详细的分析可以阅读参考博客⽂档。
zImage来历顶层vmlinux ---->arch/arm/boot/Image --->arch/arm/boot/compressed/piggy.gz --->arch/arm/boot/compressed/vmlinux --->arch/arm/boot/zImage如果要分析zImage的反汇编反汇编⽂件,可将arch/arm/boot/compressed/vmlinux进⾏反汇编,arm-linux-xxx-objdump –d vmlinux > vmlinux.dis对顶层的vmlinux反汇编得到的是未压缩的内核的反汇编⽂件,这个vmlinux才是真正的Linux内核。
piggy.gz压缩⽂件的特点gzip -f -9 < Image > piggy.gz在piggy.gz的结尾四个字节表⽰的是 Image 镜像的⼤⼩,并且是以⼩端格式存放的。
下⾯我们验证⼀下:可以看到,Image的⼤⼩是6806148B,⼗六进制值就是67DA84,接下来看看piggy.gz的结尾:可以看到,确实是将0x67DA84以⼩端的格式存放在了piggy.gz的结尾四字节中了。
vmlinux.lds1: /*2: * linux/arch/arm/boot/compressed/vmlinux.lds.in3: *4: * Copyright (C) 2000 Russell King5: *6: * This program is free software; you can redistribute it and/or modify7: * it under the terms of the GNU General Public License version 2 as8: * published by the Free Software Foundation.9: */10: OUTPUT_ARCH(arm)11: ENTRY(_start)12: SECTIONS13: {14: /DISCARD/ : {15: *(.ARM.exidx*)16: *(.ARM.extab*)17: /*18: * Discard any r/w data - this produces a link error if we have any,19: * which is required for PIC decompression. Local data generates20: * GOTOFF relocations, which prevents it being relocated independently21: * of the text/got segments.22: */23: *(.data)24: }25:26: . = 0;27: _text = .;28:29: .text : {30: _start = .;31: *(.start)32: *(.text)33: *(.text.*)34: *(.fixup)35: *(.gnu.warning)36: *(.rodata)37: *(.rodata.*)38: *(.glue_7)39: *(.glue_7t)40: *(.piggydata)41: . = ALIGN(4);42: }43:44: _etext = .;45:46: _got_start = .;47: .got : { *(.got) }48: _got_end = .;49: .got.plt : { *(.got.plt) }50: _edata = .;51:52: . = ALIGN(8);53: __bss_start = .;54: .bss : { *(.bss) }55: _end = .;56:57: . = ALIGN(8); /* the stack must be 64-bit aligned */58: .stack : { *(.stack) }59:60: .stab 0 : { *(.stab) }61: .stabstr 0 : { *(.stabstr) }62: .stab.excl 0 : { *(.stab.excl) }63: .stab.exclstr 0 : { *(.stab.exclstr) }64: .stab.index 0 : { *(.stab.index) }65: .stab.indexstr 0 : { *(.stab.indexstr) }66: .comment 0 : { *(.comment) }67: }68:arch/arm/boot/compressed/head.S1: .section ".start", #alloc, #execinstr2: /*3: * 清理不同的调⽤约定4: */5: .align6: .arm @ 启动总是进⼊ARM状态7: start:8: .type start,#function9: .rept 710: mov r0, r011: .endr12: ARM( mov r0, r0 )13: ARM( b 1f )14: THUMB( adr r12, BSYM(1f) )15: THUMB( bx r12 )16: .word 0x016f2818 @ ⽤于boot loader的魔数17: .word start @ 加载/运⾏zImage的绝对地址(编译时确定), 在vmlinux.lds中可以看到,zImage的链接起始地址是018: .word _edata @ zImage结束地址,分析vmlinux.lds可以看到,_edata是 .got 段的结束地址,后⾯紧接的就是.bss段和.stack段 19: THUMB( .thumb )20: 1: mov r7, r1 @ 保存构架ID到r7(此前由bootloader放⼊r1)21: mov r8, r2 @ 保存内核启动参数地址到r8(此前由bootloader放⼊r2)22: #ifndef __ARM_ARCH_2__23: /*24: * 通过Angel调试器启动 - 必须进⼊ SVC模式且关闭FIQs/IRQs25: * (numeric definitions from angel arm.h source).26: * 如果进⼊时在user模式下,我们只需要做这些27: */28: mrs r2, cpsr @ 获取当前模式29: tst r2, #3 @ 判断是否是user模式30: bne not_angel31: mov r0, #0x17 @ angel_SWIreason_EnterSVC32: ARM( swi 0x123456 ) @ angel_SWI_ARM swi会产⽣软中断,会跳⼊中断向量表,这个向量表⽤的是bootloader的,因为在head.S中并没有建⽴新的向量表33: THUMB( svc 0xab ) @ angel_SWI_THUMB34: not_angel:35: mrs r2, cpsr @ 关闭中断36: orr r2, r2, #0xc0 @ 以保护调试器的运作关闭IRQ和FIQ37: msr cpsr_c, r238: #else39: teqp pc, #0x0c000003@ 关闭中断(此外bootloader已设置模式为SVC)40: #endifGOT表是什么?GOT(Global Offset Table)表中每⼀项都是本运⾏模块要引⽤的⼀个全局变量或函数的地址。
Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(L。。。

Linux内核源码分析--内核启动之(5)Image内核启动(rest_init函数)(L。
前⾯粗略分析start_kernel函数,此函数中基本上是对内存管理和各⼦系统的数据结构初始化。
在内核初始化函数start_kernel执⾏到最后,就是调⽤rest_init函数,这个函数的主要使命就是创建并启动内核线程init。
这个函数虽然意思为剩下的初始化,但是这个“剩下”的可是内容颇多,下⾯详细分析如下:1. /*2. * 我们必须确定在⼀个⾮__init函数或3. * 其他根线程(root thread)和初始化线程(init thread)间的竞态。
4. * (这种竞态可能导致start_kernel在根线程运作到cpu_idle前被free_initmem“收割”。
)5. *6. *7. * gcc-3.4 偶尔会将这个函数作为内联函数, 所以使⽤了noinline.8. */9.10. static __initdata DECLARE_COMPLETION(kthreadd_done);11.1. 定义⼀个complete变量来告诉init线程:kthreads线程已经创建完成。
2. 从前似乎不是⽤complete锁,⽽是⽤⼤内核锁。
12. static noinline void __init_refok rest_init(void)13. {14. int pid;15.16. rcu_scheduler_starting();17. /*18. * 我们必须先创建init内核线程,这样它就可以获得pid为1。
19. * 尽管如此init线程将会挂起来等待创建kthreads线程。
20. * 如果我们在创建kthreadd线程前调度它,就将会出现OOPS。
21. */22. kernel_thread(kernel_init, NULL, CLONE_FS | CLONE_SIGHAND);1. 创建kernel_init内核线程,内核的1号进程23. numa_default_policy();1. 设定NUMA系统的内存访问策略为默认24. pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);25.1. 创建kthreadd内核线程,它的作⽤是管理和调度其它内核线程。
Linux内核源码分析--内核启动之(1)zImage

Linux内核源码分析--内核启动之(1)zImageLinux内核源码分析--内核启动之(1)zImag(1)zImage e⾃解压过程(Linux-3.0ARMv7)研究内核源码和内核运⾏原理的时候,很总要的⼀点是要了解内核的初始情况,也就是要了解内核启动过程。
我在研究内核的内存管理的时候,想知道内核启动后的页表的放置,页表1......2OUTPUT_ARCH(arm)3ENTRY(_start)4SECTIONS5{6/DISCARD/:{7*(.ARM.exidx*)8*(.ARM.extab*)9/*10*Discard any r/w data-this produces a link error if we have any,11*which is required for PIC decompression.Local data generates12*GOTOFF relocations,which prevents it being relocated independently13*of the text/got segments.14*/15*(.data)16}17.=TEXT_START;18_text=.;19.text:{20_start=.;21*(.start)22*(.text)23......start t arch/arm/boot/compressed/head.S S找到这个star 我们可以在arch/arm/boot/compressed/head.bootloader r ⼊⼝,这样就可以从这⾥开始⽤代码分析的⽅法研究bootloade跳转到压缩内核映像后的⾃解压启动过程:再看到MMU设置的时候,我只研究了armv7的指令。
看这些代码,必须对ARM的MMU有⼀定的了解,建议参考ARMv7的构架⼿册和⽹上的⼀份PDF《ARM MMU中⽂详解》(就是ARM⼿册中MMU部分的翻译)24/*25*linux/arch/arm/boot/compressed/head.S26*27*Copyright(C)1996-2002Russell King28*Copyright(C)2004Hyok S.Choi(MPU support)29*30*This program is free software;you can redistribute it and/or modify31*it under the terms of the GNU General Public License version2as32*published by the Free Software Foundation.33*/34#include35/*36*调试宏37*38*注意:这些宏必须不包含那些⾮100%可重定位的代码39*任何试图这样做的结果是导致程序崩溃40*当打开调试时请选择以下⼀个使⽤41*/42#ifdef DEBUG/*调试宏-中间层*/43#if defined(CONFIG_DEBUG_ICEDCC)/*使⽤内部调试协处理器CP14*/44#if defined(CONFIG_CPU_V6)||defined(CONFIG_CPU_V6K)||defined(CONFIG_CPU_V7)45.macro loadsp,rb,tmp46.endm47.macro writeb,ch,rb48mcr p14,0,\ch,c0,c5,049.endm50#elif defined(CONFIG_CPU_XSCALE)51.macro loadsp,rb,tmp52.endm53.macro writeb,ch,rb54mcr p14,0,\ch,c8,c0,055.endm56#else57.macro loadsp,rb,tmp58.endm59.macro writeb,ch,rb60mcr p14,0,\ch,c1,c0,061.endm62#endif63#else/*使⽤串⼝作为调试通道*/64#include/*包含构架相关的的调试宏的汇编⽂件调试宏-底层*/ 65.macro writeb,ch,rb 66senduart\ch,\rb67.endm68#if defined(CONFIG_ARCH_SA1100)69.macro loadsp,rb,tmp70mov\rb,#0x80000000@physical base address71#ifdef CONFIG_DEBUG_LL_SER372add\rb,\rb,#0x00050000@Ser373#else74add\rb,\rb,#0x00010000@Ser175#endif76.endm77#elif defined(CONFIG_ARCH_S3C2410)78.macro loadsp,rb,tmp79mov\rb,#0x5000000080add\rb,\rb,#0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT 81.endm82#else83.macro loadsp,rb,tmp84addruart\rb,\tmp85.endm86#endif87#endif88#endif/*DEBUG*/89/*调试宏-上层*/90.macro kputc,val/*打印字符*/91mov r0,\val92bl putc93.endm94.macro kphex,val,len/*打印⼗六进制数*/95mov r0,\val96mov r1,#\len97bl phex98.endm99.macro debug_reloc_start/*重定位内核调试宏-开始*/100#ifdef DEBUG101kputc#'\n'102kphex r6,8/*处理器id*/103kputc#':'104kphex r7,8/*构架id*/105#ifdef CONFIG_CPU_CP15106kputc#':'107mrc p15,0,r0,c1,c0108kphex r0,8/*控制寄存器*/109#endif110kputc#'\n'111kphex r5,8/*解压后的内核起始地址*/112kputc#'-'113kphex r9,8/*解压后的内核结束地址*/114kputc#'>'115kphex r4,8/*内核执⾏地址*/116kputc#'\n'117#endif118.endm119.macro debug_reloc_end/*重定位内核调试宏-结束*/ 120#ifdef DEBUG 121kphex r5,8/*内核结束地址*/122kputc#'\n'123mov r0,r4124bl memdump/*打印内核起始处256字节*/125#endif126.endm127.section".start",#alloc,#execinstr128/*129*清理不同的调⽤约定130*/131.align132.arm@启动总是进⼊ARM状态133start:134.type start,#function135.rept7136mov r0,r0137.endr138ARM(mov r0,r0)139ARM(b1f)140THUMB(adr r12,BSYM(1f))141THUMB(bx r12)142.word0x016f2818@⽤于boot loader的魔数143.word start@加载/运⾏zImage的绝对地址(编译时确定)144.word_edata@zImage结束地址145THUMB(.thumb)1461:mov r7,r1@保存构架ID到r7(此前由bootloader放⼊r1)147mov r8,r2@保存内核启动参数地址到r8(此前由bootloader放⼊r2)148#ifndef__ARM_ARCH_2__ 149/*150*通过Angel调试器启动-必须进⼊SVC模式且关闭FIQs/IRQs151*(numeric definitions from angel arm.h source).152*如果进⼊时在user模式下,我们只需要做这些153*/154mrs r2,cpsr@获取当前模式155tst r2,#3@判断是否是user模式156bne not_angel157mov r0,#0x17@angel_SWIreason_EnterSVC158ARM(swi0x123456)@angel_SWI_ARM159THUMB(svc0xab)@angel_SWI_THUMB160not_angel:161mrs r2,cpsr@关闭中断162orr r2,r2,#0xc0@以保护调试器的运作163msr cpsr_c,r2164#else165teqp pc,#0x0c000003@关闭中断(此外bootloader已设置模式为SVC)166#endif167/*168*注意⼀些缓存的刷新和其他事务可能需要在这⾥完成169*-is there an Angel SWI call for this?170*/171/*172*⼀些构架的特定代码可以在这⾥被连接器插⼊,173*但是不应使⽤r7(保存构架ID),r8(保存内核启动参数地址),and r9. 174*/ 175.text176/*177*此处确定解压后的内核映像的绝对地址(物理地址),保存于r4178*由于配置的不同可能有的结果179*(1)定义了CONFIG_AUTO_ZRELADDR180*ZRELADDR是已解压内核最终存放的物理地址181*如果AUTO_ZRELADDR被选择了,这个地址将会在运⾏是确定:182*将当pc值和0xf8000000做与操作,183*并加上TEXT_OFFSET(内核最终存放的物理地址与内存起始的偏移)184*这⾥假定zImage被放在内存开始的128MB内185*(2)没有定义CONFIG_AUTO_ZRELADDR186*直接使⽤zreladdr(此值位于arch/arm/mach-xxx/Makefile.boot⽂件确定)187*/ 188#ifdef CONFIG_AUTO_ZRELADDR189@确定内核映像地址190mov r4,pc191and r4,r4,#0xf8000000192add r4,r4,#TEXT_OFFSET193#else194ldr r4,=zreladdr195#endif196bl cache_on/*开启缓存(以及MMU)*/197restart:adr r0,LC0198ldmia r0,{r1,r2,r3,r6,r10,r11,r12}199ldr sp,[r0,#28]200/*201*我们可能运⾏在⼀个与编译时定义的不同地址上,202*所以我们必须修正变量指针203*/204sub r0,r0,r1@计算偏移量205add r6,r6,r0@重新计算_edata206add r10,r10,r0@重新获得压缩后的内核⼤⼩数据位置207/*208*内核编译系统将解压后的内核⼤⼩数据209*以⼩端格式210*附加在压缩数据的后⾯(其实是“gzip-f-9”命令的结果)211*下⾯代码的作⽤是将解压后的内核⼤⼩数据正确地放⼊r9中(避免了⼤⼩端问题)212*/213ldrb r9,[r10,#0]214ldrb lr,[r10,#1]215orr r9,r9,lr,lsl#8216ldrb lr,[r10,#2]217ldrb r10,[r10,#3]218orr r9,r9,lr,lsl#16219orr r9,r9,r10,lsl#24220/*221*下⾯代码的作⽤是将正确的当前执⾏映像的结束地址放⼊r10222*/223#ifndef CONFIG_ZBOOT_ROM224/*malloc获取的内存空间位于重定向的栈指针之上(64k max)*/225add sp,sp,r0226add r10,sp,#0x10000227#else228/*229*如果定义了ZBOOT_ROM,bss/stack是⾮可重定位的,230*但有些⼈依然可以将其放在RAM中运⾏,231*这时我们可以参考_edata.232*/233mov r10,r6234#endif235/*236*检测我们是否会发⽣⾃我覆盖的问题237*r4=解压后的内核起始地址(最终执⾏位置)238*r9=解压后内核的⼤⼩239*r10=当前执⾏映像的结束地址,包含了bss/stack/malloc空间(假设是⾮XIP执⾏的)240*我们的基本需求是: 241*(若最终执⾏位置r4在当前映像之后)r4-16k页⽬录>=r10->OK242*(若最终执⾏位置r4在当前映像之前)r4+解压后的内核⼤⼩<=当前位置(pc)->OK 243*如果上⾯的条件不满⾜,就会⾃我覆盖,必须先搬运当前映像244*/245add r10,r10,#16384246cmp r4,r10@假设最终执⾏位置r4在当前映像之后247bhs wont_overwrite248add r10,r4,r9@假设最终执⾏位置r4在当前映像之前249ARM(cmp r10,pc)@r10=解压后的内核结束地址250THUMB(mov lr,pc)251THUMB(cmp r10,lr)252bls wont_overwrite253/*254*将当前的映像重定向到解压后的内核之后(会发⽣⾃我覆盖时才执⾏,否则就被跳过)255*r6=_edata(已校正)256*r10=解压后的内核结束地址257*因为我们要把当前映像向后移动,所以我们必须由后往前复制代码,258*以防原数据和⽬标数据的重叠259*/260/*261*将解压后的内核结束地址r10扩展(reloc_code_end-restart),262*并对齐到下⼀个256B边界。
Linux 源代码分析

Linux内核(2.6.13.2)源代码分析苗彦超摘要:1系统启动1.1汇编代码head.S及以前设置CPU状态初值,创建进程0,建立进程堆栈:movq init_rsp(%rip), %rsp,init_rsp定义.globl init_rspinit_rsp:.quad init_thread_union+THREAD_SIZE-8即将虚地址init_thread_union+THREAD_SIZE-8作为当前进程(进程0)核心空间堆栈栈底,init_thread_union定义于文件arch/x86_64/kernel/init_task.c中:union thread_union init_thread_union __attribute__((__section__(".data.init_task"))) ={INIT_THREAD_INFO(init_task)};INIT_THREAD_INFO定义于文件include/asm-x86_64/thread_info.h中,初始化init_thread_union.task = &init_task,init_task同样定义于文件init_task.c中,初始化为:struct task_struct init_task = INIT_TASK(init_task);INIT_TASK宏在include/linux/init_task.h中定义。
全部利用编译时静态设置的初值,将进程0的控制结构设置完成,使进程0可以按普通核心进程访问。
init_task.mm = NULL; init_task.active_mm = INIT_MM(init_mm), init_m = “swapper”INIT_MM将init_mm.pgd初始化为swapper_pg_dir,即init_level4_pgt,定义与head.S中。
Linux内核网桥源码分析

Linux内核⽹桥源码分析Linux⽹桥源码的实现转⾃:Linux⽹桥源码的实现1、调⽤在src/net/core/dev.c的软中断函数static void net_rx_action(struct softirq_action *h)中(line 1479)#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)if (skb->dev->br_port != NULL &&br_handle_frame_hook != NULL) {handle_bridge(skb, pt_prev);dev_put(rx_dev);continue;}#endif如果定义了⽹桥或⽹桥模块,则由handle_bridge函数处理skb->dev->br_port :接收该数据包的端⼝是⽹桥端⼝组的⼀员,如果接收当前数据包的接⼝不是⽹桥的某⼀物理端⼝,则其值为NULL;br_handle_frame_hook :定义了⽹桥处理函数这段代码将数据包进⾏转向,转向的后的处理函数是钩⼦函数br_handle_frame_hook,在此之前,handle_bridge函数还要处理⼀些其它的事情:static __inline__ int handle_bridge(struct sk_buff *skb,struct packet_type *pt_prev){int ret = NET_RX_DROP;if (pt_prev) {if (!pt_prev->data)ret = deliver_to_old_ones(pt_prev, skb, 0);else {atomic_inc(&skb->users);ret = pt_prev->func(skb, skb->dev, pt_prev);}}br_handle_frame_hook(skb);return ret;}pt_prev⽤于在共享SKB的时候提⾼效率,handle_bridge函数最后将控制权交由到了br_handle_frame_hook的⼿上。
linux源代码解读

Linux 内核解读入门针对好多Linux 爱好者对内核很有兴趣却无从下手,本文旨在介绍一种解读Linux内核源码的入门方法,而不是解说Linux复杂的内核机制。
1.核心源程序的文件组织(1)Linux核心源程序通常都安装在/usr/src/Linux下,而且它有一个非常简单的编号约定:任何偶数的核心(例如 2.0.30)都是一个稳定的发行的核心,而任何奇数的核心(例如2.1.42)都是一个开发中的核心。
本文基于稳定的2.2.5源代码,第二部分的实现平台为RedHat Linux 6.0。
(2)核心源程序的文件按树形结构进行组织,在源程序树的最上层你会看到这样一些目录:● Arch :arch子目录包括了所有和体系结构相关的核心代码。
它的每一个子目录都代表一种支持的体系结构,例如i386就是关于intel cpu及与之相兼容体系结构的子目录。
PC机一般都基于此目录;● Include: include子目录包括编译核心所需要的大部分头文件。
与平台无关的头文件在include/linux子目录下,与intel cpu相关的头文件在include/asm-i386子目录下而include/scsi目录则是有关scsi设备的头文件目录;● Init:这个目录包含核心的初始化代码(注:不是系统的引导代码),包含两个文件main.c和Version.c,这是研究核心如何工作的一个非常好的起点;● Mm :这个目录包括所有独立于cpu 体系结构的内存管理代码,如页式存储管理内存的分配和释放等,而和体系结构相关的内存管理代码则位于arch/*/mm/,例如arch/i386/mm/Fault.c;● Kernel:主要的核心代码,此目录下的文件实现了大多数Linux系统的内核函数,其中最重要的文件当属sched.c,同样,和体系结构相关的代码在arch/*/kernel 中;● Drivers:放置系统所有的设备驱动程序;每种驱动程序又各占用一个子目录,如/block下为块设备驱动程序,比如ide(ide.c)。
Linux内核调试机制源代码分析

kimage_entry_t *entry; kimage_entry_t *last_entry; unsigned long destination; unsigned long start; struct page *control_code_page; struct page *swap_page; unsigned long nr_segments; struct kexec_segment segment[KEXEC_SEGMENT_MAX]; /*段数组*/ struct list_head control_pages; struct list_head dest_pages; struct list_head unuseable_pages; /* 分配给崩溃内核的下一个控制页的地址*/ unsigned long control_page; /* 指定特殊处理的标识*/ unsigned int type : 1; #define KEXEC_TYPE_DEFAULT 0 #define KEXEC_TYPE_CRASH 1 unsigned int preserve_context : 1; };
内核 kexec 接口函数说明如下:
extern void machine_kexec(struct kimage *image); /*启动内核映像*/ extern int machine_kexec_prepare(struct kimage *image); /*建立内核映 像所需要的控制页*/ extern void machine_kexec_cleanup(struct kimage *image); extern asmlinkage long sys_kexec_load(unsigned long entry, unsigned long nr_segments, struct kexec_segment __user *segments, unsigned long flags); /*装 载内核的系统调用*/ extern int kernel_kexec(void); /*启动内核*/
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
本文档的Copyleft归wwwlkk所有,使用GPL发布,可以自由拷贝、转载,转载时请保持文档的完整性,严禁用于任何商业用途。
E-mail: wwwlkk@
来源: /?business&aid=6&un=wwwlkk#7
linux2.6.35内核IMQ源码实现分析
(1)数据包截留并重新注入协议栈技术 (1)
(2)及时处理数据包技术 (2)
(3)IMQ设备数据包重新注入协议栈流程 (4)
(4)IMQ截留数据包流程 (4)
(5)IMQ在软中断中及时将数据包重新注入协议栈 (7)
(6)结束语 (9)
前言:IMQ用于入口流量整形和全局的流量控制,IMQ的配置是很简单的,但很少人分析过IMQ的内核实现,网络上也没有IMQ的源码分析文档,为了搞清楚IMQ的性能,稳定性,以及借鉴IMQ的技术,本文分析了IMQ的内核实现机制。
首先揭示IMQ的核心技术:
1.如何从协议栈中截留数据包,并能把数据包重新注入协议栈。
2.如何做到及时的将数据包重新注入协议栈。
实际上linux的标准内核已经解决了以上2个技术难点,第1个技术可以在NF_QUEUE机制中看到,第二个技术可以在发包软中断中看到。
下面先介绍这2个技术。
(1)数据包截留并重新注入协议栈技术
(2)及时处理数据包技术
QoS有个技术难点:将数据包入队,然后发送队列中合适的数据包,那么如何做到队列中的数
激活状态的队列是否能保证队列中的数据包被及时的发送吗?接下来看一下,激活状态的队列的
证了数据包会被及时的发送。
这是linux内核发送软中断的机制,IMQ就是利用了这个机制,不同点在于:正常的发送队列是将数据包发送给网卡驱动,而IMQ队列是将数据包发送给okfn函数。
以上2个技术点就是IMQ的关键技术,下面是IMQ的具体流程。
(3)IMQ设备数据包重新注入协议栈流程
(4)IMQ截留数据包流程
(5)IMQ在软中断中及时将数据包重新注入协议栈
到这里IMQ整个流程已经分析结束。
(6)结束语
使用SmartFlow对IMQ做了测试,发现IMQ有些不稳定:
1)在低压力下会丢失几个数据包。
2)总体的性能降低很大。
所以IMQ并是不一个理想的QoS方案,所以这里对IMQ就不做更详细的分析。