Linux系统之Uboot、Kernel、Busybox思考之四
创始人
2024-05-26 10:53:48
0

目录

三 内核的运行

9 设备树:

  1) 设备树产生缘由

  2) 设备树方案的流程

  3) 有了上述概念,为了支撑整个设备树的工程实现,内核实现以下内容

  4) 内核解析设备树

  5) 入口分析

  6) 解析处理。

10 udev devfs sysfs

11 系统中的USB设备 

12 网络子系统

13 文件子系统

四 运行的内核


三 内核的运行

9 设备树:

  1) 设备树产生缘由

  为解决板级设备杂乱的问题,提供一种简洁方便的管理方案

  通过定义一些规则,按规则描述设备信息,然后由内核解析,动态生成设备相关代码,完成设备的挂载

  相对硬件编码而言,规则可以看作是在代码上面又封装了一层,更加灵活

  而且,规则可以定义的更适合人类阅读,这样对提高效率和复用,也很有帮助

  2) 设备树方案的流程

  定义设备数规则,根节点,子节点,节点属性,节点属性值,cell单元,引用等等。

  需要注意,根

  需要注意,可以支持c语言预处理

  需要注意,节点可以被覆盖,重写

  需要注意,一些节点有限制,比如CPU 节点中的size必须为0, memory的类型必须为memory

  需要注意,节点名称带有 根 标记

  属性可以有值,也可以无值

  属性值可以为字符串,字符串数组,以及字节数组等形式

  cell单元,需要注意格式,其地址和size由父节点决定

  中断分ppi spi,分上升沿下降沿等,有专有定义

  引用可以使用label形式,也可以自定义全局唯一值来实现

  兼容属性定义为从一般到特殊,如果一致,需要通过model属性区分

  以上为设备树本身的一些构成规则,编写和查看设备树文件时会用到上述内容。

  从名称可以看出来,设备树的组织结构形式为树。树是一种层次结构,对应到设备上,也代表着根、枝、叶的构成。

  根可以看作是顶层总线,下面挂接了CPU、内存和其他总线,总线下面还可以有总线和设备,这样一级一级展开,构成了系统的硬件体系结构

  对应到设备树中,也就存在着父节点和子节点

 

  3) 有了上述概念,为了支撑整个设备树的工程实现,内核实现以下内容

  首先是设备树规则,不再多说。

  其次是设备树文件,dts格式,source文件,另外还有dtsi格式,属于头文件,设备树支持头文件引用,这有利于代码复用和管理。除此,设备树还支持C语言的宏定义等

  编写设备树文件后,该文件内容是human readable的,但不是计算机容易readable的,所以还需要进行转换

  内核提供dtc工具,将dts文件内容编译成dtb格式。blob代表着二进制的对象。内核读取dtb格式内容,动态生成内存中的设备对象。

  dtc工具在内核源代码的/scripts/dtc/下,编译内核源代码时,会编译出主机端的dtc工具。需要打开内核的CONFIG_DTC选项,配置其为Y

  如果配置了CONFIG_ARM_APPENDED_DTB=y,编译内核源代码时,会自动调用dtc工具编译生成dtb文件,并将其附到内核尾部。

  当然,我们也可以单独执行该命令编译内核dtb文件,比如

  ./scripts/dtc/dtc -I dts -O dtb -o /home/nfsshare/hisi.dtb arch/arm/boot/dts/hi3519av100.dts

  内核在编译过程中,如何确定编译那些dts文件呢,这些在makefile中会指定,比如对于hisi来讲,arch/arm/boot目录下makefile中有 

