[v2,08/57] zdtm: Add pidns00 test

Submitted by Andrey Vagin on April 5, 2017, 10:16 p.m.

Details

Message ID 20170405221637.GB26447@outlook.office365.com
State New
Series "Nested pid namespaces support"
Headers show

Commit Message

Andrey Vagin April 5, 2017, 10:16 p.m.
======================== Run zdtm/static/pidns00 in ns =========================
Start test
Test is SUID
./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
Run criu dump
Run criu restore
=[log]=> dump/zdtm/static/pidns00/38/1/restore.log
------------------------ grep Error ------------------------
(00.371112) Error (criu/namespaces.c:1547): 83 exited normally
(00.372426) Error (criu/namespaces.c:2749): Error during waiting pid_ns helper: No child processes
------------------------ ERROR OVER ------------------------
Send the 15 signal to  68
Wait for zdtm/static/pidns00(68) to die for 0.100000
Removing dump/zdtm/static/pidns00/38
======================== Test zdtm/static/pidns00 PASS =========================

This error is probably because we don't block sigchld.

[root@fc24 criu]# python test/zdtm.py run -t zdtm/static/pidns00 -f ns --iter 2
=== Run 1/1 ================ zdtm/static/pidns00

======================== Run zdtm/static/pidns00 in ns =========================
Start test
Test is SUID
./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
Run criu dump
Run criu restore
Run criu dump
=[log]=> dump/zdtm/static/pidns00/38/2/dump.log
------------------------ grep Error ------------------------
(00.028723) Error (criu/cr-dump.c:1388): A session leader of 68(1) is outside of its pid namespace
(00.030975) Error (criu/cr-dump.c:1764): Dumping FAILED.
------------------------ ERROR OVER ------------------------
################## Test zdtm/static/pidns00 FAIL at CRIU dump ##################
Send the 9 signal to  68
Wait for zdtm/static/pidns00(68) to die for 0.100000
##################################### FAIL #####################################

This error we have to fix before committing into the upstream repo,
because these changes will break CRIU-iter in Jenkins.

On Tue, Mar 28, 2017 at 06:35:24PM +0300, Kirill Tkhai wrote:
> Create parent (P) and its three children (C1, C2 and C3)
> with different pid namespaces:
> 
> 	     P (pid_ns1)
> 	    /|\
> 	   / | \
> 	  /  |  \
> 	 /   |   \
> 	/    |    \
> (pid_ns1) C1     C2    C3 (pid_ns1)
> 	 (pid_ns2)
> 
> where pid_ns1 is a parent of pid_ns2:
> 
> 	   pid_ns1
> 	      |
> 	   pid_ns2
> 
> Children C1, C2 and C3 created in the written order,
> i.e. C1 has the smallest pid and C2 has the biggest.
> 
> After receiving signal check, that pid namespaces
> restored right.
> 
> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> ---
>  test/zdtm/static/Makefile     |    1 
>  test/zdtm/static/pidns00.c    |  206 +++++++++++++++++++++++++++++++++++++++++
>  test/zdtm/static/pidns00.desc |    1 
>  3 files changed, 208 insertions(+)
>  create mode 100644 test/zdtm/static/pidns00.c
>  create mode 100644 test/zdtm/static/pidns00.desc
> 
> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
> index 8d5641bb..1c921d35 100644
> --- a/test/zdtm/static/Makefile
> +++ b/test/zdtm/static/Makefile
> @@ -182,6 +182,7 @@ TST_NOFILE	:=				\
>  		userns01			\
>  		userns02			\
>  		netns_sub_veth			\
> +		pidns00				\
>  #		jobctl00			\
>  
>  ifneq ($(SRCARCH),arm)
> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
> new file mode 100644
> index 00000000..cdfdbd3d
> --- /dev/null
> +++ b/test/zdtm/static/pidns00.c
> @@ -0,0 +1,206 @@
> +#define _GNU_SOURCE
> +#include <stdbool.h>
> +#include <string.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <signal.h>
> +#include <stdio.h>
> +#include <sys/mount.h>
> +#include <sys/stat.h>
> +#include <sys/mman.h>
> +#include <sys/types.h>
> +#include <sched.h>
> +#include <sys/wait.h>
> +#include <stdlib.h>
> +#include <limits.h>
> +#include <dirent.h>
> +
> +#include "zdtmtst.h"
> +#include "lock.h"
> +
> +/*
> + * Create parent (P) and its three children (C1, C2 and C3)
> + * with different pid namespaces:
> + *
> + *                  P (pid_ns1)
> + *                 /|\
> + *                / | \
> + *               /  |  \
> + *              /   |   \
> + *             /    |    \
> + * (pid_ns1) C1     C2    C3 (pid_ns1)
> + *              (pid_ns2)
> + *
> + * where pid_ns1 is a parent of pid_ns2:
> + *
> + *               pid_ns1
> + *                  |
> + *               pid_ns2
> + * Children C1, C2 and C3 created in the written order,
> + * i.e. C1 has the smallest pid and C2 has the biggest
> + * (so, current restorer should restore them in the same order).
> + * After receiving signal check, that pid namespaces
> + * restored right.
> + */
> +
> +#ifndef NSIO
> +#define NSIO    0xb7
> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> +#endif
> +
> +const char *test_doc	= "Check pid namespace hierarhy restores right";
> +const char *test_author	= "Kirill Tkhai <ktkhai@virtuozzo.com>";
> +
> +futex_t *futex;
> +
> +int child(void)
> +{
> +	futex_wait_while_lt(futex, 1);
> +	return 0;
> +}
> +
> +int __get_ns_id(int fd, unsigned int *id)
> +{
> +	struct stat st;
> +	if (fstat(fd, &st) < 0) {
> +		pr_perror("fstat() kaput");
> +		return 1;
> +	}
> +	*id = st.st_ino;
> +	return 0;
> +}
> +
> +int get_ns_id(pid_t pid, unsigned int *id)
> +{
> +	char buf[PATH_MAX];
> +	int fd, ret;
> +	sprintf(buf, "/proc/%d/ns/pid", pid);
> +	fd = open(buf, O_RDONLY);
> +	if (fd < 0) {
> +		pr_perror("Can't open %s", buf);
> +		return -1;
> +	}
> +	ret = __get_ns_id(fd, id);
> +	close(fd);
> +	return ret;
> +}
> +int main(int argc, char **argv)
> +{
> +	int status, fd, p_fd, i, nr = 0;
> +	unsigned int id, c_id;
> +	char path[PATH_MAX];
> +	pid_t pid[3];
> +
> +	test_init(argc, argv);
> +	futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> +	if (futex == MAP_FAILED) {
> +		fail("mmap futex\n");
> +		return 1;
> +	}
> +	futex_init(futex);
> +
> +	/* Child 1 */
> +	pid[0] = fork();
> +	if (pid[0] == -1) {
> +		fail("fork");
> +		return 1;
> +	} else if (pid[0] == 0)
> +		exit(child());
> +	nr++;
> +
> +	/* Child 2 */
> +	fd = open("/proc/self/ns/pid", O_RDONLY);
> +	if (fd < 0) {
> +		pr_perror("Can't get my own pid ns");
> +		goto err;
> +	}
> +
> +	if (unshare(CLONE_NEWPID) < 0) {
> +		pr_perror("Can't unshare");
> +		goto err;
> +	}
> +
> +	pid[1] = fork();
> +	if (pid[1] == -1) {
> +		fail("fork");
> +		return 1;
> +	} else if (pid[1] == 0)
> +		exit(child());
> +	nr++;
> +
> +	/* Restore pid namespace for children */
> +	if (setns(fd, CLONE_NEWPID) < 0) {
> +		pr_perror("Can't setns");
> +		goto err;
> +	}
> +	close(fd);
> +
> +	/* Child 3 */
> +	pid[2] = fork();
> +	if (pid[2] == -1) {
> +		fail("fork");
> +		goto err;
> +	} else if (pid[2] == 0)
> +		exit(child());
> +	nr++;
> +
> +	test_daemon();
> +	test_waitsig();
> +
> +	if (get_ns_id(getpid(), &id))
> +		goto err;
> +
> +	for (i = 0; i < nr; i++) {
> +		if (get_ns_id(pid[i], &c_id))
> +			goto err;
> +		if (i % 2 == 0) {
> +			if (c_id != id) {
> +				pr_err("Child %d has wrong pid ns\n", i);
> +				goto err;
> +			}
> +			continue;
> +		}
> +
> +		if (id == c_id) {
> +			pr_err("Child %d has wrong pid ns\n", i);
> +			goto err;
> +		}
> +		/* This parent namespace of this Child's should be same to ours */
> +		sprintf(path, "/proc/%d/ns/pid", pid[i]);
> +		fd = open(path, O_RDONLY);
> +		if (fd < 0) {
> +			pr_perror("Can't open");
> +			goto err;
> +		}
> +		p_fd = ioctl(fd, NS_GET_PARENT);
> +		if (p_fd < 0)
> +			pr_perror("Can't get parent");
> +		close(fd);
> +		if (p_fd < 0)
> +			goto err;
> +		if (__get_ns_id(p_fd, &c_id))
> +			goto err;
> +		close(p_fd);
> +		if (id != c_id) {
> +			pr_err("Child %d has wrong pid ns hierarhy\n", i);
> +			goto err;
> +		}
> +	}
> +
> +	futex_set_and_wake(futex, 1);
> +
> +	while (nr-- > 0) {
> +		if (wait(&status) < 0 || WEXITSTATUS(status)) {
> +			fail("pid: status=%d\n", WEXITSTATUS(status));
> +			goto err;
> +		}
> +	}
> +
> +	pass();
> +	return 0;
> +err:
> +	futex_set_and_wake(futex, 1);
> +	while (nr-- > 0)
> +		wait(&status);
> +	return 1;
> +}
> diff --git a/test/zdtm/static/pidns00.desc b/test/zdtm/static/pidns00.desc
> new file mode 100644
> index 00000000..41c1adcc
> --- /dev/null
> +++ b/test/zdtm/static/pidns00.desc
> @@ -0,0 +1 @@
> +{'flavor': 'ns uns', 'flags': 'suid noauto'}
>

