内核支持与数据
[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 avai...
read_write
[toc] fs/read_write.c 文件读写VFS实现(File Read/Write VFS Implementation) read/write系统调用的通用入口历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是VFS(虚拟文件系统)最核心、最基础的组成部分,它为了解决一个操作系统设计的根本性问题而诞生:如何为所有类型的文件和设备提供一个统一的、标准的、可移植的读写接口。 在VFS和fs/read_write.c所代表的抽象层出现之前,应用程序需要为每一种不同的文件系统编写不同的代码来进行读写,这是不可想象的。fs/read_write.c通过实现read(2), write(2)及其变体这一系列系统调用,解决了以下核心问题: 抽象与统一:无论底层是ext4文件、一个管道(pipe)、一个终端设备(tty)还是一个socket,用户空间程序都可以使用相同的read()和write()系统调用来进行I/O操作。read_write.c负责将这些通用的请求,分派给具体的文件系统或驱动程序去处理。 可移植性:它遵循了POS...
通用工具与错误处理宏
[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 = false;...
代码补丁
[TOC] static_call 和 jump_label 的区别及异同点static_call 和 jump_label 都是 Linux 内核中的优化机制,旨在提高性能,减少运行时的分支判断和间接调用开销。尽管它们的目标相似,但它们的实现方式和应用场景有所不同。 相同点 动态修改代码路径: 两者都支持在运行时动态修改代码路径,从而实现功能的启用或禁用。 通过修改指令(代码补丁),避免了传统的条件分支或间接调用的性能开销。 性能优化: 两者都旨在减少分支预测失败或间接调用的开销,适用于性能敏感的代码路径。 运行时灵活性: 两者都允许在运行时动态切换功能或行为,而无需重新编译或重启系统。 代码补丁机制: 两者都依赖于代码补丁(code patching)技术,通过修改内存中的指令来实现动态行为。 不同点 特性 static_call jump_label 主要用途 用于优化函数调用,将间接调用替换为直接调用。 用于动态启用或禁用代码块,优化条件分支判断。 优化的内容 函数调用路径(间接调用 → 直接调用)。 条件分支路径(条件判断 →...
通用数学与位操作宏
[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(ui...
底层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 位)。如果类型不是本机...
completion
kernel/sched/completion.c 内核同步原语(Kernel Synchronization Primitive) 简洁的任务完成信号量历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及它所实现的“完成量”(Completion),是为了提供一个高度简化的、专门用于解决“一个执行单元等待另一个执行单元完成某项工作”这一特定同步场景的内核原语。 简化样板代码:在completion出现之前,要实现这种“等待-通知”的模式,开发者必须手动组合更底层的原语。这通常意味着: 定义一个wait_queue_head_t(等待队列头)。 定义一个bool或int类型的标志位来表示任务是否完成。 等待者需要在一个循环中调用wait_event_interruptible(),这个宏会自动处理将任务加入等待队列、睡眠、被唤醒后检查标志位、处理伪唤醒等一系列复杂操作。 完成者需要设置标志位,然后调用wake_up()来唤醒等待者。这个过程虽然强大,但对于一个非常常见的模式来说,显得过于繁琐且容易出错(例如,忘记处理竞态条件)。 解决竞态条件:...
cpu
[TOC] include/linux/cpumask.hcpumask_check 验证当前cpu数量是否超过了配置的最大cpu数量,并返回cpu1234567891011121314151617// 验证当前cpu数量是否超过了配置的最大cpu数量static __always_inline void cpu_max_bits_warn(unsigned int cpu, unsigned int bits){#ifdef CONFIG_DEBUG_PER_CPU_MAPS WARN_ON_ONCE(cpu >= bits);#endif /* CONFIG_DEBUG_PER_CPU_MAPS */}/* verify cpu argument to cpumask_* operators *///验证当前cpu数量是否超过了配置的最大cpu数量static __always_inline unsigned int cpumask_check(unsigned int cpu){ //small_cpumask_...
cred
[TOC] kernel/cred.c 凭证管理(Credential Management) 内核中任务身份与权限的核心历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及其核心数据结构struct cred,是为了解决在现代多用户、多进程操作系统中一个根本性的安全问题:如何安全、高效、无竞争地管理和访问一个任务(进程或线程)的身份和权限集合。 集中化身份信息:一个任务的“身份”是复杂的,它包含了用户ID(UID)、组ID(GID)、补充组列表、安全标签(如SELinux上下文)、权能(Capabilities)等一系列信息。在struct cred出现之前,这些信息分散地存储在task_struct(进程描述符)中。 解决竞态条件与锁争用:直接修改task_struct中的权限字段是一个巨大的安全隐患。例如,如果一个线程正在修改自己的UID,而另一个线程同时在检查这个UID以决定是否允许某个操作,就会产生严重的竞态条件。为了保护这些字段,task_struct需要一个锁,但这在高并发系统(如大型Web服务器)中会成为严重的性能瓶颈,因为权限检查是内核中最...
seq_file
[toc] fs/seq_file.c 序列文件接口(Sequential File Interface) 构建大型虚拟文件的标准工具历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术以及它所实现的seq_file(Sequential File)接口,是为了从根本上解决Linux内核早期在创建虚拟文件(尤其是在/proc文件系统中)时遇到的几个严重问题: 4KB(PAGE_SIZE)的输出限制:在seq_file出现之前,实现一个/proc文件的标准方法是read_proc回调。这个回调函数被要求一次性地将所有输出内容生成到一个大小固定的缓冲区中(通常为一个页,即4KB)。如果输出内容超过了这个大小,就会被无情地截断。这对于显示大量信息(如系统中的所有mount点、中断、或者大量的内核调试信息)的场景来说是一个致命的限制。 复杂的实现和状态管理:read_proc回调需要开发者手动管理文件位置(offset),以支持用户空间程序多次read()一个文件。这个过程非常繁琐且极易出错。 并发不安全:在多核(SMP)系统上,read_proc的实现很难保证原子性。...