include $(srctree)/arch/arm/boot/dts/Makefile,在这个makefile中,又会引入dtb-$(CONFIG_ARCH_HISI) += \hi3519-demb.dtb

  定义了dtb目标,目录下有hi3519-demb.dts源文件,这样dtc工具就会将该文件编译为目标的dtb文件

  dtc工具不但可以编译dtb文件,还可以将dtb文件反编译为dts文件。我们看到,为了管理和复用代码,dts文件支持头文件引用,节点覆盖等。

  当文件变得庞大时,对于确认和查找节点的最终描述,反而有点不方便,此时可以使用反编译过程,将dtb文件反编译为dts文件。

  反编译后的文件是最终整理过的结果,是一颗比较规整和标准的树结构,节点描述是唯一的,这对于确认节点的最终描述,反倒是比较方便的。反编译命令如下

  ./scripts/dtc/dtc -I dtb -O dts -o /home/nfsshare/hisi.dts arch/arm/boot/dts/hi3519av100-smp-flash.dtb

  可以看到,输入-I和输出-O格式发生了调换,输出文件-o也变为了dts格式,默认输入源倒是dtb

 

  4) 内核解析设备树

  有了dtb文件,内核就可以解析该文件,动态生成设备对象。

  dtb文件的解析在内核启动过程的开始阶段,最终也是解析为一棵树。(待确认)。后续,在内核启动的后期阶段,init线程中,加载设备驱动时,会遍历之前解析的树,

  找到每一个节点,生成节点相关的设备对象及属性信息。(待确认)

  到此,整个链条就完整了。

 

  5) 入口分析

  除了内核,uboot也是可以支持设备树的。相应的,就有以下几种可能:

  A uboot支持设备树,uboot解析设备树,将解析后的结果地址告诉内核(这种应该是不行的,从软件开发感觉来讲,也没必要,反而增加了uboot和内核之间的耦合度)

  B uboot支持设备树,uboot不解析设备数,只是将dtb文件的地址告诉内核,由内核解析从特定内存或者存储地址获取dtb信息,并进行解析。

  实际中是采用这种方式,bootm启动内核时,除了传递内核地址外,还需要在命令行参数中增加dtb的地址。这种方式,二者之间通过dtb达成一致。只要对dtb的解读一致即可。

  其实,也完全可以做到不存在任何耦合,比如dtb文件只在内核这一端生成

  C uboot不支持设备树,这种情况下,uboot仍然按照bootm启动内核,设备树的相关操作完全由内核完成。

  此时,在内核编译中,平台体系结构相关部分,不再是obj-y的目标,而是dtb-y。查看内核源代码可以发现,此时arch/arm/目录下的mach-xxx目录下,体系结构相关代码已经很少

  转而,在arch/arm/boot/dts目录下有大量体系结构相关的dts存在。

  makefile中也是指定dtc工具编译dtb目标,同时定义了zImage-dtb目标,由原始vmlinux生成压缩的zImage后,通过@cat $(obj)/zImage $(DTB_OBJS_FULL) > $@将dtb目标缀在zImage后面生成zImage-dtb

  最终生成uboot引导的uImage镜像也是基于zImage-dtb结果。

  $(obj)/uImage:  $(obj)/zImage-dtb FORCE

 用二进制编辑工具打开此时的uImage,可以在末尾看到可读的dts痕迹,比如P/soc/amba/uart@04540000等,说明内核镜像中包括了dtb内容。

 为了让内核启动时,自动查找dtb并进行解析,需要打开配置选项CONFIG_ARM_APPENDED_DTB。

   当上述选项配置为Y时,在compressed目录下的head.S汇编代码中,可以看到有对设备树的处理

   补充一点,zImage作为压缩镜像,其生成$(obj)/zImage:  $(obj)/compressed/vmlinux FORCE依赖于compressed下的目标

   head.S汇编代码会嵌入到内核启动代码中,判断启动合法条件,引导跳转到C代码,在head.S中会发现如下一段代码,

   

    #ifdef CONFIG_ARM_APPENDED_DTB/**   r0  = delta*   r2  = BSS start*   r3  = BSS end*   r4  = final kernel address (possibly with LSB set)*   r5  = appended dtb size (still unknown)*   r6  = _edata*   r7  = architecture ID*   r8  = atags/device tree pointer*   r9  = size of decompressed image*   r10 = end of this image, including  bss/stack/malloc space if non XIP*   r11 = GOT start*   r12 = GOT end*   sp  = stack pointer** if there are device trees (dtb) appended to zImage, advance r10 so that the* dtb data will get relocated along with the kernel if necessary.*/ldr	lr, [r6, #0]#ifndef __ARMEB__ldr	r1, =0xedfe0dd0		@ sig is 0xd00dfeed big endian#elseldr	r1, =0xd00dfeed#endifcmp	lr, r1bne	dtb_check_done		@ not found

  从上面代码可以看出,r6是内核正常的结尾处,D0 0D FE ED是dtb的魔数,当CONFIG_ARM_APPENDED_DTB选项被选中时

    会将内核正常结尾处也就是附加dtb开头的内容加载到lr中,同时根据大小端,将dtb的魔数设置到寄存器r1中

    接着判断二者是否相等,如果不等,说明未找到dtb,否则说明内核自带了dtb

    如果发现存在dtb append,则在后续解压内核时避免对dtb部分造成影响,最终调整dtb的相关指针,以便内核启动时,能够正确加载和解析dtb

  6) 解析处理。

