aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2008-10-16 14:46:39 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-16 14:46:39 -0400
commit469ee614aaa367d9cde01cbdd2027212f56c6cc6 (patch)
treeb3adf11b97e14ece7c10c81ea9f156f16491ca87
parent2c1b861539c15491593625920058e06452cd3747 (diff)
[CIFS] eliminate usage of kthread_stop for cifsd
When cifs_demultiplex_thread was converted to a kthread based kernel thread, great pains were taken to make it so that kthread_stop would be used to bring it down. This just added unnecessary complexity since we needed to use a signal anyway to break out of kernel_recvmsg. Also, cifs_demultiplex_thread does a bit of cleanup as it's exiting, and we need to be certain that this gets done. It's possible for a kthread to exit before its main function is ever run if kthread_stop is called soon after its creation. While I'm not sure that this is a real problem with cifsd now, it could be at some point in the future if cifs_mount is ever changed to bring down the thread quickly. The upshot here is that using kthread_stop to bring down the thread just adds extra complexity with no real benefit. This patch changes the code to use the original method to bring down the thread, but still leaves it so that the thread is actually started with kthread_run. This seems to fix the deadlock caused by the reproducer in this bug report: https://bugzilla.samba.org/show_bug.cgi?id=5720 Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
-rw-r--r--fs/cifs/connect.c44
1 files changed, 15 insertions, 29 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 17ca8ce81bb7..1126f7ab4606 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -125,7 +125,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
125 struct mid_q_entry *mid_entry; 125 struct mid_q_entry *mid_entry;
126 126
127 spin_lock(&GlobalMid_Lock); 127 spin_lock(&GlobalMid_Lock);
128 if (kthread_should_stop()) { 128 if (server->tcpStatus == CifsExiting) {
129 /* the demux thread will exit normally 129 /* the demux thread will exit normally
130 next time through the loop */ 130 next time through the loop */
131 spin_unlock(&GlobalMid_Lock); 131 spin_unlock(&GlobalMid_Lock);
@@ -185,7 +185,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
185 spin_unlock(&GlobalMid_Lock); 185 spin_unlock(&GlobalMid_Lock);
186 up(&server->tcpSem); 186 up(&server->tcpSem);
187 187
188 while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) { 188 while ((server->tcpStatus != CifsExiting) &&
189 (server->tcpStatus != CifsGood)) {
189 try_to_freeze(); 190 try_to_freeze();
190 if (server->protocolType == IPV6) { 191 if (server->protocolType == IPV6) {
191 rc = ipv6_connect(&server->addr.sockAddr6, 192 rc = ipv6_connect(&server->addr.sockAddr6,
@@ -202,7 +203,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
202 } else { 203 } else {
203 atomic_inc(&tcpSesReconnectCount); 204 atomic_inc(&tcpSesReconnectCount);
204 spin_lock(&GlobalMid_Lock); 205 spin_lock(&GlobalMid_Lock);
205 if (!kthread_should_stop()) 206 if (server->tcpStatus != CifsExiting)
206 server->tcpStatus = CifsGood; 207 server->tcpStatus = CifsGood;
207 server->sequence_number = 0; 208 server->sequence_number = 0;
208 spin_unlock(&GlobalMid_Lock); 209 spin_unlock(&GlobalMid_Lock);
@@ -357,7 +358,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
357 GFP_KERNEL); 358 GFP_KERNEL);
358 359
359 set_freezable(); 360 set_freezable();
360 while (!kthread_should_stop()) { 361 while (server->tcpStatus != CifsExiting) {
361 if (try_to_freeze()) 362 if (try_to_freeze())
362 continue; 363 continue;
363 if (bigbuf == NULL) { 364 if (bigbuf == NULL) {
@@ -398,7 +399,7 @@ incomplete_rcv:
398 kernel_recvmsg(csocket, &smb_msg, 399 kernel_recvmsg(csocket, &smb_msg,
399 &iov, 1, pdu_length, 0 /* BB other flags? */); 400 &iov, 1, pdu_length, 0 /* BB other flags? */);
400 401
401 if (kthread_should_stop()) { 402 if (server->tcpStatus == CifsExiting) {
402 break; 403 break;
403 } else if (server->tcpStatus == CifsNeedReconnect) { 404 } else if (server->tcpStatus == CifsNeedReconnect) {
404 cFYI(1, ("Reconnect after server stopped responding")); 405 cFYI(1, ("Reconnect after server stopped responding"));
@@ -523,7 +524,7 @@ incomplete_rcv:
523 total_read += length) { 524 total_read += length) {
524 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1, 525 length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
525 pdu_length - total_read, 0); 526 pdu_length - total_read, 0);
526 if (kthread_should_stop() || 527 if ((server->tcpStatus == CifsExiting) ||
527 (length == -EINTR)) { 528 (length == -EINTR)) {
528 /* then will exit */ 529 /* then will exit */
529 reconnect = 2; 530 reconnect = 2;
@@ -652,14 +653,6 @@ multi_t2_fnd:
652 spin_unlock(&GlobalMid_Lock); 653 spin_unlock(&GlobalMid_Lock);
653 wake_up_all(&server->response_q); 654 wake_up_all(&server->response_q);
654 655
655 /* don't exit until kthread_stop is called */
656 set_current_state(TASK_UNINTERRUPTIBLE);
657 while (!kthread_should_stop()) {
658 schedule();
659 set_current_state(TASK_UNINTERRUPTIBLE);
660 }
661 set_current_state(TASK_RUNNING);
662
663 /* check if we have blocked requests that need to free */ 656 /* check if we have blocked requests that need to free */
664 /* Note that cifs_max_pending is normally 50, but 657 /* Note that cifs_max_pending is normally 50, but
665 can be set at module install time to as little as two */ 658 can be set at module install time to as little as two */
@@ -2234,14 +2227,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2234 spin_lock(&GlobalMid_Lock); 2227 spin_lock(&GlobalMid_Lock);
2235 srvTcp->tcpStatus = CifsExiting; 2228 srvTcp->tcpStatus = CifsExiting;
2236 spin_unlock(&GlobalMid_Lock); 2229 spin_unlock(&GlobalMid_Lock);
2237 if (srvTcp->tsk) { 2230 force_sig(SIGKILL, srvTcp->tsk);
2238 /* If we could verify that kthread_stop would
2239 always wake up processes blocked in
2240 tcp in recv_mesg then we could remove the
2241 send_sig call */
2242 force_sig(SIGKILL, srvTcp->tsk);
2243 kthread_stop(srvTcp->tsk);
2244 }
2245 } 2231 }
2246 /* If find_unc succeeded then rc == 0 so we can not end */ 2232 /* If find_unc succeeded then rc == 0 so we can not end */
2247 if (tcon) /* up accidently freeing someone elses tcon struct */ 2233 if (tcon) /* up accidently freeing someone elses tcon struct */
@@ -2255,18 +2241,18 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2255 /* if the socketUseCount is now zero */ 2241 /* if the socketUseCount is now zero */
2256 if ((temp_rc == -ESHUTDOWN) && 2242 if ((temp_rc == -ESHUTDOWN) &&
2257 (pSesInfo->server) && 2243 (pSesInfo->server) &&
2258 (pSesInfo->server->tsk)) { 2244 (pSesInfo->server->tsk))
2259 force_sig(SIGKILL, 2245 force_sig(SIGKILL,
2260 pSesInfo->server->tsk); 2246 pSesInfo->server->tsk);
2261 kthread_stop(pSesInfo->server->tsk);
2262 }
2263 } else { 2247 } else {
2264 cFYI(1, ("No session or bad tcon")); 2248 cFYI(1, ("No session or bad tcon"));
2265 if ((pSesInfo->server) && 2249 if ((pSesInfo->server) &&
2266 (pSesInfo->server->tsk)) { 2250 (pSesInfo->server->tsk)) {
2251 spin_lock(&GlobalMid_Lock);
2252 srvTcp->tcpStatus = CifsExiting;
2253 spin_unlock(&GlobalMid_Lock);
2267 force_sig(SIGKILL, 2254 force_sig(SIGKILL,
2268 pSesInfo->server->tsk); 2255 pSesInfo->server->tsk);
2269 kthread_stop(pSesInfo->server->tsk);
2270 } 2256 }
2271 } 2257 }
2272 sesInfoFree(pSesInfo); 2258 sesInfoFree(pSesInfo);
@@ -3577,10 +3563,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3577 return 0; 3563 return 0;
3578 } else if (rc == -ESHUTDOWN) { 3564 } else if (rc == -ESHUTDOWN) {
3579 cFYI(1, ("Waking up socket by sending signal")); 3565 cFYI(1, ("Waking up socket by sending signal"));
3580 if (cifsd_task) { 3566 if (cifsd_task)
3581 force_sig(SIGKILL, cifsd_task); 3567 force_sig(SIGKILL, cifsd_task);
3582 kthread_stop(cifsd_task);
3583 }
3584 rc = 0; 3568 rc = 0;
3585 } /* else - we have an smb session 3569 } /* else - we have an smb session
3586 left on this socket do not kill cifsd */ 3570 left on this socket do not kill cifsd */
@@ -3710,7 +3694,9 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3710 cERROR(1, ("Send error in SessSetup = %d", rc)); 3694 cERROR(1, ("Send error in SessSetup = %d", rc));
3711 } else { 3695 } else {
3712 cFYI(1, ("CIFS Session Established successfully")); 3696 cFYI(1, ("CIFS Session Established successfully"));
3697 spin_lock(&GlobalMid_Lock);
3713 pSesInfo->status = CifsGood; 3698 pSesInfo->status = CifsGood;
3699 spin_unlock(&GlobalMid_Lock);
3714 } 3700 }
3715 3701
3716ss_err_exit: 3702ss_err_exit: