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.