10 udev devfs sysfs

  设备的发现与管理

  内核启动时,初始化相关资源,包括进程、内存、中断、锁、设备模型、文件系统框架、用户空间交互通道等,并完成设备树的解析

  内核创建init进程,在恰当时机执行initcall区域的函数指针,进行driver setup

  各个驱动模块的初始化在执行过程中,会进行总线注册和设备匹配,匹配分多种条件,包括id table,设备名称,设备树兼容性属性等等。一般按照严格到宽松的条件进行匹配。

  匹配成功后,驱动的probe接口将被调用,进行设备的初始化及设备所需中断和内存等资源的申请

  之后,设备一般在中断的驱动下开始正常工作,包括上层触发数据发送,中断触发数据接收,上层触发各种控制操作等。

 

  在Linux中,一切设备均抽象为文件。内核驱动中,可以申请设备号,成功后,在proc/devices中可以看到设备号使用情况

  设备号申请分自动和手动两种,自动方式由内核提供空闲设备号,手动由驱动主动注册设备号,手动方式可能存在设备号冲突情况

  设备驱动申请设备号并注册后,只是在上述目录下可以看到新增加的设备号,而/dev目录下并没有实际产生设备节点

  要在/dev目录下产生设备节点,有多种方式,一种是驱动中调用内核接口device_create,注册时自动生成设备节点;一种是通过sysfs系统,在用户空间通过udev工具生成;还可以调用mknod程序,手动生成。

 

  在内核驱动中自动创建设备节点存在一些缺点,比如节点命名问题,特定功能节点的创建问题。

  所以,一些节点可能在需要时由用户空间程序创建,会提供方便。但是,完全交给用户空间,也存在问题。比如,设备发现问题。在错过设备驱动加载时机后,如何发现设备。

  这里也牵涉一些关于内核职责的问题,比如机制与策略的分离。

  2.6之后的内核提供了sysfs系统,用于管理总线、驱动、设备及它们之间的关系。udev工具就是基于sysfs进行设备管理的用户空间程序。

  借助udev工具,可以很好的解决设备命名问题,也可以在设备发现和移除时,很方便的执行定制化动作。

 

  整个流程为:

  首先,内核在初始化过程中,会加载内置驱动,完成设备的初始化和部分设备的创建。

  init程序加载用户空间第一个程序并执行时,会执行udevd后台例程。

  udevd会使用/etc/udev/udev.conf文件配置自己

  udevd会监听内核设备事件,包括add remove change等

  检测到事件后,会按优先级匹配/etc/udev/rules.d/下面的规则文件(规则文件是udevd启动时预置到其内存数据结构中的?)

  udevd是否会监听/etc/udev/rules.d目录下的规则文件的变化,实时更新规则。应该要这样,否则,需要重启udevd获取系统,这不符合用户体验要求。

  udevd会遍历所有预置的规则,匹配后,就执行相应的动作,包括赋值、执行动作、获取特定动作的结果进行赋值或执行动作

  动作的执行要放到单独的环境中,如果是脚本的话,要明确指定shell类型,udevd会fork子进程处理动作。ps可能会看到多个udevd daemon进程。

  规则文件编写原则可参考已有规则文件,其中有关属性和预定义变量,可以通过执行udevadm info -q all -n /dev/xxx -a的输出查看

  设备的相关操作信息会被记录到一个数据库中,udevadm就是读取数据库信息来展示设备相关信息的。

  -a参数可以输出设备的整个加载链条,比如从最顶层的总线到下一级总线到再下一级总线,直到当前指定设备为止。

  设备的组成结构是一个树形结构,比如执行udevadm info -q all -n /dev/sdd -a输出sdd设备信息如下

  

