Linux Kernel/PID namespace / object lifetime

在并发 PID 查找与移除之间保护对象生命周期

Linux 通过 RCU 保护 PID 查找期间的对象存活,再用引用计数延长返回对象的生命;移除 PID 后先等待 RCU 宽限期,再释放索引持有的引用。

v6.12并发与一致性核验 2026-10-09
相关概念

工程问题#

读者查找 PID 对象时,另一个 CPU 可能正在把该对象从命名空间索引中移除。如果刚读到的指针立即被释放,读者甚至来不及安全增加引用计数。

实际实现#

find_get_pid 在 RCU 读侧临界区内查找 PID 并调用 get_pid 增加引用。free_pid 在 pidmap_lock 下移除各层命名空间 IDR 条目,随后用 call_rcu 安排 delayed_put_pid。回调在宽限期后执行 put_pid,只有引用计数归零时才真正回收对象。

处理流程#

  1. 进入 RCU 读侧临界区,在当前命名空间查找 PID
  2. 在受保护期间增加对象引用,再退出读侧临界区
  3. 写侧持锁移除 IDR 中的条目,并安排 RCU 回调
  4. 宽限期结束后递减保留引用,最后一个引用释放时回收对象

源码片段#

固定版本 · 原文摘录
kernel/pid.cv6.12 · L473–L482
查看原文件
473struct pid *find_get_pid(pid_t nr)474{475	struct pid *pid;476477	rcu_read_lock();478	pid = get_pid(find_vpid(nr));479	rcu_read_unlock();480481	return pid;482}
find_get_pid

先进入 RCU 读区,再查找并增加引用。退出读区后,返回指针的生命由引用计数继续保障;调用方最终需要 put_pid。

kernel/pid.cv6.12 · L157–L164
查看原文件
157		}158159		idr_remove(&ns->idr, upid->nr);160	}161	spin_unlock_irqrestore(&pidmap_lock, flags);162163	call_rcu(&pid->rcu, delayed_put_pid);164}
free_pid

free_pid 尾部先从命名空间 IDR 摘除对象并释放 pidmap_lock,再用 call_rcu 安排 delayed_put_pid;并非在移除条目后立即释放内存。

kernel/pid.cv6.12 · L112–L131
查看原文件
112void put_pid(struct pid *pid)113{114	struct pid_namespace *ns;115116	if (!pid)117		return;118119	ns = pid->numbers[pid->level].ns;120	if (refcount_dec_and_test(&pid->count)) {121		kmem_cache_free(ns->pid_cachep, pid);122		put_pid_ns(ns);123	}124}125EXPORT_SYMBOL_GPL(put_pid);126127static void delayed_put_pid(struct rcu_head *rhp)128{129	struct pid *pid = container_of(rhp, struct pid, rcu);130	put_pid(pid);131}
put_pid / delayed_put_pid

RCU 回调只是递减一个引用。真正的缓存对象释放受 refcount_dec_and_test 控制,因此宽限期结束和引用归零是不同的条件。

三个片段连接查找、移除和最终回收;free_pid 片段是函数尾部,写侧锁获取和各命名空间循环在同一文件的前文。

收益与取舍#

工程分析

带来的收益

  • PID 查找路径无需为这次查找获取 pidmap_lock
  • 把短期查找保护与跨读侧临界区的长期对象持有分开处理

付出的代价

  • 被移除对象的内存可能保留到宽限期结束及所有引用释放之后
  • RCU 不负责序列化所有写者,也不自动保证对象可变字段的一致快照;这里仍有写侧自旋锁和引用计数

可比较的选择

读写锁保护整个查找与移除可用同一锁协调读写,但读路径需参与锁竞争;若返回后还要使用对象,依然需要生命周期约定。

版本与适用范围#

对应 Linux v6.12 的 struct pid 对象查找和释放。拿到 PID 对象引用不代表相关进程仍在运行;RCU 读侧保护也不能代替跨临界区使用所需的额外引用。

参考来源#

源码、官方文档与原始论文
01
Linux · find_get_pid / free_pid / delayed_put_pid / put_pid

kernel/pid.c · find_get_pid / free_pid / delayed_put_pid / put_pid

源码v6.12
02
Linux · get_pid

include/linux/pid.h · get_pid

源码v6.12
03
Linux · RCU 移除、宽限期与回收

Documentation/RCU/whatisRCU.rst · RCU removal and reclamation

官方文档v6.12

相关实现与比较#

1 个相关案例
6 个匹配案例