上一篇文章里提到task_struct里有一个PID散列表
- struct pid_link pids[PIDTYPE_MAX];
这里简单说一下pid_link
- struct pid_link
-
{
-
struct hlist_node node;
-
struct pid *pid;
-
};
其中hlist_node是双向链表的一个节点
- struct hlist_node {
-
struct hlist_node *next, **pprev;
-
};
由以上代码可知,pid的散列表是一个双向链表
下面介绍一些基本的函数
1、添加一个新的PID到PID散列表
关于PID的代码都在kernel/pid.c中
- void attach_pid(struct task_struct *task, enum pid_type type,
-
struct pid *pid)
-
{
-
struct pid_link *link;
-
-
link = &task->pids[type];
-
link->pid = pid;
-
hlist_add_head_rcu(&link->node, &pid->tasks[type]);
-
}
以上是添加一个PID到对应的散列表的代码:
1、首先初始化节点,设置对应的链表指针,设置PID
2、将节点加入到对应的链表中
2、获得task_struct关联的PID实例
- static inline struct pid *task_pid(struct task_struct *task)
-
{
-
return task->pids[PIDTYPE_PID].pid;
-
}
这个函数比较简单,task_struct中的
- struct pid_link pids[PIDTYPE_MAX];
这个字段将task对应的
- enum pid_type
-
{
-
PIDTYPE_PID,
-
PIDTYPE_PGID,
-
PIDTYPE_SID,
-
PIDTYPE_MAX
-
};
三种PID都存在一个数组中,因此,要取PID,则只需取PIDTYPE_PID对应的实例即可,同理也可以取得PGID和SID
3、取得PID对应的数字ID
首先PID是在指定的命名空间里的,所以只要取得pid在指定命名空间里的upid的nr字段即可
- pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns)
-
{
-
struct upid *upid;
-
pid_t nr = 0;
-
-
if (pid && ns->level <= pid->level) {
-
upid = &pid->numbers[ns->level];
-
if (upid->ns == ns)
-
nr = upid->nr;
-
}
-
return nr;
-
}
upid = &pid->numbers[ns->level];这一句是取得指定深度对应的upid,pid最末端的number[1]字段是可扩展的,里面存放了pid在不同命名空间里对应的upid(即是局部pid),
ns->level<=pid->level这个判断的主要原因是:保证pid在命名空间的可见范围内
最后判断取得的upid的命名空间和传入的是否一致,若一致则取出nr并返回。
4、分配一个PID
内核中Pid是用位图来存储的,分配pid即是在位图中寻找第一个没有使用的pid(也即是第一个值为0的比特),对于一个PID,能够看得到这个pid的命名空间都需要分配一个upid,同时upid要放入到pid散列表中
主要通过以下两个函数实现:
- struct pid *alloc_pid(struct pid_namespace *ns)
-
{
-
struct pid *pid;
-
enum pid_type type;
-
int i, nr;
-
struct pid_namespace *tmp;
-
struct upid *upid;
-
-
pid = kmem_cache_alloc(ns->pid_cachep, GFP_KERNEL);
-
if (!pid)
-
goto out;
-
-
tmp = ns;
-
for (i = ns->level; i >= 0; i--) {
-
nr = alloc_pidmap(tmp);
-
if (nr < 0)
-
goto out_free;
-
-
pid->numbers[i].nr = nr;
-
pid->numbers[i].ns = tmp;
-
tmp = tmp->parent;
-
}
-
-
get_pid_ns(ns);
-
pid->level = ns->level;
-
atomic_set(&pid->count, 1);
-
for (type = 0; type < PIDTYPE_MAX; ++type)
-
INIT_HLIST_HEAD(&pid->tasks[type]);
-
-
upid = pid->numbers + ns->level;
-
spin_lock_irq(&pidmap_lock);
-
for ( ; upid >= pid->numbers; --upid)
-
hlist_add_head_rcu(&upid->pid_chain,
-
&pid_hash[pid_hashfn(upid->nr, upid->ns)]);
-
spin_unlock_irq(&pidmap_lock);
-
-
out:
-
return pid;
-
-
out_free:
-
while (++i <= ns->level)
-
free_pidmap(pid->numbers + i);
-
-
kmem_cache_free(ns->pid_cachep, pid);
-
pid = NULL;
-
goto out;
-
}
代码比较长,我们主要关心以下代码
- struct pid *pid;
-
enum pid_type type;
-
int i, nr;
-
struct pid_namespace *tmp;
-
struct upid *upid;
-
....
- tmp = ns;
-
for (i = ns->level; i >= 0; i--) {
-
nr = alloc_pidmap(tmp);
- .....
-
-
pid->numbers[i].nr = nr;
-
pid->numbers[i].ns = tmp;
-
tmp = tmp->parent;
-
}
-
...
- pid->level = ns->level;
for ( ; upid >= pid->numbers; --upid)
hlist_add_head_rcu(&upid->pid_chain,
&pid_hash[pid_hashfn(upid->nr, upid->ns)]);
1)首先,循环里是对每个命名空间都分配一个nr,从子命名空间一直到全局命名空间
2)将每个upid放到PID散列表中。
参考资料:
1、《深入Linux内核架构》
阅读(2289) | 评论(0) | 转发(0) |