summaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 19:44:49 +0100
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-03-20 19:44:49 +0100
commit1dd761e9070aa2e543df3db41bd75ed4b8f2fab9 (patch)
tree7709d032855e0e821f3ff4ce9efc3bdb82bf4d2d /fs
parentSUNRPC: Fix a 'Busy inodes' error in rpc_pipefs (diff)
downloadlinux-1dd761e9070aa2e543df3db41bd75ed4b8f2fab9.tar.xz
linux-1dd761e9070aa2e543df3db41bd75ed4b8f2fab9.zip
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 <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/nfs/callback.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c
index 2c042f8d70b5..99d2cfbce863 100644
--- a/fs/nfs/callback.c
+++ b/fs/nfs/callback.c
@@ -55,7 +55,12 @@ static void nfs_callback_svc(struct svc_rqst *rqstp)
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;