summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2008-12-10 06:44:29 -0500
committerGreg Kroah-Hartman <gregkh@suse.de>2008-12-13 15:29:34 -0800
commit39493f2809c5d4ee52ab118e0197644ad9490d13 (patch)
treec997b169c0f4e280a4d24958d78205cddcccbc65
parent631867888f51ec9dc40bc8f7cb43cc39a6892158 (diff)
cifs: fix a regression in cifs umount codepath
backport of 469ee614aaa367d9cde01cbdd2027212f56c6cc6 upstream. Several cifs patches were added to 2.6.27.8 to fix some races in the mount/umount codepath. When this was done, a couple of prerequisite patches were missed causing a minor regression. When the last cifs mount to a server goes away, the kthread that manages the socket is supposed to come down. The patches that went into 2.6.27.8 removed the kthread_stop calls that used to take down these threads, but left the thread function expecting them. This made the thread stay up even after the last mount was gone. This patch should fix up this regression and also prevent a possible race where a dead task could be signalled. Signed-off-by: Jeff Layton <jlayton@redhat.com> Cc: Suresh Jayaraman <sjayaraman@suse.de> Acked-by: Steve French <smfrench@gmail.com> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--fs/cifs/connect.c36
1 files changed, 21 insertions, 15 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 6e2be4abe802..223647f7489b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -128,7 +128,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
struct mid_q_entry *mid_entry;
spin_lock(&GlobalMid_Lock);
- if (kthread_should_stop()) {
+ if (server->tcpStatus == CifsExiting) {
/* the demux thread will exit normally
next time through the loop */
spin_unlock(&GlobalMid_Lock);
@@ -182,7 +182,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
spin_unlock(&GlobalMid_Lock);
up(&server->tcpSem);
- while ((!kthread_should_stop()) && (server->tcpStatus != CifsGood)) {
+ while ((server->tcpStatus != CifsExiting) &&
+ (server->tcpStatus != CifsGood)) {
try_to_freeze();
if (server->addr.sockAddr6.sin6_family == AF_INET6) {
rc = ipv6_connect(&server->addr.sockAddr6,
@@ -200,7 +201,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
} else {
atomic_inc(&tcpSesReconnectCount);
spin_lock(&GlobalMid_Lock);
- if (!kthread_should_stop())
+ if (server->tcpStatus != CifsExiting)
server->tcpStatus = CifsGood;
server->sequence_number = 0;
spin_unlock(&GlobalMid_Lock);
@@ -355,7 +356,7 @@ cifs_demultiplex_thread(struct TCP_Server_Info *server)
GFP_KERNEL);
set_freezable();
- while (!kthread_should_stop()) {
+ while (server->tcpStatus != CifsExiting) {
if (try_to_freeze())
continue;
if (bigbuf == NULL) {
@@ -396,7 +397,7 @@ incomplete_rcv:
kernel_recvmsg(csocket, &smb_msg,
&iov, 1, pdu_length, 0 /* BB other flags? */);
- if (kthread_should_stop()) {
+ if (server->tcpStatus == CifsExiting) {
break;
} else if (server->tcpStatus == CifsNeedReconnect) {
cFYI(1, ("Reconnect after server stopped responding"));
@@ -527,7 +528,7 @@ incomplete_rcv:
total_read += length) {
length = kernel_recvmsg(csocket, &smb_msg, &iov, 1,
pdu_length - total_read, 0);
- if (kthread_should_stop() ||
+ if ((server->tcpStatus == CifsExiting) ||
(length == -EINTR)) {
/* then will exit */
reconnect = 2;
@@ -661,14 +662,6 @@ multi_t2_fnd:
spin_unlock(&GlobalMid_Lock);
wake_up_all(&server->response_q);
- /* 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 */
@@ -764,6 +757,7 @@ multi_t2_fnd:
read_unlock(&cifs_tcp_ses_lock);
kfree(server->hostname);
+ task_to_wake = xchg(&server->tsk, NULL);
kfree(server);
length = atomic_dec_return(&tcpSesAllocCount);
@@ -771,6 +765,16 @@ multi_t2_fnd:
mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
GFP_KERNEL);
+ /* if server->tsk was NULL then wait for a signal before exiting */
+ if (!task_to_wake) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (!signal_pending(current)) {
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+ }
+ set_current_state(TASK_RUNNING);
+ }
+
return 0;
}
@@ -2310,7 +2314,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
/* on error free sesinfo and tcon struct if needed */
mount_fail_check:
if (rc) {
- /* If find_unc succeeded then rc == 0 so we can not end */
+ /* If find_unc succeeded then rc == 0 so we can not end */
/* up accidently freeing someone elses tcon struct */
if (tcon)
cifs_put_tcon(tcon);
@@ -3715,8 +3719,10 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
cERROR(1, ("Send error in SessSetup = %d", rc));
} else {
cFYI(1, ("CIFS Session Established successfully"));
+ spin_lock(&GlobalMid_Lock);
pSesInfo->status = CifsGood;
pSesInfo->need_reconnect = false;
+ spin_unlock(&GlobalMid_Lock);
}
ss_err_exit: