aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c205
1 files changed, 72 insertions, 133 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 30ab8dc68e17..a0314259f94d 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -659,6 +659,11 @@ multi_t2_fnd:
659 } 659 }
660 } /* end while !EXITING */ 660 } /* end while !EXITING */
661 661
662 /* take it off the list, if it's not already */
663 write_lock(&cifs_tcp_ses_lock);
664 list_del_init(&server->tcp_ses_list);
665 write_unlock(&cifs_tcp_ses_lock);
666
662 spin_lock(&GlobalMid_Lock); 667 spin_lock(&GlobalMid_Lock);
663 server->tcpStatus = CifsExiting; 668 server->tcpStatus = CifsExiting;
664 spin_unlock(&GlobalMid_Lock); 669 spin_unlock(&GlobalMid_Lock);
@@ -1357,92 +1362,66 @@ cifs_parse_mount_options(char *options, const char *devname,
1357 return 0; 1362 return 0;
1358} 1363}
1359 1364
1360static struct cifsSesInfo * 1365static struct TCP_Server_Info *
1361cifs_find_tcp_session(struct in_addr *target_ip_addr, 1366cifs_find_tcp_session(struct sockaddr *addr)
1362 struct in6_addr *target_ip6_addr,
1363 char *userName, struct TCP_Server_Info **psrvTcp)
1364{ 1367{
1365 struct list_head *tmp; 1368 struct list_head *tmp;
1366 struct cifsSesInfo *ses; 1369 struct TCP_Server_Info *server;
1367 1370 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1368 *psrvTcp = NULL; 1371 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
1369 1372
1370 read_lock(&GlobalSMBSeslock); 1373 write_lock(&cifs_tcp_ses_lock);
1371 list_for_each(tmp, &GlobalSMBSessionList) { 1374 list_for_each(tmp, &cifs_tcp_ses_list) {
1372 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 1375 server = list_entry(tmp, struct TCP_Server_Info,
1373 if (!ses->server) 1376 tcp_ses_list);
1377
1378 /*
1379 * the demux thread can exit on its own while still in CifsNew
1380 * so don't accept any sockets in that state. Since the
1381 * tcpStatus never changes back to CifsNew it's safe to check
1382 * for this without a lock.
1383 */
1384 if (server->tcpStatus == CifsNew)
1374 continue; 1385 continue;
1375 1386
1376 if (target_ip_addr && 1387 if (addr->sa_family == AF_INET &&
1377 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) 1388 (addr4->sin_addr.s_addr !=
1378 continue; 1389 server->addr.sockAddr.sin_addr.s_addr))
1379 else if (target_ip6_addr && 1390 continue;
1380 memcmp(&ses->server->addr.sockAddr6.sin6_addr, 1391 else if (addr->sa_family == AF_INET6 &&
1381 target_ip6_addr, sizeof(*target_ip6_addr))) 1392 memcmp(&server->addr.sockAddr6.sin6_addr,
1382 continue; 1393 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1383 /* BB lock server and tcp session; increment use count here?? */ 1394 continue;
1384
1385 /* found a match on the TCP session */
1386 *psrvTcp = ses->server;
1387 1395
1388 /* BB check if reconnection needed */ 1396 ++server->srv_count;
1389 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { 1397 write_unlock(&cifs_tcp_ses_lock);
1390 read_unlock(&GlobalSMBSeslock); 1398 return server;
1391 /* Found exact match on both TCP and
1392 SMB sessions */
1393 return ses;
1394 }
1395 /* else tcp and smb sessions need reconnection */
1396 } 1399 }
1397 read_unlock(&GlobalSMBSeslock); 1400 write_unlock(&cifs_tcp_ses_lock);
1398
1399 return NULL; 1401 return NULL;
1400} 1402}
1401 1403
1402static struct cifsTconInfo * 1404void
1403find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) 1405cifs_put_tcp_session(struct TCP_Server_Info *server)
1404{ 1406{
1405 struct list_head *tmp; 1407 struct task_struct *task;
1406 struct cifsTconInfo *tcon;
1407 __be32 old_ip;
1408
1409 read_lock(&GlobalSMBSeslock);
1410
1411 list_for_each(tmp, &GlobalTreeConnectionList) {
1412 cFYI(1, ("Next tcon"));
1413 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
1414 if (!tcon->ses || !tcon->ses->server)
1415 continue;
1416
1417 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr;
1418 cFYI(1, ("old ip addr: %x == new ip %x ?",
1419 old_ip, new_target_ip_addr));
1420
1421 if (old_ip != new_target_ip_addr)
1422 continue;
1423
1424 /* BB lock tcon, server, tcp session and increment use count? */
1425 /* found a match on the TCP session */
1426 /* BB check if reconnection needed */
1427 cFYI(1, ("IP match, old UNC: %s new: %s",
1428 tcon->treeName, uncName));
1429 1408
1430 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE)) 1409 write_lock(&cifs_tcp_ses_lock);
1431 continue; 1410 if (--server->srv_count > 0) {
1411 write_unlock(&cifs_tcp_ses_lock);
1412 return;
1413 }
1432 1414
1433 cFYI(1, ("and old usr: %s new: %s", 1415 list_del_init(&server->tcp_ses_list);
1434 tcon->treeName, uncName)); 1416 write_unlock(&cifs_tcp_ses_lock);
1435 1417
1436 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE)) 1418 spin_lock(&GlobalMid_Lock);
1437 continue; 1419 server->tcpStatus = CifsExiting;
1438 1420 spin_unlock(&GlobalMid_Lock);
1439 /* matched smb session (user name) */
1440 read_unlock(&GlobalSMBSeslock);
1441 return tcon;
1442 }
1443 1421
1444 read_unlock(&GlobalSMBSeslock); 1422 task = xchg(&server->tsk, NULL);
1445 return NULL; 1423 if (task)
1424 force_sig(SIGKILL, task);
1446} 1425}
1447 1426
1448int 1427int
@@ -1881,16 +1860,6 @@ convert_delimiter(char *path, char delim)
1881 } 1860 }
1882} 1861}
1883 1862
1884static void
1885kill_cifsd(struct TCP_Server_Info *server)
1886{
1887 struct task_struct *task;
1888
1889 task = xchg(&server->tsk, NULL);
1890 if (task)
1891 force_sig(SIGKILL, task);
1892}
1893
1894static void setup_cifs_sb(struct smb_vol *pvolume_info, 1863static void setup_cifs_sb(struct smb_vol *pvolume_info,
1895 struct cifs_sb_info *cifs_sb) 1864 struct cifs_sb_info *cifs_sb)
1896{ 1865{
@@ -2069,21 +2038,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2069 } 2038 }
2070 } 2039 }
2071 2040
2072 if (addr.sa_family == AF_INET) 2041 srvTcp = cifs_find_tcp_session(&addr);
2073 existingCifsSes = cifs_find_tcp_session(&sin_server->sin_addr, 2042 if (srvTcp) {
2074 NULL /* no ipv6 addr */, 2043 cFYI(1, ("Existing tcp session with server found"));
2075 volume_info.username, &srvTcp); 2044 } else { /* create socket */
2076 else if (addr.sa_family == AF_INET6) {
2077 cFYI(1, ("looking for ipv6 address"));
2078 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
2079 &sin_server6->sin6_addr,
2080 volume_info.username, &srvTcp);
2081 } else {
2082 rc = -EINVAL;
2083 goto out;
2084 }
2085
2086 if (!srvTcp) {
2087 if (addr.sa_family == AF_INET6) { 2045 if (addr.sa_family == AF_INET6) {
2088 cFYI(1, ("attempting ipv6 connect")); 2046 cFYI(1, ("attempting ipv6 connect"));
2089 /* BB should we allow ipv6 on port 139? */ 2047 /* BB should we allow ipv6 on port 139? */
@@ -2153,6 +2111,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2153 memcpy(srvTcp->server_RFC1001_name, 2111 memcpy(srvTcp->server_RFC1001_name,
2154 volume_info.target_rfc1001_name, 16); 2112 volume_info.target_rfc1001_name, 16);
2155 srvTcp->sequence_number = 0; 2113 srvTcp->sequence_number = 0;
2114 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
2115 ++srvTcp->srv_count;
2116 write_lock(&cifs_tcp_ses_lock);
2117 list_add(&srvTcp->tcp_ses_list,
2118 &cifs_tcp_ses_list);
2119 write_unlock(&cifs_tcp_ses_lock);
2156 } 2120 }
2157 } 2121 }
2158 2122
@@ -2204,8 +2168,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2204 rc = cifs_setup_session(xid, pSesInfo, 2168 rc = cifs_setup_session(xid, pSesInfo,
2205 cifs_sb->local_nls); 2169 cifs_sb->local_nls);
2206 up(&pSesInfo->sesSem); 2170 up(&pSesInfo->sesSem);
2207 if (!rc)
2208 atomic_inc(&srvTcp->socketUseCount);
2209 } 2171 }
2210 } 2172 }
2211 2173
@@ -2213,9 +2175,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2213 if (!rc) { 2175 if (!rc) {
2214 setup_cifs_sb(&volume_info, cifs_sb); 2176 setup_cifs_sb(&volume_info, cifs_sb);
2215 2177
2216 tcon =
2217 find_unc(sin_server->sin_addr.s_addr, volume_info.UNC,
2218 volume_info.username);
2219 if (tcon) { 2178 if (tcon) {
2220 cFYI(1, ("Found match on UNC path")); 2179 cFYI(1, ("Found match on UNC path"));
2221 if (tcon->seal != volume_info.seal) 2180 if (tcon->seal != volume_info.seal)
@@ -2278,35 +2237,21 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2278/* on error free sesinfo and tcon struct if needed */ 2237/* on error free sesinfo and tcon struct if needed */
2279mount_fail_check: 2238mount_fail_check:
2280 if (rc) { 2239 if (rc) {
2281 /* if session setup failed, use count is zero but 2240 /* If find_unc succeeded then rc == 0 so we can not end */
2282 we still need to free cifsd thread */ 2241 /* up accidently freeing someone elses tcon struct */
2283 if (atomic_read(&srvTcp->socketUseCount) == 0) { 2242 if (tcon)
2284 spin_lock(&GlobalMid_Lock);
2285 srvTcp->tcpStatus = CifsExiting;
2286 spin_unlock(&GlobalMid_Lock);
2287 kill_cifsd(srvTcp);
2288 }
2289 /* If find_unc succeeded then rc == 0 so we can not end */
2290 if (tcon) /* up accidently freeing someone elses tcon struct */
2291 tconInfoFree(tcon); 2243 tconInfoFree(tcon);
2244
2292 if (existingCifsSes == NULL) { 2245 if (existingCifsSes == NULL) {
2293 if (pSesInfo) { 2246 if (pSesInfo) {
2294 if ((pSesInfo->server) && 2247 if ((pSesInfo->server) &&
2295 (pSesInfo->status == CifsGood)) { 2248 (pSesInfo->status == CifsGood))
2296 int temp_rc; 2249 CIFSSMBLogoff(xid, pSesInfo);
2297 temp_rc = CIFSSMBLogoff(xid, pSesInfo); 2250 else {
2298 /* if the socketUseCount is now zero */
2299 if ((temp_rc == -ESHUTDOWN) &&
2300 (pSesInfo->server))
2301 kill_cifsd(pSesInfo->server);
2302 } else {
2303 cFYI(1, ("No session or bad tcon")); 2251 cFYI(1, ("No session or bad tcon"));
2304 if (pSesInfo->server) { 2252 if (pSesInfo->server)
2305 spin_lock(&GlobalMid_Lock); 2253 cifs_put_tcp_session(
2306 srvTcp->tcpStatus = CifsExiting; 2254 pSesInfo->server);
2307 spin_unlock(&GlobalMid_Lock);
2308 kill_cifsd(pSesInfo->server);
2309 }
2310 } 2255 }
2311 sesInfoFree(pSesInfo); 2256 sesInfoFree(pSesInfo);
2312 /* pSesInfo = NULL; */ 2257 /* pSesInfo = NULL; */
@@ -3613,13 +3558,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3613 if (rc == -EBUSY) { 3558 if (rc == -EBUSY) {
3614 FreeXid(xid); 3559 FreeXid(xid);
3615 return 0; 3560 return 0;
3616 } else if (rc == -ESHUTDOWN) { 3561 }
3617 cFYI(1, ("Waking up socket by sending signal"));
3618 if (ses->server)
3619 kill_cifsd(ses->server);
3620 rc = 0;
3621 } /* else - we have an smb session
3622 left on this socket do not kill cifsd */
3623 } else 3562 } else
3624 cFYI(1, ("No session or bad tcon")); 3563 cFYI(1, ("No session or bad tcon"));
3625 } 3564 }