init
[TOC] init/init_task.c 内核线程的一个核心特征是:它们没有自己独立的用户地址空间。它们只在内核空间运行,而内核地址空间是所有进程共享的。因此,内核线程不需要一个属于自己的内存描述符 struct mm_struct,所以它们的 task->mm 指针通常是 NULL init_task 就是大名鼎鼎的 PID 0 进程,也常被称为 swapper 进程。从它的标志位 .flags = PF_KTHREAD 可以看出,它是一个内核线程。 init_task 的调度策略(policy)是 SCHED_NORMAL,这意味着它是一个普通的分时调度任务,而不是实时任务。但是初始化阶段调用了init_idle(),使得它的sched_class 是 SCHED_IDLE,这样它就可以作为 CPU 的空闲任务运行。但是fork出来的其他进程继承的还是 SCHED_NORMAL 策略。 进程的“始祖”:init_task 是系统中所有进程的祖先。在系统启动后,它会创建第一个内核线程 kernel_init(它最终会成为 PID 1 的 i...
shell命令
[TOC] 语法if 条件语句 if:用于执行一个命令并根据其退出状态码执行不同的操作。 $(if $(KBUILD_OUTPUT),, ...): 这是一个条件判断语句。(if ...) 函数的语法是 $(if condition, then-part, else-part)如果 condition 为真,则执行 then-part;否则,执行 else-part。 环境变量 shift 命令用于移动参数 shift 命令用于移动参数。它会将所有参数左移一个位置,即 $2 的值赋给 $1,$3 的值赋给 $2,以此类推。$1 的值会被丢弃,而 $0(脚本名称)不会受到影响。 local 命令用于声明局部变量${parameter+word} 用于检查变量是否已经定义 一种参数替换语法,用于检查变量是否已设置并根据结果返回不同的值。以下是对这种语法的详细解释: 1${parameter+word} 如果 parameter 已设置且不为空,则结果为 word。 如果 parameter 未设置或为空,则结果为空字符串。 标志$BASH 指向的 she...
linux_makefile
[TOC] 阅读技巧 使用make V=1来查看详细的编译过程 使用make -p来查看所有的变量和规则 顶层makefile判断GUN make 版本 检查当前的 Make 版本以确保满足条件 如果 output-sync 不在其中,这意味着当前使用的 GNU Make 版本低于 4.0,因此代码会触发一个错误,提示用户需要 GNU Make 4.0 或更高版本,并显示当前的 Make 版本 $(MAKE_VERSION)。 123ifeq ($(filter output-sync,$(.FEATURES)),)$(error GNU Make >= 4.0 is required. Your Make version is $(MAKE_VERSION))endif 检测内部变量是否被覆盖 检查 $(MAKECMDGOALS) 变量中是否包含以 __ 开头的目标。$(MAKECMDGOALS) 是一个特殊变量,包含了命令行中指定的所有目标。如果发现有以 __ 开头的目标,代码会触发一个错误,提示这些目标仅供内部使用。这种检查有助于防止用户意外调用内部目标,确保构...
构建说明
[TOC] art-pi 构建命令12345678910111213141516171819202122232425262728293031export CROSS_COMPILE=arm-none-eabi- ARCH=armmake stm32_defconfigmake menuconfig > General setup [*] Initial RAM filesystem and RAM disk (initramfs/initrd) support > Device Drivers > Block devices [*] RAM block device support (1) Default number of RAM disks (2048) Default RAM disk size (kbytes) > System Type (0xC0000000) (S)DRAM Base Address (0x02000000) (...
bio
[toc] block/bio.c 块I/O核心结构(Block I/O Core Structure) Linux I/O请求的载体历史与背景这项技术是为了解决什么特定问题而诞生的?struct bio 及其管理代码 block/bio.c 是为了解决Linux内核中一个根本性的I/O请求表示和传递问题而诞生的。它旨在取代一个更早、更原始的结构——struct buffer_head (bh)——作为I/O请求的主要载体。 buffer_head 存在以下严重问题,限制了I/O性能和系统的可扩展性: 粒度过小:一个buffer_head严格地代表单个磁盘块(例如512字节或4KB)在内存中的缓存。对于一个大的I/O操作(例如写入64KB数据),内核需要创建和管理16个独立的buffer_head对象,这非常低效。 紧密耦合:buffer_head将I/O请求(“我要写这个块”)和内存缓存(“这个块在内存中的副本”)这两个概念紧紧地耦合在一起。这种设计使得实现绕过页面缓存的直接I/...
blk-ioc
[toc] block/blk-ioc.c I/O上下文管理(I/O Context Management) 进程I/O优先级的关联与继承历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决在多任务操作系统中,如何区分和管理不同进程发起的I/O请求的重要性,从而实现更智能、更公平的I/O调度。 在blk-ioc.c(I/O Context)所代表的机制出现之前,内核的I/O调度器(I/O Scheduler)对所有进程发起的I/O请求几乎一视同仁。这会导致严重的问题: 优先级反转:一个高优先级的CPU密集型任务(如交互式桌面应用)可能会因为一个低优先级的后台I/O密集型任务(如文件索引、备份)而变得卡顿。后台任务产生的大量磁盘I/O请求会填满I/O队列,使得前台应用的关键数据读写请求需要等待很长时间。 资源争用不公:多个进程同时进行磁盘读写时,无法区分哪些进程的I/O应该被优先满足。例如,一个正在播放视频的媒体播放器和一个正...
blk-mq
[toc] block/blk-mq.c 多队列块层核心(Multi-Queue Block Layer Core) 现代存储I/O性能的基石历史与背景这项技术是为了解决什么特定问题而诞生的?blk-mq(Block Multi-Queue)框架的诞生是为了从根本上重构Linux的块设备层,以适应现代存储硬件的飞速发展,特别是高速闪存设备(SSD、NVMe)的出现。 传统的Linux块层(single-queue block layer)是为机械硬盘(HDD)设计的,其核心是一个per-device的单一请求队列。这种设计在HDD时代是合理的,因为磁盘的机械寻道时间是主要瓶颈。然而,随着能够处理数十万甚至数百万IOPS(每秒I/O操作数)的闪存设备的普及,这个单一队列的设计成为了新的、严重的性能瓶颈: 锁争用:在多核CPU系统上,所有核心提交I/O时都必须争抢保护这个单一队列的全局锁。这种锁争用导致CPU无法有效扩展,即使硬件有能力处理更多请求,软件层面也无法将请求高效地提交给硬件。 缓存行弹跳:对单一队列的频繁访问导致其数据所在的缓存行...
block
[TOC] Linux 源码中的 block 目录:块设备 I/O 的核心中枢block 目录是 Linux 内核 I/O 栈的心脏。它负责管理所有块设备(如硬盘驱动器 HDD、固态硬盘 SSD、U 盘等)的数据交换。这一层的主要目标是提供一个通用的、高效的框架,将上层文件系统和应用程序的 I/O 请求,转化为底层具体硬件驱动程序可以执行的操作。 一、 历史与背景这项技术是为了解决什么特定问题而诞生的? block 层的诞生是为了解决两个核心问题: 抽象与解耦:如果没有一个通用的块设备层,每个文件系统(如 ext4, XFS)都需要自己编写直接与各种硬盘驱动(SATA, SCSI, NVMe)对话的代码。这会导致代码冗余、开发复杂且难以维护。block 层提供了一个标准的接口,使得文件系统无需关心底层硬件的具体细节,反之亦然。 性能优化:对存储设备的随机访问通常效率很低,尤其是在机械硬盘上,会导致磁头频繁寻道,浪费大量时间。block 层通过引入 I/O 调度器 (I/O Scheduler),可以对传入的 I/O 请...
genhd
[toc] block/genhd.c 通用硬盘驱动(Generic Hard Disk Driver) 内核中块设备的表示与管理历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了在Linux内核中创建一个统一的、抽象的块设备表示,以解决如何管理和表示各种各样的块存储设备(如硬盘、软盘、U盘、RAID卷等)的问题。 在genhd.c(Generic Hard Disk)所代表的框架出现之前,内核中对不同类型块设备的管理是零散和不一致的。genhd.c的诞生旨在解决以下核心问题: 设备抽象:需要一个通用的数据结构来描述一个块设备,无论它是物理硬盘、一个硬盘上的分区,还是一个由多个磁盘组成的逻辑卷。这个结构就是struct gendisk。 分区管理:一个物理磁盘通常被划分为多个分区。内核需要一个标准的机制来发现、解析和表示这些分区,并将每个分区也作为一个独立的块设备呈现给上层。genhd.c负责扫描分区表并为每个分区创建设备节点。 设备注册与命名:需要一个统一的机制来向内核注册新的块设备,并为其分配一个唯一的设备号(major/minor num...
amba
[TOC] drivers/amba: Linux的AMBA总线与SoC设备驱动核心drivers/amba 目录是 Linux 内核中用于管理和驱动基于 AMBA (Advanced Microcontroller Bus Architecture) 总线的外设的核心框架。在现代基于 ARM 的片上系统 (SoC) 中,几乎所有的片上外设(如 UART、GPIO、SPI、I2C、定时器等)都挂载在 AMBA 总线上。因此,这个目录是 ARM SoC 平台驱动程序的基石。 一、 历史与背景这项技术是为了解决什么特定问题而诞生的? 在嵌入式系统中,特别是 SoC 中,外设不是像 PCI 或 USB 设备那样可以在运行时动态发现的(即非“热插拔”或“可枚举”的)。它们是静态地集成在芯片上的,其物理地址和中断号在芯片设计时就已经固定。 早期的 Linux 内核通过在 C 代码(board-*.c 文件)中硬编码这些“平台设备”(platform devices)的信息来支持它们。这种方法导致了巨大的问题: 内核与硬件紧密耦合: 每支持一款新的开发板,就需要编写一个新的 b...