Note: init not cleaning zombie process if it contains D-state thread(s)

I observed that when terminating a process with D-state thread(s), the process would keep in zombie state, instead of being reclaimed by init (pid-1). Here comes the steps to reproduce this behavior.

Test Environment

2 x Red Hat Enterprise Linux 6.7
|
— NFS Server
|
— NFS Client (Run below code in this server)

Example Code

[cc]
[root@rhel674 tmp]# cat zstate2.c
/****
This example code will create 3 threads,
one thread will keep writing data to a file in NFS mount point,
the other two threads will keep sleeping, doing nothing.
****/
#include
#include
#include
#include
#include
#include
#include
#include

void *task1();
void *task2();
void *task3();

int main()
{
pthread_t thread1,thread2,thread3;
const char *message1 = “Thread 1”;
const char *message2 = “Thread 2”;
const char *message3 = “Thread 3”;
int iret1, iret2, iret3;

iret1 = pthread_create ( &thread1, NULL, task1, NULL);
if(iret1)
{
fprintf(stderr, “Error – pthread_create() return code: %d\n”, iret1);
return 1;
}

iret2 = pthread_create ( &thread2, NULL, task2, NULL);
if(iret2)
{
fprintf(stderr, “Error – pthread_create() return code: %d\n”, iret2);
return 2;
}

iret3 = pthread_create ( &thread3, NULL, task3, NULL);
if(iret3)
{
fprintf(stderr, “Error – pthread_create() return code: %d\n”, iret3);
return 3;
}

printf(“pthread_create() for thread 1 returns: %d\n”,iret1);
printf(“pthread_create() for thread 2 returns: %d\n”,iret2);
printf(“pthread_create() for thread 3 returns: %d\n”,iret3);

pthread_join( thread1, NULL);
pthread_join( thread2, NULL);
pthread_join( thread3, NULL);

return 0;
}

/* This task read a NFS file. Could be in D state */
void *task1()
{
FILE *pFile;
pFile=fopen(“/mnt/nfs/testfile”, “r+”);
while(1){
fprintf (pFile, “test”);
}
}

/* Sleeping */
void *task2()
{
while(1){
sleep(1);
}
}

/* Sleeping */
void *task3()
{
while(1){
sleep(1);
}
}
[/cc]

Compile this code with below command:
[cc]
# gcc -Wall -pthread -o zstate2 zstate2.c
[/cc]

Test Steps

1. In NFS Client, run the above program:
[cc]
# mount -t nfs : /mnt/nfs
# /tmp/zstate2
[/cc]

2. After a while, poweroff (shut it down forcefully ) NFS Server.

Then we will see a zstate2 thread keep in D-state:
[cc]
[root@HA6-0 ~]# ll /proc/3801/task/ <<<---- 3801 is the pid of zstate2 total 0 dr-xr-xr-x. 6 root root 0 Apr 12 18:38 3801 dr-xr-xr-x. 6 root root 0 Apr 12 18:38 3802 dr-xr-xr-x. 6 root root 0 Apr 12 18:38 3803 dr-xr-xr-x. 6 root root 0 Apr 12 18:38 3804 [root@HA6-0 ~]# cat /proc/380{1,2,3,4}/status | grep -i state Name: zstate2 State: S (sleeping) Name: zstate2 State: D (disk sleep) Name: zstate2 State: S (sleeping) Name: zstate2 State: S (sleeping) [/cc] 3. Send SIGTERM signal to this process: [cc] [root@HA6-0 ~]# kill 3801 [root@HA6-0 ~]# cat /proc/380{1,2,3,4}/status | grep -i state cat: /proc/3803/status: No such file or directory cat: /proc/3804/status: No such file or directory Name: zstate2 State: Z (zombie) Name: zstate2 State: D (disk sleep) [/cc] And we will see the one thread keeps in D state, and the leader thread (process) keeps in Z state.