looking at device '/devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd':KERNEL=="sdd"SUBSYSTEM=="block"DRIVER==""ATTR{ro}=="0"ATTR{size}=="7814037168"ATTR{stat}=="    4597       46    37126    69300    10595     5825  2513672    73590        0    53330   142880"ATTR{range}=="16"ATTR{discard_alignment}=="0"ATTR{events}==""ATTR{ext_range}=="256"ATTR{events_poll_msecs}=="-1"ATTR{alignment_offset}=="0"ATTR{inflight}=="       0        0"ATTR{removable}=="0"ATTR{capability}=="50"ATTR{events_async}==""looking at parent device '/devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0':KERNELS=="3:0:0:0"SUBSYSTEMS=="scsi"DRIVERS=="sd"ATTRS{rev}=="CV11"ATTRS{type}=="0"ATTRS{scsi_level}=="6"ATTRS{model}=="ST4000VX005-2LY1"ATTRS{state}=="running"ATTRS{queue_type}=="simple"ATTRS{modalias}=="scsi:t-0x00"ATTRS{iodone_cnt}=="0x4826"ATTRS{iorequest_cnt}=="0x4844"ATTRS{queue_ramp_up_period}=="120000"ATTRS{timeout}=="30"ATTRS{evt_media_change}=="0"ATTRS{ioerr_cnt}=="0x0"ATTRS{queue_depth}=="31"ATTRS{vendor}=="ATA     "ATTRS{device_blocked}=="0"ATTRS{iocounterbits}=="32"looking at parent device '/devices/platform/ahci.0/ata4/host3/target3:0:0':KERNELS=="target3:0:0"SUBSYSTEMS=="scsi"DRIVERS==""looking at parent device '/devices/platform/ahci.0/ata4/host3':KERNELS=="host3"SUBSYSTEMS=="scsi"DRIVERS==""looking at parent device '/devices/platform/ahci.0/ata4':KERNELS=="ata4"SUBSYSTEMS==""DRIVERS==""looking at parent device '/devices/platform/ahci.0':KERNELS=="ahci.0"SUBSYSTEMS=="platform"DRIVERS=="ahci"ATTRS{modalias}=="platform:ahci"looking at parent device '/devices/platform':KERNELS=="platform"SUBSYSTEMS==""DRIVERS==""

  可以看到,树根是platform,中间控制器scsi,最后是block

  另外,需要注意到,父节点中名称和属性都带S,本节点中不带S,这一点在书写规则文件时也适用。即规则文件中,如果是匹配父节点的属性,则需要使用ATTRS。

  规则文件中至少需要一个匹配和一个赋值,匹配使用==,赋值使用=,赋值可以是重命名节点相关属性,或者执行定制动作。

  使用udev工具主要就是通过规则匹配来执行相关动作,所以规则文件匹配很重要。但是事件的产生,比如设备插拔等,是需要一定条件的,这对规则文件的验证带来了一些麻烦

  能否模拟整个过程,对规则进行快速验证调试呢?如果可以做到这点,那么对提高效率,就非常有帮助了。

  udevadm提供了多个选项,可以帮助用户快速调试验证规则。

  首先,让目标设备正常加载进系统中

  然后,使用前面的udevadm info选项,查看系统中的事件信息,包括一些本地属性和父节点信息

  利用上述信息,编写初步的规则文件

  使用命令udevadm test /sys/devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd模拟规则的匹配和执行过程

  上述命令后面部分是具体设备信息,该命令选项只是模拟过程,不会真正执行

  命令也会输出规则文件的解析优先级,使用该命令可进行初步调试

 

  下面进行正式的验证

  首先,我们可以启动udevadm monitor,监控实时的事件信息,为调试提供分析依据,如下所示:

