也许这些链接可能会有所帮助:
- 运行中的 PID 命名空间
- PID命名空间的简单介绍(这个来自一个系统管理员)
通过第二个链接后,很明显命名空间是隔离资源的好方法。在包括 Linux 在内的任何操作系统中,进程都是最重要的资源之一。用他自己的话说
是的,就是这样,使用这个命名空间可以重新启动 PID 编号并获得您自己的“1”进程。这可以被视为进程标识符树中的“chroot”。当您需要在日常工作中处理 pid 并且被 4 位数字卡住时,它非常方便......</p>
因此,您可以创建自己的私有流程树,然后将其分配给特定用户和/或特定任务。在这棵树中,进程不必担心 PID 与“容器”外的 PID 冲突。因此,这与将这棵树完全交给不同的“根”用户一样好。这位好人用一个很好的小例子来解释事情做得很好,所以我不会在这里重复。
就内核而言,我可以为您提供一些指导以帮助您入门。我不是这里的专家,但我希望这对您有所帮助。
这篇 LWN文章描述了查看 PID 的旧方法和新方法。用它自己的话来说:
一个任务可能具有的所有 PID 都在struct pid
. 此结构包含 ID 值、具有此 ID 的任务列表、引用计数器和要存储在哈希表中的哈希列表节点,以便更快地搜索。关于任务列表的更多信息。基本上,一个任务具有三个 PID:进程 ID (PID)、进程组 ID (PGID) 和会话 ID (SID)。PGID和SID可以在任务之间共享,例如,当两个或多个任务属于同一个组时,每个组ID寻址多个任务。使用 PID 命名空间,这个结构变得有弹性。现在,每个 PID 可能有多个值,每个值在一个命名空间中有效。也就是说,一个任务在一个命名空间中可能具有 1024 的 PID,而在另一个命名空间中可能具有 256。所以,前者发生了struct pid
变化。以下是如何
struct pid
在引入 PID 命名空间之前看起来像:
struct pid {
atomic_t count; /* reference counter */
int nr; /* the pid value */
struct hlist_node pid_chain; /* hash chain */
struct hlist_head tasks[PIDTYPE_MAX]; /* lists of tasks */
struct rcu_head rcu; /* RCU helper */
};
这就是它现在的样子:
struct upid {
int nr; /* moved from struct pid */
struct pid_namespace *ns; /* the namespace this value
* is visible in */
struct hlist_node pid_chain; /* moved from struct pid */
};
struct pid {
atomic_t count;
struct hlist_head tasks[PIDTYPE_MAX];
struct rcu_head rcu;
int level; /* the number of upids */
struct upid numbers[0];
};
如您所见,struct upid
now 表示 PID 值——它存储在散列中并具有 PID 值。要将 转换struct pid
为 PID 或反之亦然,可以使用一组帮助器,如
task_pid_nr()
、pid_nr_ns()
、find_task_by_vpid()
等。
虽然有点过时,但这些信息足以让您入门。这里还有一个更重要的结构需要提及。它是struct nsproxy
。这个结构是所有事物命名空间相对于它所关联的进程的焦点。它包含一个指向该进程的子进程将使用的 PID 命名空间的指针。当前进程的 PID 命名空间使用task_active_pid_ns
.
在struct task_struct
中,我们有一个命名空间代理指针,它被恰当地称为nsproxy
,它指向这个进程的struct nsproxy
结构。如果您跟踪创建新流程所需的步骤,您可以找到 和 之间的task_struct
关系。struct nsproxy
struct pid
Linux 中的新进程总是从现有进程中派生出来,然后使用execve
(或 exec 系列中的类似函数)替换它的映像。因此,作为 的一部分do_fork
,copy_process
被调用。
作为复制父进程的一部分,会发生以下重要事情:
task_struct
首先使用dup_task_struct
.
- 父进程的命名空间也使用
copy_namespaces
. 这也为孩子创建了一个新nsproxy
结构,它的 nsproxy 指针指向这个新创建的结构
对于非 INIT 进程(原始全局 PID也就是启动时产生的第一个进程),PID
分配一个结构,使用该结构实际上为新ed 进程alloc_pid
分配一个新的 PID 结构。fork
此函数的简短片段:
nr = alloc_pidmap(tmp);
if(nr<0)
goto out_free;
pid->numbers[i].nr = nr;
pid->numbers[i].ns = tmp;
upid
这通过给它一个新的 PID 以及它当前所属的命名空间来填充结构。
此外,作为copy process
函数的一部分,这个新分配的 PID 然后链接到相应的task_struct
via 函数pid_nr
,即它的全局 ID(从 INIT 命名空间看起来是原始 PID nr)存储pid
在task_struct
.
在最后阶段,通过领域内的功能与这个新结构copy_process
之间建立了联系。task_struct
pid
pid_link
task_struct
attach_pid
它还有很多,但我希望这至少能给你一些先机。
注意:我指的是最新的(截至目前)内核版本,即。3.17.2.