Author: Trond Myklebust NFSv4: Ensure the callback daemon flushes signals If the callback daemon is signalled, but is unable to exit because it still has users, then we need to flush signals. If not, then svc_recv() can never sleep, and so we hang. If we flush signals, then we also have to be prepared to resend them when we want the thread to exit. Signed-off-by: Trond Myklebust --- fs/nfs/callback.c | 19 +++++++++++++------ 1 files changed, 13 insertions(+), 6 deletions(-) diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 2c042f8..99d2cfb 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -55,7 +55,12 @@ static void nfs_callback_svc(struct svc_ complete(&nfs_callback_info.started); - while (nfs_callback_info.users != 0 || !signalled()) { + for(;;) { + if (signalled()) { + if (nfs_callback_info.users == 0) + break; + flush_signals(current); + } /* * Listen for a request on the socket */ @@ -135,11 +140,13 @@ int nfs_callback_down(void) lock_kernel(); down(&nfs_callback_sema); - if (--nfs_callback_info.users || nfs_callback_info.pid == 0) - goto out; - kill_proc(nfs_callback_info.pid, SIGKILL, 1); - wait_for_completion(&nfs_callback_info.stopped); -out: + nfs_callback_info.users--; + do { + if (nfs_callback_info.users != 0 || nfs_callback_info.pid == 0) + break; + if (kill_proc(nfs_callback_info.pid, SIGKILL, 1) < 0) + break; + } while (wait_for_completion_timeout(&nfs_callback_info.stopped, 5*HZ) == 0); up(&nfs_callback_sema); unlock_kernel(); return ret;