Patch hide | download patch | download mbox

diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
index cdfdbd3..72e9019 100644
--- a/test/zdtm/static/pidns00.c
+++ b/test/zdtm/static/pidns00.c
@@ -127,6 +127,22 @@  int main(int argc, char **argv)
        } else if (pid[1] == 0)
                exit(child());
        nr++;
+       /* Restore pid namespace for children */
+       if (setns(fd, CLONE_NEWPID) < 0) {
+               pr_perror("Can't setns");
+               goto err;
+       }
+       if (unshare(CLONE_NEWPID) < 0) {
+               pr_perror("Can't unshare");
+               goto err;
+       }
+
+       pid[1] = fork();
+       if (pid[1] == -1) {
+               fail("fork");
+               return 1;
+       } else if (pid[1] == 0)
+               exit(child());
 
        /* Restore pid namespace for children */
        if (setns(fd, CLONE_NEWPID) < 0) {

Comments

Kirill Tkhai April 6, 2017, 10:01 a.m.
On 06.04.2017 01:16, Andrei Vagin wrote:
> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
> index cdfdbd3..72e9019 100644
> --- a/test/zdtm/static/pidns00.c
> +++ b/test/zdtm/static/pidns00.c
> @@ -127,6 +127,22 @@ int main(int argc, char **argv)
>         } else if (pid[1] == 0)
>                 exit(child());
>         nr++;
> +       /* Restore pid namespace for children */
> +       if (setns(fd, CLONE_NEWPID) < 0) {
> +               pr_perror("Can't setns");
> +               goto err;
> +       }
> +       if (unshare(CLONE_NEWPID) < 0) {
> +               pr_perror("Can't unshare");
> +               goto err;
> +       }
> +
> +       pid[1] = fork();
> +       if (pid[1] == -1) {
> +               fail("fork");
> +               return 1;
> +       } else if (pid[1] == 0)
> +               exit(child());
>  
>         /* Restore pid namespace for children */
>         if (setns(fd, CLONE_NEWPID) < 0) {
> 
> 
> ======================== Run zdtm/static/pidns00 in ns =========================
> Start test
> Test is SUID
> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
> Run criu dump
> Run criu restore
> =[log]=> dump/zdtm/static/pidns00/38/1/restore.log
> ------------------------ grep Error ------------------------
> (00.371112) Error (criu/namespaces.c:1547): 83 exited normally
> (00.372426) Error (criu/namespaces.c:2749): Error during waiting pid_ns helper: No child processes
> ------------------------ ERROR OVER ------------------------
> Send the 15 signal to  68
> Wait for zdtm/static/pidns00(68) to die for 0.100000
> Removing dump/zdtm/static/pidns00/38
> ======================== Test zdtm/static/pidns00 PASS =========================
> 
> This error is probably because we don't block sigchld.

Yeah, I think the same.
 
> [root@fc24 criu]# python test/zdtm.py run -t zdtm/static/pidns00 -f ns --iter 2
> === Run 1/1 ================ zdtm/static/pidns00
> 
> ======================== Run zdtm/static/pidns00 in ns =========================
> Start test
> Test is SUID
> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
> Run criu dump
> Run criu restore
> Run criu dump
> =[log]=> dump/zdtm/static/pidns00/38/2/dump.log
> ------------------------ grep Error ------------------------
> (00.028723) Error (criu/cr-dump.c:1388): A session leader of 68(1) is outside of its pid namespace
> (00.030975) Error (criu/cr-dump.c:1764): Dumping FAILED.
> ------------------------ ERROR OVER ------------------------
> ################## Test zdtm/static/pidns00 FAIL at CRIU dump ##################
> Send the 9 signal to  68
> Wait for zdtm/static/pidns00(68) to die for 0.100000
> ##################################### FAIL #####################################
> 
> This error we have to fix before committing into the upstream repo,
> because these changes will break CRIU-iter in Jenkins.

It's because of sid and pgid are not restored in any way if there is nested pid_ns.
To fix that means to fully support them.

> On Tue, Mar 28, 2017 at 06:35:24PM +0300, Kirill Tkhai wrote:
>> Create parent (P) and its three children (C1, C2 and C3)
>> with different pid namespaces:
>>
>> 	     P (pid_ns1)
>> 	    /|\
>> 	   / | \
>> 	  /  |  \
>> 	 /   |   \
>> 	/    |    \
>> (pid_ns1) C1     C2    C3 (pid_ns1)
>> 	 (pid_ns2)
>>
>> where pid_ns1 is a parent of pid_ns2:
>>
>> 	   pid_ns1
>> 	      |
>> 	   pid_ns2
>>
>> Children C1, C2 and C3 created in the written order,
>> i.e. C1 has the smallest pid and C2 has the biggest.
>>
>> After receiving signal check, that pid namespaces
>> restored right.
>>
>> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
>> ---
>>  test/zdtm/static/Makefile     |    1 
>>  test/zdtm/static/pidns00.c    |  206 +++++++++++++++++++++++++++++++++++++++++
>>  test/zdtm/static/pidns00.desc |    1 
>>  3 files changed, 208 insertions(+)
>>  create mode 100644 test/zdtm/static/pidns00.c
>>  create mode 100644 test/zdtm/static/pidns00.desc
>>
>> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
>> index 8d5641bb..1c921d35 100644
>> --- a/test/zdtm/static/Makefile
>> +++ b/test/zdtm/static/Makefile
>> @@ -182,6 +182,7 @@ TST_NOFILE	:=				\
>>  		userns01			\
>>  		userns02			\
>>  		netns_sub_veth			\
>> +		pidns00				\
>>  #		jobctl00			\
>>  
>>  ifneq ($(SRCARCH),arm)
>> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
>> new file mode 100644
>> index 00000000..cdfdbd3d
>> --- /dev/null
>> +++ b/test/zdtm/static/pidns00.c
>> @@ -0,0 +1,206 @@
>> +#define _GNU_SOURCE
>> +#include <stdbool.h>
>> +#include <string.h>
>> +#include <fcntl.h>
>> +#include <unistd.h>
>> +#include <signal.h>
>> +#include <stdio.h>
>> +#include <sys/mount.h>
>> +#include <sys/stat.h>
>> +#include <sys/mman.h>
>> +#include <sys/types.h>
>> +#include <sched.h>
>> +#include <sys/wait.h>
>> +#include <stdlib.h>
>> +#include <limits.h>
>> +#include <dirent.h>
>> +
>> +#include "zdtmtst.h"
>> +#include "lock.h"
>> +
>> +/*
>> + * Create parent (P) and its three children (C1, C2 and C3)
>> + * with different pid namespaces:
>> + *
>> + *                  P (pid_ns1)
>> + *                 /|\
>> + *                / | \
>> + *               /  |  \
>> + *              /   |   \
>> + *             /    |    \
>> + * (pid_ns1) C1     C2    C3 (pid_ns1)
>> + *              (pid_ns2)
>> + *
>> + * where pid_ns1 is a parent of pid_ns2:
>> + *
>> + *               pid_ns1
>> + *                  |
>> + *               pid_ns2
>> + * Children C1, C2 and C3 created in the written order,
>> + * i.e. C1 has the smallest pid and C2 has the biggest
>> + * (so, current restorer should restore them in the same order).
>> + * After receiving signal check, that pid namespaces
>> + * restored right.
>> + */
>> +
>> +#ifndef NSIO
>> +#define NSIO    0xb7
>> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
>> +#endif
>> +
>> +const char *test_doc	= "Check pid namespace hierarhy restores right";
>> +const char *test_author	= "Kirill Tkhai <ktkhai@virtuozzo.com>";
>> +
>> +futex_t *futex;
>> +
>> +int child(void)
>> +{
>> +	futex_wait_while_lt(futex, 1);
>> +	return 0;
>> +}
>> +
>> +int __get_ns_id(int fd, unsigned int *id)
>> +{
>> +	struct stat st;
>> +	if (fstat(fd, &st) < 0) {
>> +		pr_perror("fstat() kaput");
>> +		return 1;
>> +	}
>> +	*id = st.st_ino;
>> +	return 0;
>> +}
>> +
>> +int get_ns_id(pid_t pid, unsigned int *id)
>> +{
>> +	char buf[PATH_MAX];
>> +	int fd, ret;
>> +	sprintf(buf, "/proc/%d/ns/pid", pid);
>> +	fd = open(buf, O_RDONLY);
>> +	if (fd < 0) {
>> +		pr_perror("Can't open %s", buf);
>> +		return -1;
>> +	}
>> +	ret = __get_ns_id(fd, id);
>> +	close(fd);
>> +	return ret;
>> +}
>> +int main(int argc, char **argv)
>> +{
>> +	int status, fd, p_fd, i, nr = 0;
>> +	unsigned int id, c_id;
>> +	char path[PATH_MAX];
>> +	pid_t pid[3];
>> +
>> +	test_init(argc, argv);
>> +	futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
>> +	if (futex == MAP_FAILED) {
>> +		fail("mmap futex\n");
>> +		return 1;
>> +	}
>> +	futex_init(futex);
>> +
>> +	/* Child 1 */
>> +	pid[0] = fork();
>> +	if (pid[0] == -1) {
>> +		fail("fork");
>> +		return 1;
>> +	} else if (pid[0] == 0)
>> +		exit(child());
>> +	nr++;
>> +
>> +	/* Child 2 */
>> +	fd = open("/proc/self/ns/pid", O_RDONLY);
>> +	if (fd < 0) {
>> +		pr_perror("Can't get my own pid ns");
>> +		goto err;
>> +	}
>> +
>> +	if (unshare(CLONE_NEWPID) < 0) {
>> +		pr_perror("Can't unshare");
>> +		goto err;
>> +	}
>> +
>> +	pid[1] = fork();
>> +	if (pid[1] == -1) {
>> +		fail("fork");
>> +		return 1;
>> +	} else if (pid[1] == 0)
>> +		exit(child());
>> +	nr++;
>> +
>> +	/* Restore pid namespace for children */
>> +	if (setns(fd, CLONE_NEWPID) < 0) {
>> +		pr_perror("Can't setns");
>> +		goto err;
>> +	}
>> +	close(fd);
>> +
>> +	/* Child 3 */
>> +	pid[2] = fork();
>> +	if (pid[2] == -1) {
>> +		fail("fork");
>> +		goto err;
>> +	} else if (pid[2] == 0)
>> +		exit(child());
>> +	nr++;
>> +
>> +	test_daemon();
>> +	test_waitsig();
>> +
>> +	if (get_ns_id(getpid(), &id))
>> +		goto err;
>> +
>> +	for (i = 0; i < nr; i++) {
>> +		if (get_ns_id(pid[i], &c_id))
>> +			goto err;
>> +		if (i % 2 == 0) {
>> +			if (c_id != id) {
>> +				pr_err("Child %d has wrong pid ns\n", i);
>> +				goto err;
>> +			}
>> +			continue;
>> +		}
>> +
>> +		if (id == c_id) {
>> +			pr_err("Child %d has wrong pid ns\n", i);
>> +			goto err;
>> +		}
>> +		/* This parent namespace of this Child's should be same to ours */
>> +		sprintf(path, "/proc/%d/ns/pid", pid[i]);
>> +		fd = open(path, O_RDONLY);
>> +		if (fd < 0) {
>> +			pr_perror("Can't open");
>> +			goto err;
>> +		}
>> +		p_fd = ioctl(fd, NS_GET_PARENT);
>> +		if (p_fd < 0)
>> +			pr_perror("Can't get parent");
>> +		close(fd);
>> +		if (p_fd < 0)
>> +			goto err;
>> +		if (__get_ns_id(p_fd, &c_id))
>> +			goto err;
>> +		close(p_fd);
>> +		if (id != c_id) {
>> +			pr_err("Child %d has wrong pid ns hierarhy\n", i);
>> +			goto err;
>> +		}
>> +	}
>> +
>> +	futex_set_and_wake(futex, 1);
>> +
>> +	while (nr-- > 0) {
>> +		if (wait(&status) < 0 || WEXITSTATUS(status)) {
>> +			fail("pid: status=%d\n", WEXITSTATUS(status));
>> +			goto err;
>> +		}
>> +	}
>> +
>> +	pass();
>> +	return 0;
>> +err:
>> +	futex_set_and_wake(futex, 1);
>> +	while (nr-- > 0)
>> +		wait(&status);
>> +	return 1;
>> +}
>> diff --git a/test/zdtm/static/pidns00.desc b/test/zdtm/static/pidns00.desc
>> new file mode 100644
>> index 00000000..41c1adcc
>> --- /dev/null
>> +++ b/test/zdtm/static/pidns00.desc
>> @@ -0,0 +1 @@
>> +{'flavor': 'ns uns', 'flags': 'suid noauto'}
>>
Andrey Vagin April 6, 2017, 5:23 p.m.
On Thu, Apr 06, 2017 at 01:01:56PM +0300, Kirill Tkhai wrote:
> On 06.04.2017 01:16, Andrei Vagin wrote:
> > diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
> > index cdfdbd3..72e9019 100644
> > --- a/test/zdtm/static/pidns00.c
> > +++ b/test/zdtm/static/pidns00.c
> > @@ -127,6 +127,22 @@ int main(int argc, char **argv)
> >         } else if (pid[1] == 0)
> >                 exit(child());
> >         nr++;
> > +       /* Restore pid namespace for children */
> > +       if (setns(fd, CLONE_NEWPID) < 0) {
> > +               pr_perror("Can't setns");
> > +               goto err;
> > +       }
> > +       if (unshare(CLONE_NEWPID) < 0) {
> > +               pr_perror("Can't unshare");
> > +               goto err;
> > +       }
> > +
> > +       pid[1] = fork();
> > +       if (pid[1] == -1) {
> > +               fail("fork");
> > +               return 1;
> > +       } else if (pid[1] == 0)
> > +               exit(child());
> >  
> >         /* Restore pid namespace for children */
> >         if (setns(fd, CLONE_NEWPID) < 0) {
> > 
> > 
> > ======================== Run zdtm/static/pidns00 in ns =========================
> > Start test
> > Test is SUID
> > ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
> > Run criu dump
> > Run criu restore
> > =[log]=> dump/zdtm/static/pidns00/38/1/restore.log
> > ------------------------ grep Error ------------------------
> > (00.371112) Error (criu/namespaces.c:1547): 83 exited normally
> > (00.372426) Error (criu/namespaces.c:2749): Error during waiting pid_ns helper: No child processes
> > ------------------------ ERROR OVER ------------------------
> > Send the 15 signal to  68
> > Wait for zdtm/static/pidns00(68) to die for 0.100000
> > Removing dump/zdtm/static/pidns00/38
> > ======================== Test zdtm/static/pidns00 PASS =========================
> > 
> > This error is probably because we don't block sigchld.
> 
> Yeah, I think the same.
>  
> > [root@fc24 criu]# python test/zdtm.py run -t zdtm/static/pidns00 -f ns --iter 2
> > === Run 1/1 ================ zdtm/static/pidns00
> > 
> > ======================== Run zdtm/static/pidns00 in ns =========================
> > Start test
> > Test is SUID
> > ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
> > Run criu dump
> > Run criu restore
> > Run criu dump
> > =[log]=> dump/zdtm/static/pidns00/38/2/dump.log
> > ------------------------ grep Error ------------------------
> > (00.028723) Error (criu/cr-dump.c:1388): A session leader of 68(1) is outside of its pid namespace
> > (00.030975) Error (criu/cr-dump.c:1764): Dumping FAILED.
> > ------------------------ ERROR OVER ------------------------
> > ################## Test zdtm/static/pidns00 FAIL at CRIU dump ##################
> > Send the 9 signal to  68
> > Wait for zdtm/static/pidns00(68) to die for 0.100000
> > ##################################### FAIL #####################################
> > 
> > This error we have to fix before committing into the upstream repo,
> > because these changes will break CRIU-iter in Jenkins.
> 
> It's because of sid and pgid are not restored in any way if there is nested pid_ns.
> To fix that means to fully support them.

We have to do  a minimal support, otherwise it can't be commited.


> 
> > On Tue, Mar 28, 2017 at 06:35:24PM +0300, Kirill Tkhai wrote:
> >> Create parent (P) and its three children (C1, C2 and C3)
> >> with different pid namespaces:
> >>
> >> 	     P (pid_ns1)
> >> 	    /|\
> >> 	   / | \
> >> 	  /  |  \
> >> 	 /   |   \
> >> 	/    |    \
> >> (pid_ns1) C1     C2    C3 (pid_ns1)
> >> 	 (pid_ns2)
> >>
> >> where pid_ns1 is a parent of pid_ns2:
> >>
> >> 	   pid_ns1
> >> 	      |
> >> 	   pid_ns2
> >>
> >> Children C1, C2 and C3 created in the written order,
> >> i.e. C1 has the smallest pid and C2 has the biggest.
> >>
> >> After receiving signal check, that pid namespaces
> >> restored right.
> >>
> >> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
> >> ---
> >>  test/zdtm/static/Makefile     |    1 
> >>  test/zdtm/static/pidns00.c    |  206 +++++++++++++++++++++++++++++++++++++++++
> >>  test/zdtm/static/pidns00.desc |    1 
> >>  3 files changed, 208 insertions(+)
> >>  create mode 100644 test/zdtm/static/pidns00.c
> >>  create mode 100644 test/zdtm/static/pidns00.desc
> >>
> >> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
> >> index 8d5641bb..1c921d35 100644
> >> --- a/test/zdtm/static/Makefile
> >> +++ b/test/zdtm/static/Makefile
> >> @@ -182,6 +182,7 @@ TST_NOFILE	:=				\
> >>  		userns01			\
> >>  		userns02			\
> >>  		netns_sub_veth			\
> >> +		pidns00				\
> >>  #		jobctl00			\
> >>  
> >>  ifneq ($(SRCARCH),arm)
> >> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
> >> new file mode 100644
> >> index 00000000..cdfdbd3d
> >> --- /dev/null
> >> +++ b/test/zdtm/static/pidns00.c
> >> @@ -0,0 +1,206 @@
> >> +#define _GNU_SOURCE
> >> +#include <stdbool.h>
> >> +#include <string.h>
> >> +#include <fcntl.h>
> >> +#include <unistd.h>
> >> +#include <signal.h>
> >> +#include <stdio.h>
> >> +#include <sys/mount.h>
> >> +#include <sys/stat.h>
> >> +#include <sys/mman.h>
> >> +#include <sys/types.h>
> >> +#include <sched.h>
> >> +#include <sys/wait.h>
> >> +#include <stdlib.h>
> >> +#include <limits.h>
> >> +#include <dirent.h>
> >> +
> >> +#include "zdtmtst.h"
> >> +#include "lock.h"
> >> +
> >> +/*
> >> + * Create parent (P) and its three children (C1, C2 and C3)
> >> + * with different pid namespaces:
> >> + *
> >> + *                  P (pid_ns1)
> >> + *                 /|\
> >> + *                / | \
> >> + *               /  |  \
> >> + *              /   |   \
> >> + *             /    |    \
> >> + * (pid_ns1) C1     C2    C3 (pid_ns1)
> >> + *              (pid_ns2)
> >> + *
> >> + * where pid_ns1 is a parent of pid_ns2:
> >> + *
> >> + *               pid_ns1
> >> + *                  |
> >> + *               pid_ns2
> >> + * Children C1, C2 and C3 created in the written order,
> >> + * i.e. C1 has the smallest pid and C2 has the biggest
> >> + * (so, current restorer should restore them in the same order).
> >> + * After receiving signal check, that pid namespaces
> >> + * restored right.
> >> + */
> >> +
> >> +#ifndef NSIO
> >> +#define NSIO    0xb7
> >> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
> >> +#endif
> >> +
> >> +const char *test_doc	= "Check pid namespace hierarhy restores right";
> >> +const char *test_author	= "Kirill Tkhai <ktkhai@virtuozzo.com>";
> >> +
> >> +futex_t *futex;
> >> +
> >> +int child(void)
> >> +{
> >> +	futex_wait_while_lt(futex, 1);
> >> +	return 0;
> >> +}
> >> +
> >> +int __get_ns_id(int fd, unsigned int *id)
> >> +{
> >> +	struct stat st;
> >> +	if (fstat(fd, &st) < 0) {
> >> +		pr_perror("fstat() kaput");
> >> +		return 1;
> >> +	}
> >> +	*id = st.st_ino;
> >> +	return 0;
> >> +}
> >> +
> >> +int get_ns_id(pid_t pid, unsigned int *id)
> >> +{
> >> +	char buf[PATH_MAX];
> >> +	int fd, ret;
> >> +	sprintf(buf, "/proc/%d/ns/pid", pid);
> >> +	fd = open(buf, O_RDONLY);
> >> +	if (fd < 0) {
> >> +		pr_perror("Can't open %s", buf);
> >> +		return -1;
> >> +	}
> >> +	ret = __get_ns_id(fd, id);
> >> +	close(fd);
> >> +	return ret;
> >> +}
> >> +int main(int argc, char **argv)
> >> +{
> >> +	int status, fd, p_fd, i, nr = 0;
> >> +	unsigned int id, c_id;
> >> +	char path[PATH_MAX];
> >> +	pid_t pid[3];
> >> +
> >> +	test_init(argc, argv);
> >> +	futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
> >> +	if (futex == MAP_FAILED) {
> >> +		fail("mmap futex\n");
> >> +		return 1;
> >> +	}
> >> +	futex_init(futex);
> >> +
> >> +	/* Child 1 */
> >> +	pid[0] = fork();
> >> +	if (pid[0] == -1) {
> >> +		fail("fork");
> >> +		return 1;
> >> +	} else if (pid[0] == 0)
> >> +		exit(child());
> >> +	nr++;
> >> +
> >> +	/* Child 2 */
> >> +	fd = open("/proc/self/ns/pid", O_RDONLY);
> >> +	if (fd < 0) {
> >> +		pr_perror("Can't get my own pid ns");
> >> +		goto err;
> >> +	}
> >> +
> >> +	if (unshare(CLONE_NEWPID) < 0) {
> >> +		pr_perror("Can't unshare");
> >> +		goto err;
> >> +	}
> >> +
> >> +	pid[1] = fork();
> >> +	if (pid[1] == -1) {
> >> +		fail("fork");
> >> +		return 1;
> >> +	} else if (pid[1] == 0)
> >> +		exit(child());
> >> +	nr++;
> >> +
> >> +	/* Restore pid namespace for children */
> >> +	if (setns(fd, CLONE_NEWPID) < 0) {
> >> +		pr_perror("Can't setns");
> >> +		goto err;
> >> +	}
> >> +	close(fd);
> >> +
> >> +	/* Child 3 */
> >> +	pid[2] = fork();
> >> +	if (pid[2] == -1) {
> >> +		fail("fork");
> >> +		goto err;
> >> +	} else if (pid[2] == 0)
> >> +		exit(child());
> >> +	nr++;
> >> +
> >> +	test_daemon();
> >> +	test_waitsig();
> >> +
> >> +	if (get_ns_id(getpid(), &id))
> >> +		goto err;
> >> +
> >> +	for (i = 0; i < nr; i++) {
> >> +		if (get_ns_id(pid[i], &c_id))
> >> +			goto err;
> >> +		if (i % 2 == 0) {
> >> +			if (c_id != id) {
> >> +				pr_err("Child %d has wrong pid ns\n", i);
> >> +				goto err;
> >> +			}
> >> +			continue;
> >> +		}
> >> +
> >> +		if (id == c_id) {
> >> +			pr_err("Child %d has wrong pid ns\n", i);
> >> +			goto err;
> >> +		}
> >> +		/* This parent namespace of this Child's should be same to ours */
> >> +		sprintf(path, "/proc/%d/ns/pid", pid[i]);
> >> +		fd = open(path, O_RDONLY);
> >> +		if (fd < 0) {
> >> +			pr_perror("Can't open");
> >> +			goto err;
> >> +		}
> >> +		p_fd = ioctl(fd, NS_GET_PARENT);
> >> +		if (p_fd < 0)
> >> +			pr_perror("Can't get parent");
> >> +		close(fd);
> >> +		if (p_fd < 0)
> >> +			goto err;
> >> +		if (__get_ns_id(p_fd, &c_id))
> >> +			goto err;
> >> +		close(p_fd);
> >> +		if (id != c_id) {
> >> +			pr_err("Child %d has wrong pid ns hierarhy\n", i);
> >> +			goto err;
> >> +		}
> >> +	}
> >> +
> >> +	futex_set_and_wake(futex, 1);
> >> +
> >> +	while (nr-- > 0) {
> >> +		if (wait(&status) < 0 || WEXITSTATUS(status)) {
> >> +			fail("pid: status=%d\n", WEXITSTATUS(status));
> >> +			goto err;
> >> +		}
> >> +	}
> >> +
> >> +	pass();
> >> +	return 0;
> >> +err:
> >> +	futex_set_and_wake(futex, 1);
> >> +	while (nr-- > 0)
> >> +		wait(&status);
> >> +	return 1;
> >> +}
> >> diff --git a/test/zdtm/static/pidns00.desc b/test/zdtm/static/pidns00.desc
> >> new file mode 100644
> >> index 00000000..41c1adcc
> >> --- /dev/null
> >> +++ b/test/zdtm/static/pidns00.desc
> >> @@ -0,0 +1 @@
> >> +{'flavor': 'ns uns', 'flags': 'suid noauto'}
> >>
Kirill Tkhai April 7, 2017, 8:58 a.m.
On 06.04.2017 20:23, Andrei Vagin wrote:
> On Thu, Apr 06, 2017 at 01:01:56PM +0300, Kirill Tkhai wrote:
>> On 06.04.2017 01:16, Andrei Vagin wrote:
>>> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
>>> index cdfdbd3..72e9019 100644
>>> --- a/test/zdtm/static/pidns00.c
>>> +++ b/test/zdtm/static/pidns00.c
>>> @@ -127,6 +127,22 @@ int main(int argc, char **argv)
>>>         } else if (pid[1] == 0)
>>>                 exit(child());
>>>         nr++;
>>> +       /* Restore pid namespace for children */
>>> +       if (setns(fd, CLONE_NEWPID) < 0) {
>>> +               pr_perror("Can't setns");
>>> +               goto err;
>>> +       }
>>> +       if (unshare(CLONE_NEWPID) < 0) {
>>> +               pr_perror("Can't unshare");
>>> +               goto err;
>>> +       }
>>> +
>>> +       pid[1] = fork();
>>> +       if (pid[1] == -1) {
>>> +               fail("fork");
>>> +               return 1;
>>> +       } else if (pid[1] == 0)
>>> +               exit(child());
>>>  
>>>         /* Restore pid namespace for children */
>>>         if (setns(fd, CLONE_NEWPID) < 0) {
>>>
>>>
>>> ======================== Run zdtm/static/pidns00 in ns =========================
>>> Start test
>>> Test is SUID
>>> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
>>> Run criu dump
>>> Run criu restore
>>> =[log]=> dump/zdtm/static/pidns00/38/1/restore.log
>>> ------------------------ grep Error ------------------------
>>> (00.371112) Error (criu/namespaces.c:1547): 83 exited normally
>>> (00.372426) Error (criu/namespaces.c:2749): Error during waiting pid_ns helper: No child processes
>>> ------------------------ ERROR OVER ------------------------
>>> Send the 15 signal to  68
>>> Wait for zdtm/static/pidns00(68) to die for 0.100000
>>> Removing dump/zdtm/static/pidns00/38
>>> ======================== Test zdtm/static/pidns00 PASS =========================
>>>
>>> This error is probably because we don't block sigchld.
>>
>> Yeah, I think the same.
>>  
>>> [root@fc24 criu]# python test/zdtm.py run -t zdtm/static/pidns00 -f ns --iter 2
>>> === Run 1/1 ================ zdtm/static/pidns00
>>>
>>> ======================== Run zdtm/static/pidns00 in ns =========================
>>> Start test
>>> Test is SUID
>>> ./pidns00 --pidfile=pidns00.pid --outfile=pidns00.out
>>> Run criu dump
>>> Run criu restore
>>> Run criu dump
>>> =[log]=> dump/zdtm/static/pidns00/38/2/dump.log
>>> ------------------------ grep Error ------------------------
>>> (00.028723) Error (criu/cr-dump.c:1388): A session leader of 68(1) is outside of its pid namespace
>>> (00.030975) Error (criu/cr-dump.c:1764): Dumping FAILED.
>>> ------------------------ ERROR OVER ------------------------
>>> ################## Test zdtm/static/pidns00 FAIL at CRIU dump ##################
>>> Send the 9 signal to  68
>>> Wait for zdtm/static/pidns00(68) to die for 0.100000
>>> ##################################### FAIL #####################################
>>>
>>> This error we have to fix before committing into the upstream repo,
>>> because these changes will break CRIU-iter in Jenkins.
>>
>> It's because of sid and pgid are not restored in any way if there is nested pid_ns.
>> To fix that means to fully support them.
> 
> We have to do  a minimal support, otherwise it can't be commited.

What is minimal support?
 
> 
>>
>>> On Tue, Mar 28, 2017 at 06:35:24PM +0300, Kirill Tkhai wrote:
>>>> Create parent (P) and its three children (C1, C2 and C3)
>>>> with different pid namespaces:
>>>>
>>>> 	     P (pid_ns1)
>>>> 	    /|\
>>>> 	   / | \
>>>> 	  /  |  \
>>>> 	 /   |   \
>>>> 	/    |    \
>>>> (pid_ns1) C1     C2    C3 (pid_ns1)
>>>> 	 (pid_ns2)
>>>>
>>>> where pid_ns1 is a parent of pid_ns2:
>>>>
>>>> 	   pid_ns1
>>>> 	      |
>>>> 	   pid_ns2
>>>>
>>>> Children C1, C2 and C3 created in the written order,
>>>> i.e. C1 has the smallest pid and C2 has the biggest.
>>>>
>>>> After receiving signal check, that pid namespaces
>>>> restored right.
>>>>
>>>> Signed-off-by: Kirill Tkhai <ktkhai@virtuozzo.com>
>>>> ---
>>>>  test/zdtm/static/Makefile     |    1 
>>>>  test/zdtm/static/pidns00.c    |  206 +++++++++++++++++++++++++++++++++++++++++
>>>>  test/zdtm/static/pidns00.desc |    1 
>>>>  3 files changed, 208 insertions(+)
>>>>  create mode 100644 test/zdtm/static/pidns00.c
>>>>  create mode 100644 test/zdtm/static/pidns00.desc
>>>>
>>>> diff --git a/test/zdtm/static/Makefile b/test/zdtm/static/Makefile
>>>> index 8d5641bb..1c921d35 100644
>>>> --- a/test/zdtm/static/Makefile
>>>> +++ b/test/zdtm/static/Makefile
>>>> @@ -182,6 +182,7 @@ TST_NOFILE	:=				\
>>>>  		userns01			\
>>>>  		userns02			\
>>>>  		netns_sub_veth			\
>>>> +		pidns00				\
>>>>  #		jobctl00			\
>>>>  
>>>>  ifneq ($(SRCARCH),arm)
>>>> diff --git a/test/zdtm/static/pidns00.c b/test/zdtm/static/pidns00.c
>>>> new file mode 100644
>>>> index 00000000..cdfdbd3d
>>>> --- /dev/null
>>>> +++ b/test/zdtm/static/pidns00.c
>>>> @@ -0,0 +1,206 @@
>>>> +#define _GNU_SOURCE
>>>> +#include <stdbool.h>
>>>> +#include <string.h>
>>>> +#include <fcntl.h>
>>>> +#include <unistd.h>
>>>> +#include <signal.h>
>>>> +#include <stdio.h>
>>>> +#include <sys/mount.h>
>>>> +#include <sys/stat.h>
>>>> +#include <sys/mman.h>
>>>> +#include <sys/types.h>
>>>> +#include <sched.h>
>>>> +#include <sys/wait.h>
>>>> +#include <stdlib.h>
>>>> +#include <limits.h>
>>>> +#include <dirent.h>
>>>> +
>>>> +#include "zdtmtst.h"
>>>> +#include "lock.h"
>>>> +
>>>> +/*
>>>> + * Create parent (P) and its three children (C1, C2 and C3)
>>>> + * with different pid namespaces:
>>>> + *
>>>> + *                  P (pid_ns1)
>>>> + *                 /|\
>>>> + *                / | \
>>>> + *               /  |  \
>>>> + *              /   |   \
>>>> + *             /    |    \
>>>> + * (pid_ns1) C1     C2    C3 (pid_ns1)
>>>> + *              (pid_ns2)
>>>> + *
>>>> + * where pid_ns1 is a parent of pid_ns2:
>>>> + *
>>>> + *               pid_ns1
>>>> + *                  |
>>>> + *               pid_ns2
>>>> + * Children C1, C2 and C3 created in the written order,
>>>> + * i.e. C1 has the smallest pid and C2 has the biggest
>>>> + * (so, current restorer should restore them in the same order).
>>>> + * After receiving signal check, that pid namespaces
>>>> + * restored right.
>>>> + */
>>>> +
>>>> +#ifndef NSIO
>>>> +#define NSIO    0xb7
>>>> +#define NS_GET_PARENT   _IO(NSIO, 0x2)
>>>> +#endif
>>>> +
>>>> +const char *test_doc	= "Check pid namespace hierarhy restores right";
>>>> +const char *test_author	= "Kirill Tkhai <ktkhai@virtuozzo.com>";
>>>> +
>>>> +futex_t *futex;
>>>> +
>>>> +int child(void)
>>>> +{
>>>> +	futex_wait_while_lt(futex, 1);
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int __get_ns_id(int fd, unsigned int *id)
>>>> +{
>>>> +	struct stat st;
>>>> +	if (fstat(fd, &st) < 0) {
>>>> +		pr_perror("fstat() kaput");
>>>> +		return 1;
>>>> +	}
>>>> +	*id = st.st_ino;
>>>> +	return 0;
>>>> +}
>>>> +
>>>> +int get_ns_id(pid_t pid, unsigned int *id)
>>>> +{
>>>> +	char buf[PATH_MAX];
>>>> +	int fd, ret;
>>>> +	sprintf(buf, "/proc/%d/ns/pid", pid);
>>>> +	fd = open(buf, O_RDONLY);
>>>> +	if (fd < 0) {
>>>> +		pr_perror("Can't open %s", buf);
>>>> +		return -1;
>>>> +	}
>>>> +	ret = __get_ns_id(fd, id);
>>>> +	close(fd);
>>>> +	return ret;
>>>> +}
>>>> +int main(int argc, char **argv)
>>>> +{
>>>> +	int status, fd, p_fd, i, nr = 0;
>>>> +	unsigned int id, c_id;
>>>> +	char path[PATH_MAX];
>>>> +	pid_t pid[3];
>>>> +
>>>> +	test_init(argc, argv);
>>>> +	futex = mmap(NULL, sizeof(*futex), PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
>>>> +	if (futex == MAP_FAILED) {
>>>> +		fail("mmap futex\n");
>>>> +		return 1;
>>>> +	}
>>>> +	futex_init(futex);
>>>> +
>>>> +	/* Child 1 */
>>>> +	pid[0] = fork();
>>>> +	if (pid[0] == -1) {
>>>> +		fail("fork");
>>>> +		return 1;
>>>> +	} else if (pid[0] == 0)
>>>> +		exit(child());
>>>> +	nr++;
>>>> +
>>>> +	/* Child 2 */
>>>> +	fd = open("/proc/self/ns/pid", O_RDONLY);
>>>> +	if (fd < 0) {
>>>> +		pr_perror("Can't get my own pid ns");
>>>> +		goto err;
>>>> +	}
>>>> +
>>>> +	if (unshare(CLONE_NEWPID) < 0) {
>>>> +		pr_perror("Can't unshare");
>>>> +		goto err;
>>>> +	}
>>>> +
>>>> +	pid[1] = fork();
>>>> +	if (pid[1] == -1) {
>>>> +		fail("fork");
>>>> +		return 1;
>>>> +	} else if (pid[1] == 0)
>>>> +		exit(child());
>>>> +	nr++;
>>>> +
>>>> +	/* Restore pid namespace for children */
>>>> +	if (setns(fd, CLONE_NEWPID) < 0) {
>>>> +		pr_perror("Can't setns");
>>>> +		goto err;
>>>> +	}
>>>> +	close(fd);
>>>> +
>>>> +	/* Child 3 */
>>>> +	pid[2] = fork();
>>>> +	if (pid[2] == -1) {
>>>> +		fail("fork");
>>>> +		goto err;
>>>> +	} else if (pid[2] == 0)
>>>> +		exit(child());
>>>> +	nr++;
>>>> +
>>>> +	test_daemon();
>>>> +	test_waitsig();
>>>> +
>>>> +	if (get_ns_id(getpid(), &id))
>>>> +		goto err;
>>>> +
>>>> +	for (i = 0; i < nr; i++) {
>>>> +		if (get_ns_id(pid[i], &c_id))
>>>> +			goto err;
>>>> +		if (i % 2 == 0) {
>>>> +			if (c_id != id) {
>>>> +				pr_err("Child %d has wrong pid ns\n", i);
>>>> +				goto err;
>>>> +			}
>>>> +			continue;
>>>> +		}
>>>> +
>>>> +		if (id == c_id) {
>>>> +			pr_err("Child %d has wrong pid ns\n", i);
>>>> +			goto err;
>>>> +		}
>>>> +		/* This parent namespace of this Child's should be same to ours */
>>>> +		sprintf(path, "/proc/%d/ns/pid", pid[i]);
>>>> +		fd = open(path, O_RDONLY);
>>>> +		if (fd < 0) {
>>>> +			pr_perror("Can't open");
>>>> +			goto err;
>>>> +		}
>>>> +		p_fd = ioctl(fd, NS_GET_PARENT);
>>>> +		if (p_fd < 0)
>>>> +			pr_perror("Can't get parent");
>>>> +		close(fd);
>>>> +		if (p_fd < 0)
>>>> +			goto err;
>>>> +		if (__get_ns_id(p_fd, &c_id))
>>>> +			goto err;
>>>> +		close(p_fd);
>>>> +		if (id != c_id) {
>>>> +			pr_err("Child %d has wrong pid ns hierarhy\n", i);
>>>> +			goto err;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	futex_set_and_wake(futex, 1);
>>>> +
>>>> +	while (nr-- > 0) {
>>>> +		if (wait(&status) < 0 || WEXITSTATUS(status)) {
>>>> +			fail("pid: status=%d\n", WEXITSTATUS(status));
>>>> +			goto err;
>>>> +		}
>>>> +	}
>>>> +
>>>> +	pass();
>>>> +	return 0;
>>>> +err:
>>>> +	futex_set_and_wake(futex, 1);
>>>> +	while (nr-- > 0)
>>>> +		wait(&status);
>>>> +	return 1;
>>>> +}
>>>> diff --git a/test/zdtm/static/pidns00.desc b/test/zdtm/static/pidns00.desc
>>>> new file mode 100644
>>>> index 00000000..41c1adcc
>>>> --- /dev/null
>>>> +++ b/test/zdtm/static/pidns00.desc
>>>> @@ -0,0 +1 @@
>>>> +{'flavor': 'ns uns', 'flags': 'suid noauto'}
>>>>