udevadm monitor --propertymonitor will print the received events for:UDEV - the event which udev sends out after rule processingKERNEL - the kernel ueventKERNEL[1624468946.462053] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd (block)UDEV_LOG=3ACTION=addDEVPATH=/devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sddSUBSYSTEM=blockDEVNAME=sddDEVTYPE=diskNPARTS=3SEQNUM=1416MAJOR=8MINOR=48UDEV  [1624468946.474712] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd (block)UDEV_LOG=3ACTION=addDEVPATH=/devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sddSUBSYSTEM=blockDEVNAME=/dev/sddDEVTYPE=diskNPARTS=3SEQNUM=1416MAJOR=8MINOR=48

  monitor会输出内核的uevent事件和udev处理后输出的event

  其次,使用udevadm trigger触发事件,比如对于上述硬盘加载,可以用如下触发命令

  udevadm trigger --action=add --subsystem-match=block --sysname-match=sdd

  udevadm trigger --action=add --subsystem-match=block --sysname-match=sd*

  trigger支持shell的通配符匹配,只触发满足规则的节点的事件,这一点需要注意,比如对于上面的第一条规则,monitor输出

  KERNEL[1624533496.063615] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd (block)KERNEL[1624533496.063753] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd1 (block)KERNEL[1624533496.063840] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd2 (block)KERNEL[1624533496.063919] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd3 (block)

  对于上述第二条,monitor输出

  KERNEL[1624533496.063995] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.1/1-1.4.1:1.0/host4/target4:0:0/4:0:0:0/block/sdb (block)KERNEL[1624533496.064080] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2:1.0/host5/target5:0:0/5:0:0:0/block/sda (block)KERNEL[1624533496.064181] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2:1.0/host5/target5:0:0/5:0:0:0/block/sda/sda1 (block)KERNEL[1624533496.064269] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/host6/target6:0:0/6:0:0:0/block/sdc (block)UDEV  [1624533496.081699] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.1/1-1.4.1:1.0/host4/target4:0:0/4:0:0:0/block/sdb (block)UDEV  [1624533496.082981] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.3/1-1.4.3:1.0/host6/target6:0:0/6:0:0:0/block/sdc (block)UDEV  [1624533496.083941] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2:1.0/host5/target5:0:0/5:0:0:0/block/sda (block)UDEV  [1624533496.085070] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd (block)UDEV  [1624533496.103061] add      /devices/platform/hiusb-ehci.0/usb1/1-1/1-1.4/1-1.4.2/1-1.4.2:1.0/host5/target5:0:0/5:0:0:0/block/sda/sda1 (block)UDEV  [1624533496.107014] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd3 (block)UDEV  [1624533496.107077] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd2 (block)UDEV  [1624533496.112003] add      /devices/platform/ahci.0/ata4/host3/target3:0:0/3:0:0:0/block/sdd/sdd1 (block)

  可见,monitor输出为满足trigger条件的节点,并未输出父节点或子节点

 

  另外,trigger可以匹配的选项也是比较多的,可以支持attribute匹配,如下

  udevadm trigger --action=add --subsystem-match=block --attr-match=size=7814037168

  使用上述命令时,需要注意只输出符合条件的节点,另外,发现trigger不触发同时匹配父子节点的条件

udevadm trigger --action=add    --attr-match=model=ST4000VX005-2LY1 --attr-match=size=7814037168

  这一点与上面所述的规则也是一致的

 

  trigger触发事件后,udev就会匹配规则文件,然后执行动作,通过观察monitor的输出,检查动作的执行是否符合预期。

  另外,udevadm control可以修改udev后台例程的日志级别

  实际设备上发现,修改udev.conf文件,将日志级别从err改为debug或info后,系统启动不了,加载根文件系统后,不再进一步加载其他程序,这一点待研究确认。

 

  通过上述流程,可以发现,新接入的设备,会由内核产生event,udev可以捕获该event

  如果错过设备接入时机,没有捕获事件,可以通过trigger主动触发,让内核将之前保存的事件再次通知到应用层,同样可以匹配规则执行动作

  所以结合sysfs和udev可以解决设备的重命名和挂载等处理需求

 

  最后补充强调一下,

  这里的trigger本质上是让内核重新发出事件,也就是说,实际上事件已经错过了。

  根文件系统加载后,对于用户空间加载前,即udev本身启动监控前,内核驱动加载过程中已经识别和加载的设备,如何进行配置,就是依靠该命令

  但是udev是在用户空间启动的,所以udev启动后,如果需要处理内核加载过程中的设备事件信息,就需要重新触发。但此时,该如何确定匹配条件呢?

  答案是直接执行udevadm trigger,不加参数,此时内核会将所有产生的事件全部上报,由udev按需处理。

