Chapter 2: Process Management and Scheduling
Because a parent namespace sees PIDs in child namespaces, but not vice versa, the kernel
has to ensure that the current namespace levelis less than or equal to the level in which the
local PID was generated.
It is also important to note that the kernel need only worry about generating global PIDs:
All other ID types in the global namespace will be mapped to PIDs, so there is no need to
generate, for instance, global TGIDs or SIDs.
Instead of usingpid_nr_nsin the second step, the kernel could also employ one of these auxiliary
functions:
❑ pid_vnrreturns the local PID seen from the namespace to which the ID belongs.
❑ pid_nrobtains the global PID as seen from the init process.
Both rely onpid_nr_nsand automatically select the properlevel: 0 for the global PID, andpid->level
for the local one.
The kernel provides several helper functions that combine the described steps:
kernel/pid.c
pid_t task_pid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
pid_t task_tgid_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
pid_t task_pgrp_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
pid_t task_session_nr_ns(struct task_struct *tsk, struct pid_namespace *ns)
Their meaning is obvious from the functionnames, so we need not add anything further.
Now let us turn our attention to how the kernel can convert a numerical PID together with the namespace
into apidinstance. Again two steps are required:
- To determine thepidinstance (the in-kernel representation of a PID) given the local numer-
ical PID of a process and the associated namespace (the userspace representation of a PID),
the kernel must employ a standard hashing scheme: First, the array index inpid_hashis
computed from the PID and namespace pointers,^5 and then the hash list is traversed until
the desired element has been found. This is handled by the auxiliary functionfind_pid_ns:
kernel/pid.c
struct pid fastcall find_pid_ns(int nr, struct pid_namespace ns)
Instances ofstruct upidare kept on the hash, but since these are directly contained in
struct pid, the kernel can infer the desired information using thecontainer_ofmechanism
(see Appendix C). - pid_taskextracts the firsttask_structinstance that is queued on the list
pid->tasks[type].
These two steps are performed by the auxiliary functionfind_task_by_pid)_type_ns:
kernel/pid.c
struct task_struct *find_task_by_pid_type_ns(int type, int nr,
struct pid_namespace *ns)
(^5) For this purpose, the kernel uses multiplicative hashing with a prime number that is in a golden ratio to the largest number that
can be represented in a machine word. For details, refer to [Knu97].