nvmem
[toc] drivers/nvmem/core.c NVMEM核心(NVMEM Core) 非易失性内存的统一访问框架历史与背景这项技术是为了解决什么特定问题而诞生的?NVMEM(Non-Volatile Memory)子系统的诞生是为了解决一个在嵌入式系统中普遍存在的问题:如何以一种标准的、统一的方式来访问各种小型、非易失性存储设备中的原始数据。 在此框架出现之前,内核中没有一个专门的子系统来处理这类需求,导致了实现上的混乱: 缺乏统一接口:一个以太网驱动需要从板载的I2C EEPROM中读取MAC地址,而一个无线网卡驱动可能需要从SoC内部的EFUSE(电子熔丝)中读取校准数据。这些驱动不得不自己去实现与特定存储芯片(EEPROM, EFUSE, OTP等)的交互逻辑,或者依赖于特定平台的私有接口。 驱动间强耦合:设备驱动(消费者)被迫要知道提供数据的存储芯片(生产者)的具体细节。如果硬件设计发生变化,例如将MAC地址从EEPROM移到了SPI Flash的一个分区中,那么设备驱动的代码就需要进行重大修改。 代码重复与不可移植:每个需要读取配置数据的驱...
mmc
[toc] drivers/mmc 多媒体卡(MultiMediaCard)子系统 SD/eMMC/SDIO设备驱动框架历史与背景这项技术是为了解决什么特定问题而诞生的?drivers/mmc 子系统是为了给Linux内核提供一个统一的、可扩展的框架来支持一整类基于**多媒体卡(MultiMediaCard)**规范及其衍生协议的设备而诞生的。这些设备包括: MMC (MultiMediaCard):一种早期的闪存卡标准。 SD (Secure Digital) Card:在MMC基础上发展而来的、目前最普及的移动存储卡,增加了安全特性和更高的性能。 eMMC (embedded MMC):将MMC控制器和NAND闪存封装在同一个BGA芯片中,作为一种“嵌入式”存储解决方案,被广泛用作智能手机、平板电脑和许多嵌入式设备的“硬盘”。 SDIO (Secure Digital Input/Output):一种扩展规范,允许SD插槽除了支持存储卡外,还能连接I/O设备,如Wi-Fi模块、蓝牙模块、GPS接收器等。 在没有这个统一框架...
OF
[TOC] OF在 Linux 内核中,of 通常是 Open Firmware 的缩写。Open Firmware 是一种硬件设备描述标准,用于描述设备树(Device Tree)。设备树是一种数据结构,用于以树状层次结构描述硬件的布局和配置,特别是在嵌入式系统和 ARM 架构中广泛使用。 of 表示与设备树(Device Tree)相关的驱动代码。 fdt.c 表示与 Flat Device Tree(FDT,扁平设备树)相关的实现。 设备树的作用设备树的主要作用是将硬件信息从内核代码中分离出来,使得内核可以通过解析设备树来获取硬件配置,而无需硬编码。这种方式提高了内核的可移植性和灵活性。 在 Linux 内核中,fwnode 和 node 是两种不同的结构体,分别用于描述硬件设备的固件信息和设备树节点信息。它们的主要区别在于用途和适用场景。 fwnode和node的区别1. fwnode_handlefwnode_handle 是一个通用的固件节点(firmware node)抽象,用于描述硬件设备的固件信息。它可以适配多种固件接口,例如设备树(Device Tree...
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)移动到另一个地方(比如一个网络套接字的缓冲区),你需要编写专门的、针对这两种特定缓冲...
kobject
[TOC] lib/kobject.c 内核对象(Kernel Object) 设备模型的核心基石历史与背景这项技术是为了解决什么特定问题而诞生的?lib/kobject.c 及其核心数据结构 struct kobject 的诞生,是为了解决在Linux 2.5/2.6内核开发周期中遇到的一个根本性问题:缺乏一个统一的、内在一致的内核对象模型。 在kobject出现之前,内核充满了各种不相关的子系统,它们: 缺乏统一的生命周期管理:内核中创建了大量的动态对象,但没有一个标准的方法来跟踪它们的使用情况并安全地释放它们。这导致了复杂的、容易出错的手动引用计数或锁机制,是use-after-free和内存泄漏等bug的主要来源。 无法表示对象间的层次关系:物理世界中的硬件设备天然地具有层次结构(例如,一个USB鼠标连接到一个USB集线器,该集线器又连接到一个PCI总线上的USB控制器)。旧的内核模型无法以一种通用的方式来表达这种父子关系。 没有统一的内核-用户空间接口:procfs被滥用于向用户空间暴露各种各样的内核信息,但它缺乏结构和访问控制,变得杂乱无章。内核...
maple_tree
[TOC] lib/maple_tree.c 高性能B树实现(High-Performance B-Tree Implementation) VMA管理的核心数据结构历史与背景这项技术是为了解决什么特定问题而诞生的?Maple Tree(枫树)是为了解决Linux内核内存管理子系统中的一个核心性能瓶颈而设计的。具体来说,它是为了取代管理虚拟内存区域(Virtual Memory Areas, VMAs)的红黑树(Red-Black Tree)。 在Maple Tree出现之前,每个进程的内存地址空间(struct mm_struct)都使用一棵红黑树来组织其所有的VMA。当进程的VMA数量非常多时(例如大型数据库或科学计算应用),以及在多线程环境下,这棵红-黑树成为了一个严重的争用点: 锁争用(Lock Contention):对VMA树的任何修改(如mmap, munmap)都需要获取一个重量级的读写信号量(mmap_sem,现在是mmap_lock)。在写者持有锁期间,所有其他试图查找或修改VMA的线程都会被阻塞,这严重限制了内存密集型应用的可扩展性。 缓存效率低...
radix-tree
[TOC] lib/radix-tree.c 基数树(Radix Tree) 整数键到指针的高效映射历史与背景这项技术是为了解决什么特定问题而诞生的?lib/radix-tree.c 提供的基数树(Radix Tree)是为了解决一个在内核中非常常见的问题:如何将一个整数(特别是unsigned long类型)作为键,高效地、空间优化地映射到一个指针。 在基数树出现之前,内核中存在多种方式来解决这个问题,但各有缺点: 哈希表:对于稀疏的键(例如,文件偏移量,可能非常大且不连续),哈希表虽然平均查找速度快,但存在哈希冲突问题,且无法高效地进行范围查找或有序遍历。 红黑树:可以处理稀疏的键并支持有序遍历,但它是指针密集型的数据结构,每个节点都有左右子指针、父指针和颜色等额外开销,导致内存占用较高,且缓存效率不佳。 直接映射数组:如果键的范围不大且密集,这是最快的方法。但如果键的范围很大(例如unsigned long的所有可能值),创建一个如此巨大的指针数组是完全不可行的,会消耗天文数字般的内存。 基数树被设计出来,就是为了结合以上方法的优点,同时避免它们的缺点。它特别...
rbtree
[TOC] lib/rbtree.c 红黑树(Red-Black Tree) 内核中通用的有序数据管理历史与背景这项技术是为了解决什么特定问题而诞生的?lib/rbtree.c 提供的红黑树(Red-Black Tree)是为了解决一个在计算机科学和操作系统内核中都非常普遍的需求:如何在一个动态变化的数据集合中,高效地维护元素的有序性,并提供快速的查找、插入和删除操作。 在红黑树出现之前,内核中的有序数据管理主要依赖于: 有序链表:实现简单,但查找操作需要O(n)的时间,当数据量大时性能极差。 简单的二叉搜索树:在理想情况下查找性能是O(log n),但在最坏情况下(例如,按顺序插入元素)会退化成一个链表,性能同样下降到O(n)。 红黑树作为一种自平衡的二叉搜索树(Self-balancing Binary Search Tree),被引入来解决这个问题。它通过一套相对简单的规则(着色和旋转),确保树在任何插入和删除操作后都保持“大致平衡”,从而保证了其查找、插入和删除操作在最坏情况下的时间复杂度都能维持在O(log n)。这为内核中需要高效处理有序数据的子系统提供...
refcount
[TOC] include/linux/refcount.h 安全引用计数器(Safe Reference Counter) 防止Use-After-Free的专用原子计数器历史与背景这项技术是为了解决什么特定问题而诞生的?refcount_t 的诞生是为了解决一个在内核并发编程中长期存在的、非常严重的安全问题:使用通用的原子操作 (atomic_t) 来实现引用计数时存在的固有风险。 在 refcount_t 出现之前,内核中广泛使用 atomic_t 来管理共享对象的生命周期。这种做法虽然可行,但非常脆弱,是导致 use-after-free (UAF) 和 double-free 等严重安全漏洞的常见原因: 整数溢出 (Overflow):如果一个对象的引用计数持续增加,达到 atomic_t 能表示的最大值(UINT_MAX)时,下一次 atomic_inc() 会使其值回绕(wrap around)到 0。这会造成灾难性后果:一个实际上被大量使用的对象,其引用计数突然变为0,从而被错误地释放,导致所有其他引用者都在访问一块已被释放的内存。 零值增加...
search
[TOC] include/linux/bsearch.h 二分查找bsearch12345678910111213141516171819202122232425262728293031323334353637383940414243/* * bsearch - 对元素数组进行二进制搜索 * @key:指向正在搜索的项目的指针 * @base:指向要搜索的第一个元素的指针 * @num:元件数量 * @size:每个元素的大小 * @cmp:指向比较功能的指针 * * 此函数对给定数组进行二进制搜索。 数组的内容应该已经在提供的比较函数下按升序排序。 * * 请注意,键不必与数组中的元素具有相同的类型,e.g. key可以是字符串,比较函数可以将字符串与结构体的 name 字段进行比较。 但是,如果数组中的键和元素属于同一类型,则可以对 sort() 和 bsearch() 使用相同的比较函数。 */void *bsearch(const void *key, const void *base, size_t num, size_t size, cmp_fu...