11 系统中的USB设备 

  执行lsusb命令输出如下内容

  Bus 002 Device 001: ID 1d6b:0001 主机控制器 根HUBBus 001 Device 001: ID 1d6b:0002 主机控制器 根HUBBus 001 Device 002: ID 05e3:0610 USB HUBBus 001 Device 003: ID 05e3:0610 USB HUBBus 001 Device 004: ID 05e3:0610 USB HUBBus 001 Device 009: ID 1c9e:9b3c 龙尚模块Bus 001 Device 006: ID 0424:2240 USB读卡器Bus 001 Device 007: ID 0424:2240 USB读卡器Bus 001 Device 008: ID 0424:2240 USB读卡器Bus 001 Device 005: ID 0403:6011 USB转串口Bus 001 Device 010: ID 1c9e:9b3c 龙尚模块Bus 003 Device 001: ID 1d6b:0002 主机控制器 根HUBBus 003 Device 002: ID 0eef:0001 触摸屏Bus 004 Device 001: ID 1d6b:0003 主机控制器 根HUB

  从上面可以看出,有四个总线,每个总线上各有1个或多个设备

  从CPU角度来看,整体的USB树形结构如下图所示:

CPU --ohci 根设备,全速设备--usb2 [1d6b:0001] 主机USB控制器--ehci 根设备,高速设备--usb1 [1d6b:0002] 主机USB控制器--1-1 [05e3:0610] USB HUB--1-1.1 [1c9e:9b3c] 龙尚模块--1-1.4 [05e3:0610] USB HUB--1-1.4.1 [0424:2240] 三个存储卡USB口读卡器--1-1.4.2 [0424:2240]--1-1.4.3 [0424:2240]--1-1.2 nop--1-1.3 nop--1-2 [05e3:0610] USB HUB--1-2.1 [0403:6011] USB转串口--1-2.1:1.0 转换的多个串口--1-2.1:1.1--1-2.1:1.2--1-2.1:1.3--1-2.2 [1c9e:9b3c] 龙尚模块--xhci 根设备,USB3.0--usb3 [1d6b:0002] 主机USB控制器--touch [0eef:0001] 触摸屏--usb4 [1d6b:0003] 主机USB控制器--usb4 [1d6b:0003] 主机USB控制器

  CPU本身带了三个控制器,分别支持全速,2.0以及3.0的USB设备。

12 网络子系统

   文件抽象特性在网络子系统表达能力不强。

   不过,仍然可以通过iNode将网络子系统中的资源和对象跟文件关联起来,这对特定情况下的问题查找很有帮助。

   区分路由策略和路由表

   待补充。

13 文件子系统

   关键几个数据结构

   超级块  inode  目录  文件   等。

   文件子系统有两个主要问题需要处理,一个是高效的组织结构;一个是一致性。

   这里一致性是更加棘手的一个问题。文件系统主要通过两个手段来保证一致性,一个是日志,一个是写时复制。

   除此,还有其他一些原则,包括读写、节点、速度、大小、压缩、缓存、备份、索引、均衡、随机等原则。

   具体参见博客:

   7.5 文件系统_龙赤子的博客-CSDN博客

  

   关于缓存,多说一点。

   页缓存与缓冲区缓存。文件子系统构建后,优化的一大目标就是缓冲。我们知道,机械硬盘的吞吐量跟CPU和内存的处理速度差异太大。

   特别是近二三十年,摩尔定律使得CPU处理性能不断翻翻,但是机械硬盘的速度,并没有太大的改进。为了匹配速度上的差异,就需要缓存来解决。

   在嵌入式领域,很多时候使用flash作为数据断电保存的介质。相对机械动作,电子芯片的处理速度有很大的提升,但是跟CPU和内存相比,仍然有很大差距,所以缓存仍然是需要的。

   最开始,块设备缓冲(更多针对直接操作物理设备块)是单独的,跟页缓冲(更多是针对文件映射)没有关系,这样一来,同一份数据,在内核中就可能存在多份。

   后来,将二者整合到一起,在底层都是基于页缓冲。按物理页操作,也是内核擅长的。

  

   实际中可能出现文件内容改变、损坏、丢失的情况。解决思路是

   A 文件定期备份

   B 分类管理,比如对于不变文件,保证只读属性,减少出错可能

   C 监测文件IO状态,获取相关信息,辅助问题分析

   D 异常断电、关机的特殊处理

   E 电磁隔离保护

   F 专用模块负责文件读写管理。

