aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2008-10-22 13:57:07 -0400
committerSteve French <sfrench@us.ibm.com>2008-10-23 01:06:20 -0400
commitb1c8d2b421376bc941823ee93e36cb491609b02c (patch)
tree40908334b5a289ef7e6337d14d29104cc2bd79e2 /fs
parent8d281efb67463fe8aac8f6e10b31492fc218bf2b (diff)
cifs: handle the TCP_Server_Info->tsk field more carefully
cifs: handle the TCP_Server_Info->tsk field more carefully We currently handle the TCP_Server_Info->tsk field without any locking, but with some half-measures to try and prevent races. These aren't really sufficient though. When taking down cifsd, use xchg() to swap the contents of the tsk field with NULL so we don't end up trying to send it more than one signal. Also, don't allow cifsd to exit until the signal is received if we expect one. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs')
-rw-r--r--fs/cifs/connect.c41
1 files changed, 28 insertions, 13 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index f51b79a67e1b..71b7661e2260 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -750,6 +750,7 @@ multi_t2_fnd:
750 write_unlock(&GlobalSMBSeslock); 750 write_unlock(&GlobalSMBSeslock);
751 751
752 kfree(server->hostname); 752 kfree(server->hostname);
753 task_to_wake = xchg(&server->tsk, NULL);
753 kfree(server); 754 kfree(server);
754 755
755 length = atomic_dec_return(&tcpSesAllocCount); 756 length = atomic_dec_return(&tcpSesAllocCount);
@@ -757,6 +758,16 @@ multi_t2_fnd:
757 mempool_resize(cifs_req_poolp, length + cifs_min_rcv, 758 mempool_resize(cifs_req_poolp, length + cifs_min_rcv,
758 GFP_KERNEL); 759 GFP_KERNEL);
759 760
761 /* if server->tsk was NULL then wait for a signal before exiting */
762 if (!task_to_wake) {
763 set_current_state(TASK_INTERRUPTIBLE);
764 while (!signal_pending(current)) {
765 schedule();
766 set_current_state(TASK_INTERRUPTIBLE);
767 }
768 set_current_state(TASK_RUNNING);
769 }
770
760 return 0; 771 return 0;
761} 772}
762 773
@@ -1846,6 +1857,16 @@ convert_delimiter(char *path, char delim)
1846 } 1857 }
1847} 1858}
1848 1859
1860static void
1861kill_cifsd(struct TCP_Server_Info *server)
1862{
1863 struct task_struct *task;
1864
1865 task = xchg(&server->tsk, NULL);
1866 if (task)
1867 force_sig(SIGKILL, task);
1868}
1869
1849int 1870int
1850cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, 1871cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1851 char *mount_data, const char *devname) 1872 char *mount_data, const char *devname)
@@ -2233,7 +2254,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2233 spin_lock(&GlobalMid_Lock); 2254 spin_lock(&GlobalMid_Lock);
2234 srvTcp->tcpStatus = CifsExiting; 2255 srvTcp->tcpStatus = CifsExiting;
2235 spin_unlock(&GlobalMid_Lock); 2256 spin_unlock(&GlobalMid_Lock);
2236 force_sig(SIGKILL, srvTcp->tsk); 2257 kill_cifsd(srvTcp);
2237 } 2258 }
2238 /* If find_unc succeeded then rc == 0 so we can not end */ 2259 /* If find_unc succeeded then rc == 0 so we can not end */
2239 if (tcon) /* up accidently freeing someone elses tcon struct */ 2260 if (tcon) /* up accidently freeing someone elses tcon struct */
@@ -2246,19 +2267,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2246 temp_rc = CIFSSMBLogoff(xid, pSesInfo); 2267 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2247 /* if the socketUseCount is now zero */ 2268 /* if the socketUseCount is now zero */
2248 if ((temp_rc == -ESHUTDOWN) && 2269 if ((temp_rc == -ESHUTDOWN) &&
2249 (pSesInfo->server) && 2270 (pSesInfo->server))
2250 (pSesInfo->server->tsk)) 2271 kill_cifsd(pSesInfo->server);
2251 force_sig(SIGKILL,
2252 pSesInfo->server->tsk);
2253 } else { 2272 } else {
2254 cFYI(1, ("No session or bad tcon")); 2273 cFYI(1, ("No session or bad tcon"));
2255 if ((pSesInfo->server) && 2274 if (pSesInfo->server) {
2256 (pSesInfo->server->tsk)) {
2257 spin_lock(&GlobalMid_Lock); 2275 spin_lock(&GlobalMid_Lock);
2258 srvTcp->tcpStatus = CifsExiting; 2276 srvTcp->tcpStatus = CifsExiting;
2259 spin_unlock(&GlobalMid_Lock); 2277 spin_unlock(&GlobalMid_Lock);
2260 force_sig(SIGKILL, 2278 kill_cifsd(pSesInfo->server);
2261 pSesInfo->server->tsk);
2262 } 2279 }
2263 } 2280 }
2264 sesInfoFree(pSesInfo); 2281 sesInfoFree(pSesInfo);
@@ -3545,7 +3562,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3545 int rc = 0; 3562 int rc = 0;
3546 int xid; 3563 int xid;
3547 struct cifsSesInfo *ses = NULL; 3564 struct cifsSesInfo *ses = NULL;
3548 struct task_struct *cifsd_task;
3549 char *tmp; 3565 char *tmp;
3550 3566
3551 xid = GetXid(); 3567 xid = GetXid();
@@ -3561,7 +3577,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3561 tconInfoFree(cifs_sb->tcon); 3577 tconInfoFree(cifs_sb->tcon);
3562 if ((ses) && (ses->server)) { 3578 if ((ses) && (ses->server)) {
3563 /* save off task so we do not refer to ses later */ 3579 /* save off task so we do not refer to ses later */
3564 cifsd_task = ses->server->tsk;
3565 cFYI(1, ("About to do SMBLogoff ")); 3580 cFYI(1, ("About to do SMBLogoff "));
3566 rc = CIFSSMBLogoff(xid, ses); 3581 rc = CIFSSMBLogoff(xid, ses);
3567 if (rc == -EBUSY) { 3582 if (rc == -EBUSY) {
@@ -3569,8 +3584,8 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3569 return 0; 3584 return 0;
3570 } else if (rc == -ESHUTDOWN) { 3585 } else if (rc == -ESHUTDOWN) {
3571 cFYI(1, ("Waking up socket by sending signal")); 3586 cFYI(1, ("Waking up socket by sending signal"));
3572 if (cifsd_task) 3587 if (ses->server)
3573 force_sig(SIGKILL, cifsd_task); 3588 kill_cifsd(ses->server);
3574 rc = 0; 3589 rc = 0;
3575 } /* else - we have an smb session 3590 } /* else - we have an smb session
3576 left on this socket do not kill cifsd */ 3591 left on this socket do not kill cifsd */