sysfs
[TOC] fs/sysfs/fs.c & dir.c 内核对象文件系统(Kernel Object Filesystem) 将内核对象层次结构导出到用户空间历史与背景这项技术是为了解决什么特定问题而诞生的?Sysfs(System Filesystem)的诞生是为了解决一个在早期Linux内核中日益严重的问题:/proc文件系统的混乱。 /proc的无序扩张:/proc文件系统最初设计用于提供关于系统中正在运行的进程的信息(即/proc/[pid]目录)。然而,由于其便利性,内核开发者开始将各种与进程无关的系统信息、硬件状态和可调参数也塞入/proc,导致其结构混乱、内容混杂,缺乏统一的逻辑。 缺乏结构化视图:/proc中的信息是平面的、零散的,无法清晰地反映出系统中设备、驱动和总线之间复杂的层次关系和连接关系。例如,你很难从/proc中直观地看出某个USB设备连接在哪条总线上,以及它正在使用哪个驱动程序。 Sysfs是作为统一设备模型(Unified Device Model),或称为kobject模型,的一部分而被创造出来的。它的核心目...
backing-dev
[toc] mm/backing-dev.c 回写管理(Writeback Management) 脏页回写的调速器与执行者历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决Linux内核中一个核心的性能与数据一致性难题:如何智能、高效地将内存中被修改过的数据(“脏页”,Dirty Pages)写回到持久化存储设备(“后备设备”,Backing Device)中。 在mm/backing-dev.c所代表的现代回写框架出现之前,Linux的脏页回写机制比较原始,存在诸多问题: 全局瓶颈:早期的pdflush机制使用一个全局的线程池来处理所有设备的回写任务。这意味着一个慢速设备(如USB 1.0 U盘)的回写任务,可能会长时间占用一个flusher线程,从而阻塞一个高速设备(如NVMe SSD)的回写,造成**队头阻塞(Head-of-line blocking)**问题。 缺乏精细控制:无法对单个设备设置不同的回写策略。所有设备共享一套全局的回写参数,这对于性能差异巨大的异构存储环境是极其低效的。 写操作延迟风暴(Latency Spikes):当系...
filemap
[TOC] mm/filemap.c: Linux 页缓存 (Page Cache) 的心脏mm/filemap.c 是 Linux 内核中实现和管理页缓存 (Page Cache) 的核心源文件。页缓存是 Linux I/O 性能的基石,它将磁盘上的文件内容缓存到物理内存(RAM)中,使得后续对同一文件的读写操作可以直接在内存中完成,从而避免了缓慢的磁盘 I/O。 可以把 mm/filemap.c 想象成一个高效的“图书管理员”,它负责管理一个巨大的图书馆(页缓存),图书馆里的每一页书(struct page)都对应着磁盘文件上的某一页内容。 一、 核心职责mm/filemap.c 的代码几乎参与了所有与文件 I/O 相关的内存操作,其核心职责包括: 页缓存的查找与插入 (Finding and Inserting): 当需要读取文件数据时,它负责在页缓存中查找是否已缓存了对应的页面。如果找到(Cache Hit),则直接返回内存页;如果未找到(Cache Miss),则负责分配一个新的物理页,并将其插入到页缓存中,准备从磁盘加载数据...
list_lru
[TOC] list_lru: Linux内核的可扩展对象缓存管理器list_lru 是 Linux 内核提供的一套可扩展的、近似 LRU (Least Recently Used) 缓存列表管理机制。它专门设计用来高效地管理大量、小型、生命周期不一的内核对象,例如目录项缓存(dentries)和索引节点缓存(inodes)。 可以将其想象成一个特殊的“图书馆卡片目录系统”,这个系统需要被许多图书管理员(CPU核心)同时、频繁地访问,并且需要一种高效的方式来找出那些最久未被使用的卡片(对象)以便回收。 一、 核心问题:为什么需要 list_lru?在理解 list_lru 的设计之前,必须先明白它要解决的核心问题:在多核环境下的锁竞争。 一个朴素的 LRU 列表实现通常是这样的: 维护一个全局的双向链表。 当一个对象被访问时,将它从链表中的当前位置移到链表头(表示最新使用)。 当需要回收内存时,从链表尾部(表示最久未使用)开始移除对象。 这种实现在单核系统上工作得很好。但在现代多核系统中,会产生一个巨大的性能瓶颈:所有 CPU 核心都必须竞争同一个全局锁来修改这个链表...
memblock
[TOC] mm/memblock.c: Linux内核的“拓荒时代”内存管理器mm/memblock.c 实现了一种极其早期的、简单的物理内存分配器,它在内核启动的“拓荒时代”——即在页分配器(伙伴系统)初始化之前——扮演着至关重要的角色。 可以将其想象成一个在建造正式仓库(伙伴系统)之前,用来管理建筑材料(物理内存)的临时账本和场地规划师。它的唯一使命是在最原始的环境下,为内核自身的初始化提供最基本的内存分配服务,并在完成使命后,将所有管理权平稳地移交给更高级的内存管理系统。 一、 核心问题:为什么需要 memblock?在内核启动的极早期(start_kernel 函数刚开始执行时),真正的内存管理子系统(如伙伴系统、Slab 分配器)还完全不存在。这些高级系统本身就需要分配内存来存放它们复杂的数据结构(如 mem_map 数组、kmem_cache 结构等)。这就产生了一个“先有鸡还是先有蛋”的问题: 为了初始化内存管理器,你需要分配内存。 但为了分配内存,你需要一个已初始化的内存管理器。 memblock 就是为了打破这个循环而存在的。它是一个极其简单的...
init
[TOC] Linux 内存模型之基石:FLATMEM 深度解析FLATMEM 是 Linux 内核中最基础、最常用,也是最高效的内存模型。正如其名,“平坦内存”模型假定系统的物理内存是一个单一、连续、不存在大间隙的地址空间。 一、 核心原理:mem_map 数组FLATMEM 模型的全部精髓都围绕着一个核心数据结构:一个巨大的、全局的 struct page 数组,通常被称为 mem_map。 什么是 struct page? 在 Linux 内核中,物理内存不是按字节管理的,而是按固定大小的块来管理的,这个块被称为页帧 (Page Frame)(通常是 4KB)。 内核为每一个物理页帧都分配了一个 struct page 描述符。这个结构体包含了该物理页帧的所有元数据,例如:它的引用计数、它是否是脏页、是否被锁定、属于哪个地址空间映射等。 mem_map 的作用 FLATMEM 模型在内核启动的极早期,会分配一个足够大的连续内存区域,用来存放一个 struct page 数组。这个数组的大小足以覆盖从物理地址 0(或某个起始偏移)到系统最大物理内存地址之间的所有页...
nommu
[TOC] mm/nommu.c NO-MMU内存管理(NO-MMU Memory Management) 适用于无内存管理单元的系统历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了让Linux操作系统能够运行在没有**内存管理单元(MMU)**的简单微控制器(MCU)和嵌入式处理器上。标准的Linux内核设计严重依赖MMU来实现以下核心功能: 虚拟内存:为每个进程提供独立的、巨大的、线性的虚拟地址空间。 内存保护:利用硬件机制防止一个进程访问另一个进程或内核的内存空间,保障系统稳定性和安全性。 内存映射与分页:实现写时复制(Copy-on-Write)、按需分页(Demand Paging)和交换(Swapping)等高级内存管理技术。 许多低成本、低功耗的嵌入式处理器(如ARM Cortex-M系列)为了节省芯片面积和功耗,并不包含MMU。mm/nommu.c 及其相关代码提供了一套替代的、简化的内存管理模型,使得功能强大的Linux内核能够在这种受限的硬件上运行,这通常被称为uClinux(Micro-Controller Linux)。 它的...
page-writeback
[TOC] mm/page-writeback.c 页面回写(Page Writeback) 数据持久化的核心机制历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决一个计算机体系结构中的根本性矛盾:内存(RAM)与持久性存储设备(如硬盘、SSD)之间巨大的性能差距。 性能缓冲:应用程序向文件写入数据时,如果每次写入都必须等待慢速的存储设备完成,那么整个系统的性能和响应速度将变得无法接受。页面回写机制利用高速的内存作为写回缓存(Write-back Cache),允许write()系统调用将数据写入内存(即 Page Cache)后立即返回,从而极大地提升了应用程序的写入性能和系统吞吐量。 数据持久化:内存中的数据是易失的,断电后会丢失。因此,必须有一个可靠的机制,将在内存中被修改过的数据(称为“脏页”,Dirty Page)在合适的时机写回到持久性存储设备上,确保数据的最终安全性。 I/O效率优化:该机制可以将多次小的、离散的写入操作在内存中合并成一次大的、连续的写入操作,然后再提交给存储设备。这种**I/O合并(I/O...
percpu
[TOC] mm/percpu.c Per-CPU Variables Management Per-CPU数据管理的核心实现历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了从根本上解决在多核(SMP)系统中并发访问共享数据所带来的性能瓶颈而诞生的。 锁争用(Lock Contention):在多核系统中,如果多个CPU核心频繁地更新同一个全局变量(例如,一个网络数据包统计计数器),它们必须使用锁(如自旋锁)来保护这个变量,以避免数据竞争。当核心数量增加时,对这个锁的争夺会变得非常激烈,导致CPU花费大量时间在等待锁上,而不是执行实际工作,从而严重限制了系统的扩展性。 缓存一致性开销(Cache Coherency Overhead):即使不使用锁(例如使用原子操作),也会有性能问题。当一个CPU核心修改了共享变量,它所在的缓存行(Cache Line)会被标记为“脏”(Modified)。根据缓存一致性协议(如MESI),其他CPU核心上该缓存行的副本必须被置为“无效”(Invalidated)。当其他CPU也想访问这个变量时,就必须从修改过的那个核...
page_alloc
[TOC] mm/page_alloc.c 伙伴系统内存分配器(Buddy System Memory Allocator) 内核物理内存管理的核心历史与背景这项技术是为了解决什么特定问题而诞生的?这项技术是为了解决操作系统内核中最根本的问题之一:如何高效、可靠地管理整个系统的物理内存(RAM)。内核自身及其服务的子系统(如进程管理、文件系统缓存、网络协议栈)都需要动态地申请和释放内存。mm/page_alloc.c 中实现的伙伴系统(Buddy System)旨在满足以下核心需求: 管理基本单位:将物理内存划分为固定大小的“页”(通常是4KB),并以此为基本单位进行管理。 提供连续内存:许多硬件设备(特别是进行直接内存访问DMA的设备)和某些内核数据结构要求得到的内存块在物理上是连续的。伙伴系统的设计目标之一就是能够分配不同大小的、物理连续的内存块。 对抗外部碎片:在长时间运行的系统中,频繁地分配和释放不同大小的内存块会导致物理内存中产生许多不连续的小空闲块。这种现象称为“外部碎片”,它会导致即使总的空闲内存很多,也无法满足一个较大连续内存的申请。伙伴系统通过其独特...








