summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-05-11 15:53:33 +0000
committerSteve French <sfrench@us.ibm.com>2008-05-11 17:45:44 +0000
commite691b9d1a096fbaaff9d6d6aef1adc593b786e62 (patch)
treea329a4d115315d4dd459d171c3c98b2bc8c4728b
parent67750fb9e07940c078d1edb16fd736ccc92a4a4e (diff)
downloadlinux-e691b9d1a096fbaaff9d6d6aef1adc593b786e62.tar.gz
linux-e691b9d1a096fbaaff9d6d6aef1adc593b786e62.tar.bz2
linux-e691b9d1a096fbaaff9d6d6aef1adc593b786e62.zip
[CIFS] don't allow demultiplex thread to exit until kthread_stop is called
cifs_demultiplex_thread can exit under several conditions: 1) if it's signaled 2) if there's a problem with session setup 3) if kthread_stop is called on it The first two are problems. If kthread_stop is called on the thread, there is no guarantee that it will still be up. We need to have the thread stay up until kthread_stop is called on it. One option would be to not even try to tear things down until after kthread_stop is called. However, in the case where there is a problem setting up the session, there's no real reason to try continuing the loop. This patch allows the thread to clean up and prepare for exit under all three conditions, but it has the thread go to sleep until kthread_stop is called. This allows us to simplify the shutdown code somewhat since we can be reasonably sure that the thread won't exit after being signaled but before kthread_stop is called. It also removes the places where the thread itself set the tsk variable since it appeared that it could have a potential race where the thread might never be shut down. Signed-off-by: Jeff Layton <jlayton@redhat.com> Acked-by: Christoph Hellwig <hch@infradead.org> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/connect.c28
1 files changed, 14 insertions, 14 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 965050867599..f428bf3bf1a9 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -348,7 +348,6 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
int reconnect;
current->flags |= PF_MEMALLOC;
- server->tsk = current; /* save process info to wake at shutdown */
cFYI(1, ("Demultiplex PID: %d", task_pid_nr(current)));
write_lock(&GlobalSMBSeslock);
atomic_inc(&tcpSesAllocCount);
@@ -651,10 +650,20 @@ multi_t2_fnd:
spin_lock(&GlobalMid_Lock);
server->tcpStatus = CifsExiting;
- server->tsk = NULL;
+ spin_unlock(&GlobalMid_Lock);
+
+ /* don't exit until kthread_stop is called */
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ while (!kthread_should_stop()) {
+ schedule();
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+
/* check if we have blocked requests that need to free */
/* Note that cifs_max_pending is normally 50, but
can be set at module install time to as little as two */
+ spin_lock(&GlobalMid_Lock);
if (atomic_read(&server->inFlight) >= cifs_max_pending)
atomic_set(&server->inFlight, cifs_max_pending - 1);
/* We do not want to set the max_pending too low or we
@@ -2187,15 +2196,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
srvTcp->tcpStatus = CifsExiting;
spin_unlock(&GlobalMid_Lock);
if (srvTcp->tsk) {
- struct task_struct *tsk;
/* If we could verify that kthread_stop would
always wake up processes blocked in
tcp in recv_mesg then we could remove the
send_sig call */
force_sig(SIGKILL, srvTcp->tsk);
- tsk = srvTcp->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(srvTcp->tsk);
}
}
/* If find_unc succeeded then rc == 0 so we can not end */
@@ -2211,23 +2217,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
if ((temp_rc == -ESHUTDOWN) &&
(pSesInfo->server) &&
(pSesInfo->server->tsk)) {
- struct task_struct *tsk;
force_sig(SIGKILL,
pSesInfo->server->tsk);
- tsk = pSesInfo->server->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(pSesInfo->server->tsk);
}
} else {
cFYI(1, ("No session or bad tcon"));
if ((pSesInfo->server) &&
(pSesInfo->server->tsk)) {
- struct task_struct *tsk;
force_sig(SIGKILL,
pSesInfo->server->tsk);
- tsk = pSesInfo->server->tsk;
- if (tsk)
- kthread_stop(tsk);
+ kthread_stop(pSesInfo->server->tsk);
}
}
sesInfoFree(pSesInfo);