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

[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 <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <syslog.h>
#include <pthread.h>

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);
	}
}

Compile this code with below command:

# gcc -Wall -pthread -o zstate2 zstate2.c

Test Steps

1. In NFS Client, run the above program:

# mount -t nfs <nfs-server>:<nfs-share> /mnt/nfs
# /tmp/zstate2

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

Then we will see a zstate2 thread keep in D-state:

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

3. Send SIGTERM signal to this process:

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

And we will see the one thread keeps in D state, and the leader thread (process) keeps in Z state.