四 运行的内核

  1 可以把内核想象为一个大进程,把自己想想成CPU,CPU就是一些寄存器的集合加逻辑处理过程。

  2 内存视图看内核,Linux 的内存视图

  参见博客:

  学内核之十六:linux内存管理结构大蓝图_龙赤子的博客-CSDN博客

 

  包括内存实体 :

  任务结构 链条 地址空间

  3 内核与应用层的交互途径:

  proc

  sys

  dev

  ioctl

  netlink

  unix socket

  4 关于堆栈

  堆栈分内核堆栈和应用堆栈

  对于ARM来讲,在内核配置unwind选项的情况下,堆栈是通过解析unwind段来回溯的。

  unwind段中记录了各个函数的入栈指令,然后根据发生异常时的PC地址,定位到具体的函数,之后反推堆栈操作,得到上一级的lr和fp地址

  lr为调用函数的返回地址,通过该寄存器内容可以知道调用者是那个函数

  fp为堆栈指针,通过该寄存器可以定位堆栈边界,这样一级一级回溯,即可获取调用栈信息。

  关于内核调用栈的回溯,在内核unwind.c代码中

  对CPU和堆栈的关系理解,可参见博主的文章:

  学内核之四:关于内核与硬件的衔接_龙赤子的博客-CSDN博客

 

  5 关于内核调试分析

  perf 性能跟踪 大框架

  ftrace 函数调用跟踪

  ebpf 事件跟踪

上一篇:Unity UI框架

下一篇:webRTC

相关内容

热门资讯

喜欢穿一身黑的男生性格(喜欢穿... 今天百科达人给各位分享喜欢穿一身黑的男生性格的知识,其中也会对喜欢穿一身黑衣服的男人人好相处吗进行解...
发春是什么意思(思春和发春是什... 本篇文章极速百科给大家谈谈发春是什么意思,以及思春和发春是什么意思对应的知识点,希望对各位有所帮助,...
网络用语zl是什么意思(zl是... 今天给各位分享网络用语zl是什么意思的知识,其中也会对zl是啥意思是什么网络用语进行解释,如果能碰巧...
为什么酷狗音乐自己唱的歌不能下... 本篇文章极速百科小编给大家谈谈为什么酷狗音乐自己唱的歌不能下载到本地?,以及为什么酷狗下载的歌曲不是...
华为下载未安装的文件去哪找(华... 今天百科达人给各位分享华为下载未安装的文件去哪找的知识,其中也会对华为下载未安装的文件去哪找到进行解...
怎么往应用助手里添加应用(应用... 今天百科达人给各位分享怎么往应用助手里添加应用的知识,其中也会对应用助手怎么添加微信进行解释,如果能...
家里可以做假山养金鱼吗(假山能... 今天百科达人给各位分享家里可以做假山养金鱼吗的知识,其中也会对假山能放鱼缸里吗进行解释,如果能碰巧解...
四分五裂是什么生肖什么动物(四... 本篇文章极速百科小编给大家谈谈四分五裂是什么生肖什么动物,以及四分五裂打一生肖是什么对应的知识点,希...
一帆风顺二龙腾飞三阳开泰祝福语... 本篇文章极速百科给大家谈谈一帆风顺二龙腾飞三阳开泰祝福语,以及一帆风顺二龙腾飞三阳开泰祝福语结婚对应...
美团联名卡审核成功待激活(美团... 今天百科达人给各位分享美团联名卡审核成功待激活的知识,其中也会对美团联名卡审核未通过进行解释,如果能...