linux内核进程命名空间-应用层与内核层
///clone_vm.c part 1
#define _GNU_SOURCE
#include<sched.h>
#include<sys/wait.h>
#include<string.h>
#include<sys/types.h>
#include<stdio.h>
#include<stdlib.h>
#include<sys/syscall.h>
#include<unistd.h>
#define gettidv1() syscall(__NR_gettid)//syscall(__NR_gettid)函数的意思就是获取线程ID,这句话的意思是宏定义gettidv1()函数为获取线程id的函数
#define gettidv2() syscall(SYS_gettid)//这两个syscall没有任何区别,所以函数两个gettidv也没有任何的区别
#define getpid() syscall(SYS_getpid)//通过宏定义的方式获取pid
#define STACK_SIZE 1024*1024
static int child_func(void *arg)
{
char* buf = (char*)arg;
printf("in child sees buf = %s tid=%ld,pid=%ld \n",buf,gettidv1(),getpid());
sprintf(buf,"hello from child tid=%ld,pid=%ld\n",gettidv1(),getpid());
getchar();//子进程不能结束,
return 0;
}
///clone_vm.c part 2
int main(int argc,char **argv)
{
char test;
//给子任务分配参数
char *stack = malloc(STACK_SIZE);
if(!stack){
perror("malloc");
exit(1);
}
//看看第一个命令行参数
printf("\nthe programme name is %s\n",argv[0]);
//唤起命令行参数vm,设置CLONE_VM标记
unsigned long flags = 0;
if((argc>1)&&(!strcmp(argv[1],"vm")))
flags |= CLONE_VM;
char buf[100];
sprintf(buf,"hello from parent pid=%ld\n",getpid());
printf("in parent process before clone\n buf=%s",buf);
//根据不同的标记创建子进程
flags |= CLONE_NEWPID;
if(clone(child_func,stack+STACK_SIZE,flags|SIGCHLD,buf)==-1)
{
perror("clone");
exit(1);
}
int status;
if(waitpid(-1,&status,0)==-1)
{
perror("wait");
exit(1);
}
printf("in parent process: child exited with status %d.\n buf = %s \n",status,buf);
test = getchar();
return 0;
}
运行结果:子进程全局pid 6438,局部pid 1.父进程全局pid 6437
#include<linux/module.h>
#include<linux/sched.h>
#include<linux/pid.h>
#include<linux/init.h>
MODULE_LICENSE("GPL");
static int __init __task_pid_nr_ns_init(void);
static void __exit __task_pid_nr_ns_exit(void);
int __init __task_pid_nr_ns_init(void)
{ //find_get_pid获取的时全局struct pid,level == 0;
int test_level;
struct pid *kpid = find_get_pid(current->pid);
struct task_struct *task = pid_task(kpid,PIDTYPE_PID);
pid_t result = __task_pid_nr_ns(task,
PIDTYPE_PID,kpid->numbers[kpid->level].ns);
printk("current->pid: %d\n",current->pid);
printk("result: %d\n",result);
printk("kpid->numbers[kpid->level].nr: %d\n",
kpid->numbers[kpid->level].nr);
printk("kpid->level: %d\n",kpid->level);
printk("namespace_test\n\n\n");
#define PID_TEST 6438
//struct pid_namespace *ns = find_pid_ns((pid_t)PID_TEST);
kpid = find_get_pid((pid_t)PID_TEST);
if(kpid == NULL)
{
printk("kpid null!\n");
return 0;
}
printk("kpid->numbers[kpid->level].nr: %d\n",
kpid->numbers[kpid->level].nr);
printk("kpid->level: %d\n",kpid->level);
task = pid_task(kpid,PIDTYPE_PGID);
if(task == NULL)
{
printk("PIDTYPE_PGID task null!\n");
}
task = pid_task(kpid,PIDTYPE_PID);
if(task == NULL)
{
printk("PIDTYPE_PID task null!\n");
}
printk("task->pid: %d\n",task->pid);
result = __task_pid_nr_ns(task,
PIDTYPE_PID,kpid->numbers[kpid->level].ns);
if(result == NULL)
{
printk("PIDTYPE_PID result null!\n");
}
printk("PIDTYPE_PID result:%d\n",result);
if(kpid->level>0)
{
test_level = kpid->level-1;
result = __task_pid_nr_ns(task,
PIDTYPE_PID,kpid->numbers[test_level].ns);
if(result == NULL)
{
printk("PIDTYPE_PID result level-1 null!\n");
}
printk("PIDTYPE_PID result level - 1:%d\n",result);
}
result = __task_pid_nr_ns(task,
PIDTYPE_PGID,kpid->numbers[kpid->level].ns);
if(result == NULL)
{
printk("PIDTYPE_PGID result null!\n");
}
printk("PIDTYPE_PGID result:%d\n",result);
return 0;
}
void __exit __task_pid_nr_ns_exit(void)
{
printk("__task_pid_nr_ns exit ok!\n");
}
module_init(__task_pid_nr_ns_init);
module_exit(__task_pid_nr_ns_exit);
Makefile
PWD = $(shell pwd)
KERNEL_SRC = /usr/src/linux-3.19/
obj-m := __task_pid_nr_ns.o
all:
$(MAKE) -C $(KERNEL_SRC) M=$(PWD) modules
clean:
rm *.ko
rm *.o
结果:#define PID_TEST 6438(子进程全局pid_t pid)
子进程局部pid = 1;
全局struct pid.level = 1; find_get_pid可以通过子进程的全局pid_t pid 找到struct pid(只有一个且是全局)。其中find_get_pid 使用current宏的全局pid_namespace(内核中current 对应的level = 0).而且struct pid 的 level = 1;且在level = 1 时的局部pid_t pid 为1;
pid_task()只能找到struct pid.tasks 对应的PIDTYPE_PID下的struct task_struct.
__task_pid_nr_ns可以通过struct task_struct ,并指定命名空间(局部和全局),得到struct_task 或者 对应的pid_t pid(局部或全局)
__task_pid_nr_ns 也可以通过struct task_struct 和PIDTYPE_PGID指定 task_struct 的组长。但不适合子进程在局部命名空间,父进程在全局空间此时父进程不是子进程的组长。
适合的情况比如下图#define PID_TEST 6437 (父进程全局pid_t pid)和#define PID_TEST 6436 (sudo 全局pid_t pid) 后的结果。
namespace
https://www.jianshu.com/p/241cde455d76
find_get_pid()
https://blog.****.net/tiantao2012/article/details/78598869
task_active_pid_ns()
https://blog.****.net/tiantao2012/article/details/78715681
clone():
https://blog.****.net/narcissus2_/article/details/86411460
struct pid
https://blog.****.net/u011673554/article/details/48554821
pid_hash 散列表。
https://blog.****.net/bysun2013/article/details/14053937
pid hash 实现
https://blog.****.net/zhang2531/article/details/52089211