news 2026/10/30 2:30:54

slub add_full

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
slub add_full

add_full()是 SLUB 调试中用于把完全占满的 slab 页加入 per-node 的full链表的函数。这个函数只在CONFIG_SLUB_DEBUG下存在,因为正常运行时 SLUB 不追踪满 slab。

一、函数签名

static void add_full(struct kmem_cache *s, struct kmem_cache_node *n, struct slab *slab)
参数含义
s缓存
n对象所在 NUMA 节点的kmem_cache_node
slab要加入的 slab 页

无返回值。

二、典型实现

static void add_full(struct kmem_cache *s, struct kmem_cache_node *n, struct slab *slab) { if (!(s->flags & SLAB_STORE_USER)) return; lockdep_assert_held(&n->list_lock); list_add(&slab->slab_list, &n->full); }

逻辑:

  1. 门控:未开SLAB_STORE_USER直接返回。

  2. 锁断言:lockdep_assert_held(&n->list_lock)确认调用者已持有 node 的list_lock。

  3. 头插链表:list_add(&slab->slab_list, &n->full)把 slab 加入full列表头部。

三、full列表回顾

struct kmem_cache_node:

struct kmem_cache_node { spinlock_t list_lock; unsigned long nr_partial; struct list_head partial; #ifdef CONFIG_SLUB_DEBUG atomic_long_t nr_slabs; atomic_long_t total_objects; struct list_head full; // ← 这里 #endif };
  • partial:部分空闲的 slab,正常运行时也维护。

  • full:完全占满的 slab,仅调试时维护。

为什么正常运行时不需要full:

  • 满 slab 没有空闲对象,分配路径不会用到。

  • 释放时若某个满 slab 变部分空闲,需要知道它在哪——正常运行时它根本不在任何列表上,靠对象指针反查 slab 即可处理。

  • 只有调试时需要枚举所有 slab(校验、统计),才需要full列表把满 slab 也挂起来。

四、调用时机

add_full()在 slab由非满变满时调用:

// 分配路径中,对象从 slab 取出,slab 变满 if (slab->inuse == slab->objects) { // 从 partial 移除,加入 full remove_partial(n, slab); add_full(s, n, slab); }

对应地,由满变非满时调remove_full():

static void remove_full(struct kmem_cache *s, struct kmem_cache_node *n, struct slab *slab) { if (!(s->flags & SLAB_STORE_USER)) return; lockdep_assert_held(&n->list_lock); list_del(&slab->slab_list); }
状态变化操作
partial → fullremove_partial+add_full
full → partialremove_full+add_partial
full → freeremove_full+ 归还伙伴系统

五、与其他列表操作的关系

SLUB 里 slab 列表操作的完整集合:

函数操作
add_partial(n, slab, tail)加入 partial 列表(头或尾)
remove_partial(n, slab)从 partial 移除
add_full(s, n, slab)加入 full 列表(仅调试)
remove_full(s, n, slab)从 full 移除(仅调试)

这些操作都在n->list_lock保护下进行,且通常成对出现。

六、锁与并发

lockdep_assert_held(&n->list_lock);
  • lockdep_assert_held():调试断言,确认调用者持有指定锁。

  • 不改变运行时行为(未开 lockdep 时是空宏),但能在开发阶段抓出“忘了加锁”的 bug。

  • 所有列表操作都必须在list_lock保护下,因为n->partial/n->full是多个 CPU 共享的 per-node 结构。

调用者通常:

spin_lock(&n->list_lock); // ... 操作 slab 状态 add_full(s, n, slab); spin_unlock(&n->list_lock);

七、slab_list字段

list_add(&slab->slab_list, &n->full);
  • slab->slab_list:struct slab里的struct list_head成员,用于挂在各种列表上。

  • 同一个slab_list字段在不同状态下挂不同列表:

    • 在 partial 列表上 → 挂在n->partial。

    • 在 full 列表上 → 挂在n->full。

    • 在 CPU partial 上 → 挂在c->partial。

  • 因为一个 slab 同一时刻只能处于一种列表状态,复用同一个list_head节省空间。

八、与前面知识的呼应

前面讲过这里体现
struct kmem_cache_noden->full、n->list_lock
SLAB_STORE_USER门控条件
list_lock保护列表操作
add_partial/remove_partial对称的 partial 操作
struct slabslab->slab_list字段
slab->inuse/slab->objects判断满/非满

九、总结

add_full(s, n, slab)在开启SLAB_STORE_USER时,把由非满变满的 slab 页加入 per-node 的full链表,要求在n->list_lock保护下调用。它只在调试时存在,用于维护完整视图以便校验和统计;正常运行时满 slab 不被追踪,以节省开销。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/30 2:30:31

结构化输出为何“格式正确、答案错误”?JSON Schema 的能力边界

结构化输出为何“格式正确、答案错误”?JSON Schema 的能力边界 JSON 能解析、字段也都符合 Schema,业务结果仍然可能错。结构化输出约束的是可接受的形式,字段是否来自证据则是另一层问题。 一个必填下拉框没有“不知道”选项时&#xff0c…

作者头像 李华
网站建设 2026/10/30 2:29:48

FunASR安装

在 Windows 上配置和运行 FunASR,最省事的路子是走 Docker 一键部署,或者用现成的整合包‌。下面按不同需求给出对应方案。🐳 方案一:Docker 一键部署(推荐,适合离线转写服务) 这是目前最省心的…

作者头像 李华
网站建设 2026/10/30 2:26:28

浏览器网页加载流程抓包复现

在进入实验室之前,我们已经浅浅学过计算机网络原理,大概了解了网络如何运行,了解TCP/IP四层模型和OSI七层模型,那么,数据从浏览器到服务器经历了哪些层?HTTP请求和响应长什么样?为什么输入网址后…

作者头像 李华
网站建设 2026/10/30 2:25:49

记一次 PGP 驱动残留导致的开机蓝屏修复

输对 BitLocker 48 位恢复密钥,磁盘显示已解锁,然后——蓝屏,无限循环。朋友的笔记本就这么折腾了我一整天,最后发现元凶是一个 2010 年的老软件残留驱动。这篇把从 BCD 重建到 UpperFilters 残留排查的完整过程记下来&#xff0c…

作者头像 李华