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

linux内核进程命名空间-应用层与内核层

linux内核进程命名空间-应用层与内核层

 

#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)

linux内核进程命名空间-应用层与内核层

子进程局部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) 后的结果。

linux内核进程命名空间-应用层与内核层

linux内核进程命名空间-应用层与内核层

 

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