代码补丁
[TOC] static_call 和 jump_label 的区别及异同点static_call 和 jump_label 都是 Linux 内核中的优化机制,旨在提高性能,减少运行时的分支判断和间接调用开销。尽管它们的目标相似,但它们的实现方式和应用场景有所不同。 相同点 动态修改代码路径: 两者都支持在运行时动态修改代码路径,从而实现功能的启用或禁用。 通过修改指令(代码补丁),避免了传统的条件分支或间接调用的性能开销。 性能优化: 两者都旨在减少分支预测失败或间接调用的开销,适用于性能敏感的代码路径。 运行时灵活性: 两者都允许在运行时动态切换功能或行为,而无需重新编译或重启系统。 代码补丁机制: 两者都依赖于代码补丁(code patching)技术,通过修改内存中的指令来实现动态行为。 不同点 特性 static_call jump_label 主要用途 用于优化函数调用,将间接调用替换为直接调用。 用于动态启用或禁用代码块,优化条件分支判断。 优化的内容 函数调用路径(间接调用 → 直接调用)。 条件分支路径(条件判...
内核支持与数据
[toc] Makefile宏LINUX_ARM_ARCH12345678910111213141516//arch/arm/Makefile# Note that GCC does not numerically define an architecture version# macro, but instead defines a whole series of macros which makes# testing for a specific architecture or later rather impossible.cpp-$(CONFIG_CPU_32v7M) :=-D__LINUX_ARM_ARCH__=7cpp-$(CONFIG_CPU_32v7) :=-D__LINUX_ARM_ARCH__=7cpp-$(CONFIG_CPU_32v6) :=-D__LINUX_ARM_ARCH__=6# Only override the compiler option if ARMv6. The ARMv6K extensions are# always a...
底层CPU与体系结构宏
[toc] include/asm-generic/rwonce.h: 提供 READ_ONCE() 和 WRITE_ONCE() 宏,防止编译器优化,保证单次读写的原子性1234567/* * 阻止编译器合并或重新获取读取或写入。还禁止编译器对 READ_ONCE 和 WRITE_ONCE 的连续实例重新排序,但前提是编译器知道某些特定排序。使编译器了解 Sequences 的一种方法是将 READ_ONCE 或 WRITE_ONCE 的两次调用放在不同的 C 语句中。 * * 这两个宏也适用于聚合数据类型,如结构体或联合体。 * * 它们的两个主要用例是:(1) 调解进程级代码和 irq/NMI 处理程序之间的通信,所有处理程序都运行在同一个 CPU 上,以及 (2) 确保编译器不会折叠、纺锤或以其他方式破坏不需要排序或与提供所需排序的显式内存屏障或原子指令交互的访问。 */ compiletime_assert_rwonce_type __native_word 是一个宏,用于检查给定类型是否是本机字长(通常是 32 位或 64 位)。如果类型不...
通用工具与错误处理宏
[toc] include/linux/once_lite.h: (一次性调用) 提供确保某段代码在多核环境下只被精确执行一次的宏 每个宏仅在第一次使用时,执行函数功能.通过静态变量来实现一次性调用的功能 12345678910111213141516171819202122232425262728/* 调用一次函数。类似于 DO_ONCE(),但不通过jump label使用跳转标签修补。 */#define DO_ONCE_LITE(func, ...) \ DO_ONCE_LITE_IF(true, func, ##__VA_ARGS__)//通过静态变量来实现一次性调用的功能#define __ONCE_LITE_IF(condition) \ ({ \ static bool __section(".data..once") __already_done; \ bool __ret_cond = !!(condition); \ bool __ret_once = fal...
通用数学与位操作宏
[toc] include/asm-generic/div64.h : 提供64位除法操作的通用实现# arch/arm/include/asm/div64.h1234567891011121314151617181920212223242526272829/* * __div64_32() 的语义是: * * uint32_t __div64_32(uint64_t *n, uint32_t base) * { * uint32_t remainder = *n % base; * *n = *n / base; * return remainder; * } * * 换句话说,一个 64 位的被除数和一个 32 位的除数产生 64 位的结果和 32 位的余数。 为了以最佳方式实现这一点,我们覆盖了 lib/div64.c 中的通用版本,以使用完全非标准参数和结果调用约定的 __do_div64 程序集实现(当心)。 */static inline uint32_t __div64_32...
crc32
[TOC] lib/crc32.c 循环冗余校验库(Cyclic Redundancy Check Library) 通用的数据完整性校验算法历史与背景这项技术是为了解决什么特定问题而诞生的?lib/crc32.c 提供的是循环冗余校验(CRC32)算法的内核标准实现。这项技术的核心目标是解决数据完整性(Data Integrity)问题。在数据传输(如网络通信)和存储(如磁盘读写)过程中,由于硬件故障、电气噪声或其他物理干扰,数据可能会发生意外的、非恶意的损坏(即比特翻转)。CRC32 旨在提供一个高效、可靠的方法来检测这些随机错误。 它通过为一个数据块计算出一个短小的、固定长度的“校验和”(checksum),附加在数据块的末尾。接收方或读取方对收到的数据块执行相同的计算,并将结果与附加的校验和进行比较。如果不匹配,就意味着数据在传输或存储过程中发生了损坏。 它的发展经历了哪些重要的里程碑或版本迭代?CRC 算法本身是信息论领域的经典算法,其在 Linux 内核中的实现则随着计算机体系结构的发展而不断演进和优化: 基本查表法(Table-Driven):最初和最基...
dump_stack
[TOC] lib/dump_stack.c 栈回溯打印(Stack Trace Dumping) 内核调试与错误诊断的基石历史与背景这项技术是为了解决什么特定问题而诞生的?lib/dump_stack.c 中的功能是为了解决内核开发和运维中最核心的一个问题:当内核遇到意外的、严重的状态(如错误、警告、崩溃)时,如何快速定位问题的根源? 在复杂的操作系统内核中,一个函数的执行可能是由一个非常深的函数调用链触发的。当在某个底层函数中检测到错误时,仅仅知道“这里出错了”是远远不够的,开发者必须知道“内核是如何执行到这里的?”。dump_stack 技术就是为了回答这个问题,它提供了以下关键能力: 上下文追溯(Contextual Traceability):它能打印出当前的函数调用链(Call Trace / Stack Trace),清晰地展示从触发点一直回溯到调用栈顶层的路径。这对于理解错误发生的上下文至关重要。 状态快照(State Snapshot):除了函数调用链,它还能打印出当前CPU的寄存器值、栈内容等关键信息,为事后调试(post-mortem ...
hash
[TOC] lib/hashtable.h & include/linux/hash.h 哈希表与哈希函数(Hash Table & Hash Functions) 内核中快速数据查找的基础设施历史与背景这项技术是为了解决什么特定问题而诞生的?哈希表(Hash Table)和哈希函数(Hash Functions)是为了解决一个计算机科学中的基础问题而诞生的:如何实现高效的数据查找、插入和删除。在操作系统内核中,需要管理大量的对象,例如进程、打开的文件、内存页面、缓存的数据块(inodes, dentries)等。对这些对象进行快速访问是保证系统整体性能的关键。 具体来说,这项技术解决了以下问题: 性能瓶OT颈:如果使用简单的链表来管理这些对象,那么每次查找都需要遍历整个列表,其时间复杂度为O(n),当对象数量n巨大时,性能会急剧下降。 代码重复:在哈希表通用框架出现之前,内核中有数十个甚至更多的子系统都各自实现了自己的哈希表逻辑。 这导致了大量的代码重复、不一致的实现和潜在的bug分散在各处。 可扩展性:随着硬件的发展,内存容量不...
idr
[TOC] lib/idr.c IDR/IDA机制(ID-to-Pointer/ID Allocator) 内核对象ID的分配与管理历史与背景这项技术是为了解决什么特定问题而诞生的?lib/idr.c 中的IDR(ID Radix Tree)和IDA(ID Allocator)机制是为了解决一个在内核中普遍存在的问题:如何为一个内核对象动态地分配一个唯一的、通常是小整数的ID,并能通过这个ID快速地反向查找到该对象。 这解决了以下几个关键痛点: 需要稳定的“句柄”:内核中的许多对象(如设备、定时器)需要被用户空间或其他子系统通过一个简单的整数ID来引用,这个ID就像一个“句柄”。直接暴露内核指针既不安全(违反KASLR)也不稳定(对象可能被重新分配)。 稀疏ID的空间效率:如果要支持的ID范围很大(例如0到INT_MAX),但实际同时存在的对象数量却相对较少,使用一个简单的指针数组(void *pointers[INT_MAX])将会造成巨大的内存浪费。IDR/IDA需要一种空间高效的方式来管理这种“稀疏”的ID分配。 ID的循环使用:当...
iov_iter
[toc] lib/iov_iter.c 通用 I/O 向量迭代器:用于分散/收集数据的通用句柄历史与背景这项技术是为了解决什么特定問題而诞生的?这项技术以及其核心数据结构struct iov_iter,是为了解决Linux内核I/O栈中一个长期存在的、导致代码重复和不兼容的根本性问题:缺乏一个统一的、通用的方式来表示和操作非连续的内存缓冲区。 统一数据源和目的地:在iov_iter出现之前,内核的不同子系统使用各自不同的方式来描述数据缓冲区。例如: 用户空间通过readv/writev系统调用传入一个struct iove数组。 内核内部可能使用struct kvec数组来表示内核空间的非连续缓冲区。 块设备层使用struct bio_vec(bvec)来描述直接指向物理页面的缓冲区,用于DMA。 管道(Pipes)有自己的struct pipe_buffer。这个多样性导致了一个严重的问题:如果你想把数据从一个地方(比如用户空间的iovec)移动到另一个地方(比如一个网络套接字的缓冲区),你需要编写专门的、针对这两种特定缓冲...








