aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs')
-rw-r--r--fs/cifs/cifs_debug.c2
-rw-r--r--fs/cifs/cifsfs.c3
-rw-r--r--fs/cifs/cifsglob.h17
-rw-r--r--fs/cifs/cifsproto.h1
-rw-r--r--fs/cifs/cifssmb.c18
-rw-r--r--fs/cifs/connect.c205
6 files changed, 96 insertions, 150 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index ba8723d95996..40b5108fb4f9 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -144,7 +144,7 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v)
144 seq_printf(m, "TCP status: %d\n\tLocal Users To " 144 seq_printf(m, "TCP status: %d\n\tLocal Users To "
145 "Server: %d SecMode: 0x%x Req On Wire: %d", 145 "Server: %d SecMode: 0x%x Req On Wire: %d",
146 ses->server->tcpStatus, 146 ses->server->tcpStatus,
147 atomic_read(&ses->server->socketUseCount), 147 ses->server->srv_count,
148 ses->server->secMode, 148 ses->server->secMode,
149 atomic_read(&ses->server->inFlight)); 149 atomic_read(&ses->server->inFlight));
150 150
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index af16a2406b1c..2946dab0718f 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -1059,7 +1059,7 @@ init_cifs(void)
1059{ 1059{
1060 int rc = 0; 1060 int rc = 0;
1061 cifs_proc_init(); 1061 cifs_proc_init();
1062 INIT_LIST_HEAD(&global_cifs_sock_list); 1062 INIT_LIST_HEAD(&cifs_tcp_ses_list);
1063 INIT_LIST_HEAD(&GlobalSMBSessionList); /* BB to be removed by jl */ 1063 INIT_LIST_HEAD(&GlobalSMBSessionList); /* BB to be removed by jl */
1064 INIT_LIST_HEAD(&GlobalTreeConnectionList); /* BB to be removed by jl */ 1064 INIT_LIST_HEAD(&GlobalTreeConnectionList); /* BB to be removed by jl */
1065 INIT_LIST_HEAD(&GlobalOplock_Q); 1065 INIT_LIST_HEAD(&GlobalOplock_Q);
@@ -1089,6 +1089,7 @@ init_cifs(void)
1089 GlobalMaxActiveXid = 0; 1089 GlobalMaxActiveXid = 0;
1090 memset(Local_System_Name, 0, 15); 1090 memset(Local_System_Name, 0, 15);
1091 rwlock_init(&GlobalSMBSeslock); 1091 rwlock_init(&GlobalSMBSeslock);
1092 rwlock_init(&cifs_tcp_ses_lock);
1092 spin_lock_init(&GlobalMid_Lock); 1093 spin_lock_init(&GlobalMid_Lock);
1093 1094
1094 if (cifs_max_pending < 2) { 1095 if (cifs_max_pending < 2) {
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 13dc48414a78..313f7bfedec7 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -123,6 +123,7 @@ struct cifs_cred {
123struct TCP_Server_Info { 123struct TCP_Server_Info {
124 struct list_head tcp_ses_list; 124 struct list_head tcp_ses_list;
125 struct list_head smb_ses_list; 125 struct list_head smb_ses_list;
126 int srv_count; /* reference counter */
126 /* 15 character server name + 0x20 16th byte indicating type = srv */ 127 /* 15 character server name + 0x20 16th byte indicating type = srv */
127 char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; 128 char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL];
128 char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; 129 char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2];
@@ -144,7 +145,6 @@ struct TCP_Server_Info {
144 bool svlocal:1; /* local server or remote */ 145 bool svlocal:1; /* local server or remote */
145 bool noblocksnd; /* use blocking sendmsg */ 146 bool noblocksnd; /* use blocking sendmsg */
146 bool noautotune; /* do not autotune send buf sizes */ 147 bool noautotune; /* do not autotune send buf sizes */
147 atomic_t socketUseCount; /* number of open cifs sessions on socket */
148 atomic_t inFlight; /* number of requests on the wire to server */ 148 atomic_t inFlight; /* number of requests on the wire to server */
149#ifdef CONFIG_CIFS_STATS2 149#ifdef CONFIG_CIFS_STATS2
150 atomic_t inSend; /* requests trying to send */ 150 atomic_t inSend; /* requests trying to send */
@@ -591,13 +591,18 @@ require use of the stronger protocol */
591#define GLOBAL_EXTERN extern 591#define GLOBAL_EXTERN extern
592#endif 592#endif
593 593
594 594/*
595/* the list of TCP_Server_Info structures, ie each of the sockets 595 * the list of TCP_Server_Info structures, ie each of the sockets
596 * connecting our client to a distinct server (ip address), is 596 * connecting our client to a distinct server (ip address), is
597 * chained together by global_cifs_sock_list. The list of all our SMB 597 * chained together by cifs_tcp_ses_list. The list of all our SMB
598 * sessions (and from that the tree connections) can be found 598 * sessions (and from that the tree connections) can be found
599 * by iterating over global_cifs_sock_list */ 599 * by iterating over cifs_tcp_ses_list
600GLOBAL_EXTERN struct list_head global_cifs_sock_list; 600 */
601GLOBAL_EXTERN struct list_head cifs_tcp_ses_list;
602
603/* protects cifs_tcp_ses_list and srv_count for each tcp session */
604GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock;
605
601GLOBAL_EXTERN struct list_head GlobalSMBSessionList; /* BB to be removed by jl*/ 606GLOBAL_EXTERN struct list_head GlobalSMBSessionList; /* BB to be removed by jl*/
602GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; /* BB to be removed */ 607GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; /* BB to be removed */
603GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 608GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h
index 6f21ecb85ce5..0250a994c6e6 100644
--- a/fs/cifs/cifsproto.h
+++ b/fs/cifs/cifsproto.h
@@ -102,6 +102,7 @@ extern void acl_to_uid_mode(struct inode *inode, const char *path,
102 const __u16 *pfid); 102 const __u16 *pfid);
103extern int mode_to_acl(struct inode *inode, const char *path, __u64); 103extern int mode_to_acl(struct inode *inode, const char *path, __u64);
104 104
105extern void cifs_put_tcp_session(struct TCP_Server_Info *server);
105extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *, 106extern int cifs_mount(struct super_block *, struct cifs_sb_info *, char *,
106 const char *); 107 const char *);
107extern int cifs_umount(struct super_block *, struct cifs_sb_info *); 108extern int cifs_umount(struct super_block *, struct cifs_sb_info *);
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 7f0651b69573..cd9e9a145e4d 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -664,8 +664,9 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
664 rc = -EIO; 664 rc = -EIO;
665 goto neg_err_exit; 665 goto neg_err_exit;
666 } 666 }
667 667 read_lock(&cifs_tcp_ses_lock);
668 if (server->socketUseCount.counter > 1) { 668 if (server->srv_count > 1) {
669 read_unlock(&cifs_tcp_ses_lock);
669 if (memcmp(server->server_GUID, 670 if (memcmp(server->server_GUID,
670 pSMBr->u.extended_response. 671 pSMBr->u.extended_response.
671 GUID, 16) != 0) { 672 GUID, 16) != 0) {
@@ -674,9 +675,11 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
674 pSMBr->u.extended_response.GUID, 675 pSMBr->u.extended_response.GUID,
675 16); 676 16);
676 } 677 }
677 } else 678 } else {
679 read_unlock(&cifs_tcp_ses_lock);
678 memcpy(server->server_GUID, 680 memcpy(server->server_GUID,
679 pSMBr->u.extended_response.GUID, 16); 681 pSMBr->u.extended_response.GUID, 16);
682 }
680 683
681 if (count == 16) { 684 if (count == 16) {
682 server->secType = RawNTLMSSP; 685 server->secType = RawNTLMSSP;
@@ -830,12 +833,9 @@ CIFSSMBLogoff(const int xid, struct cifsSesInfo *ses)
830 pSMB->AndXCommand = 0xFF; 833 pSMB->AndXCommand = 0xFF;
831 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); 834 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0);
832session_already_dead: 835session_already_dead:
833 atomic_dec(&ses->server->socketUseCount); 836 if (ses->server) {
834 if (atomic_read(&ses->server->socketUseCount) == 0) { 837 cifs_put_tcp_session(ses->server);
835 spin_lock(&GlobalMid_Lock); 838 rc = 0;
836 ses->server->tcpStatus = CifsExiting;
837 spin_unlock(&GlobalMid_Lock);
838 rc = -ESHUTDOWN;
839 } 839 }
840 up(&ses->sesSem); 840 up(&ses->sesSem);
841 841
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 }