ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

page_alloc FPI*

page_alloc FPI* fpi_t的标志并引入了一个与 PCPPer-CPU Pages相关的锁。逐块拆解。一、FPI_TO_TAIL—— 放到空闲链表尾部#define FPI_TO_TAIL ((__force fpi_t)BIT(1))值 第 1 位BIT(1) 2。语义把可能已经合并的页块放到空闲链表的尾部而不是默认的头部。为什么要放尾部伙伴系统的空闲链表在分配时通常从头部取LIFO 风格。如果释放时放到尾部那么这页/块短期内不会被优先分配出去链表头部的页会被优先复用效果是让某些页在空闲链表里停留更久。为什么希望它停留更久注释说得很清楚用于两类场景1. 内存上线memory onlining——fresh pages内存热插拔后新上线的内存页刚加入伙伴系统。此时系统可能正在做页面乱序page shuffling目的是让物理页的分配更随机、减少可预测的碎片模式。但FPI_TO_TAIL的注释说Will ignore page shuffling (relevant code - e.g., memory onlining - is expected to shuffle the whole zone).意思是用这个标志放回时不做 shuffle因为调用方如内存上线会自己负责把整个 zone 打乱。所以这里不必多此一举。把 fresh pages 放尾部可以让它们先待着等整体 shuffle 或后续分配慢慢消化。2. 页隔离page isolation、空闲页上报free page reporting——untouched pages这些机制会把页临时从空闲链表借出做检查/迁移判断/上报然后原样放回。这些页没有被真正使用过内容/状态没变。放回尾部可以保持空闲链表的稳定性避免干扰正常的分配顺序比如避免刚借出又立刻被分配走导致机制自身逻辑混乱。关键警告不要依赖它保证正确性Note: No code should rely on this flag for correctness - its purely to allow for optimizations...这个标志只影响顺序/性能不改变语义正确性。任何代码不能假设用了FPI_TO_TAIL的页一定最后被分配。它纯粹是个优化提示。二、FPI_TRYLOCK—— 不加锁释放/* Free the page without taking locks. Rely on trylock only. */ #define FPI_TRYLOCK ((__force fpi_t)BIT(2))值 第 2 位BIT(2) 4。语义释放页时不阻塞地获取锁只用trylock。为什么需要 trylock正常释放页需要拿zone 锁zone-lock在锁竞争激烈多 CPU 高并发释放时阻塞等锁会带来延迟甚至抖动。FPI_TRYLOCK让调用方尝试拿锁拿到就释放拿不到就放弃不等待把页留给别的路径处理比如稍后重试、或交给 PCP 路径。这通常用于不希望阻塞的上下文如某些批量释放、内存压力下的快速路径。因为底层锁 API 是spin_trylock风格所以叫TRYLOCK。三、PCP 批量参数锁/* prevent 1 _updater_ of zone percpu pageset -high and -batch fields */ static DEFINE_MUTEX(pcp_batch_high_lock); #define MIN_PERCPU_PAGELIST_HIGH_FRACTION (8)这两行和fpi_t无关是 PCPPer-CPU Pageset相关的全局定义。pcp_batch_high_lock一个静态互斥锁mutex。作用注释写明防止多个更新者同时修改 zone percpu pageset 的-high和-batch字段。背景每个 CPU、每个 zone 有一个per_cpu_pages结构含high高水位、batch批量补充/归还的页数等字段。这些字段可以在运行时调整比如通过 sysctl 或内存热插拔/CPU 上线时重新计算。调整涉及多个 CPU 的 pageset必须串行化否则并发修改会导致高水位和批量值不一致部分 CPU 用旧值、部分用新值缓存行为异常过多/过少页滞留。所以用一把 mutex 保护整个更新过程。用 mutex 而非 spinlock是因为这类更新是慢路径配置/热插拔时可以睡眠不需要原子自旋。MIN_PERCPU_PAGELIST_HIGH_FRACTION (8)一个常量值为8。用途计算 PCP 高水位时的下限比例。从名字看MIN ... HIGH ... FRACTION即per-CPU 页链表高水位的最小分数。典型逻辑示意是high max(high, zone_managed_pages / (8 * ...));或类似地保证high不会低于某个与 zone 大小成比例的最小值分母 8即至少是 zone 页数的某分数。具体公式随内核版本不同但核心含义是给pcp-high设定一个基于 zone 规模的最小值防止在高内存压力或大 zone 下 PCP 缓存过小、频繁回落到伙伴系统。四、更新后的fpi_t标志总览标志位语义FPI_NONE0无特殊请求FPI_SKIP_REPORT_NOTIFYBIT(0)跳过 Free Page Reporting 通知FPI_TO_TAILBIT(1)放到空闲链表尾部优化非正确性依赖FPI_TRYLOCKBIT(2)只用 trylock不阻塞等锁一句话总结FPI_TO_TAIL让释放的页块排到空闲链表尾部用于内存上线、页隔离、空闲页上报等新鲜/未触碰页的优化不保证正确性FPI_TRYLOCK让释放时只尝试拿锁、不阻塞而pcp_batch_high_lock和MIN_PERCPU_PAGELIST_HIGH_FRACTION则是保护并约束每 CPU 页集高水位/批量参数更新的配套机制。
返回列表