分配pid
![]()
static int alloc_pidmap( struct pid_namespace *pid_ns)
![]()
{
![]()
int i, offset, max_scan, pid, last = pid_ns->last_pid;
![]()
struct pidmap *map;
/* last为上次分配的pid */
![]()
pid = last + 1;
![]()
/* 如果pid比最大值还大,那么就设置成RESERVED_PIDS 300,在Linux系统中会保留一部分进程号用作它用 */
![]()
if (pid >= pid_max)
![]()
pid = RESERVED_PIDS;
![]()
/* 计算出该pid在它所在的map表中的偏移量 */
![]()
offset = pid & BITS_PER_PAGE_MASK;
![]()
/* 计算出该pid所在的map,pid/BITS_PER_PAGE就是它所在map对应的pidmap偏移量 */
![]()
map = &pid_ns->pidmap[pid/BITS_PER_PAGE];
![]()
/* 计算最大遍历次数,pid_max是一个全局变量,默认值PID_MAX_DEFAULT,根据系统是否设置CONFIG_BASE_SMALL,可以为0x1000或0x8000, 在x86体系上,(pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE 始终是1, 当pid是在map的第一个位置的时候,即offset=0的时候,只需循环
![]()
一次;当pid不是第一个位置,在中间或者结尾,即offset!=0的时候,max_scan=1,就需要循环两次,从last+1的位置开始,一直找到末尾,还>没找到对应的,那就从头开始,找到last处,总之需要走一遍map */
![]()
max_scan = (pid_max + BITS_PER_PAGE - 1)/BITS_PER_PAGE - !offset;
![]()
for (i = 0; i <= max_scan; ++i) {
![]()
if (unlikely(!map->page)) {
![]()
/* 如果page为空,则从新分配一个,同时加锁再次判断是否为空,如果为空则直接设置,否则分配的就多余了
![]()
如果其他地方也在使用该page的时候,那么有可能在加锁之前,map->page由空变成了不空,
![]()
void *page = kzalloc(PAGE_SIZE, GFP_KERNEL);
![]()
/*
![]()
* Free the page if someone raced with us
![]()
* installing it:
![]()
*/
![]()
spin_lock_irq(&pidmap_lock);
![]()
if (map->page)
![]()
kfree(page);
![]()
else
![]()
map->page = page;
![]()
spin_unlock_irq(&pidmap_lock);
![]()
if (unlikely(!map->page))
![]()
break;
![]()
}
![]()
/* 如果map存在空闲位置,那么就设置该offset对应的比特位*/
![]()
if (likely(atomic_read(&map->nr_free))) {
![]()
do {
![]()
if (!test_and_set_bit(offset, map->page)) {
![]()
/* 减少空闲位置个数 */
![]()
atomic_dec(&map->nr_free);
![]()
pid_ns->last_pid = pid;
![]()
/* 分配成功返回对应pid */
![]()
return pid;
![]()
}
![]()
/* 设置不成功,或许该位已经置位,那么继续寻找下一个比特位为0的位置,同时生成一个pid */
![]()
offset = find_next_offset(map, offset);
![]()
pid = mk_pid(pid_ns, map, offset);
![]()
/*
![]()
* find_next_offset() found a bit, the pid from it
![]()
* is in-bounds, and if we fell back to the last
![]()
* bitmap block and the final block was the same
![]()
* as the starting point, pid is before last_pid.
![]()
*/
![]()
} while (offset < BITS_PER_PAGE && pid < pid_max &&
![]()
(i != max_scan || pid < last ||
![]()
!((last+1) & BITS_PER_PAGE_MASK)));
![]()
}
![]()
/* 如果map中已经没有空闲了,且判断还存在其他map的时候,继续在下一个map中分配
![]()
在x86体系上,判断始终不成立 */
![]()
if (map < &pid_ns->pidmap[(pid_max-1)/BITS_PER_PAGE]) {
![]()
++map;
![]()
offset = 0;
![]()
} else {
![]()
/* 否则就从第一个位置从头开始找 */
![]()
map = &pid_ns->pidmap[0];
![]()
offset = RESERVED_PIDS;
![]()
/* 如果这个时候的位置已经是上次分配的了,那么就已经找过了,没必要再找一次了 */
![]()
if (unlikely(last == offset))
![]()
break;
![]()
}
![]()
pid = mk_pid(pid_ns, map, offset);
![]()
}
![]()
return -1;
![]()
}