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.c226
1 files changed, 125 insertions, 101 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a0314259f94d..44130e052e0b 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -144,23 +144,18 @@ cifs_reconnect(struct TCP_Server_Info *server)
144 144
145 /* before reconnecting the tcp session, mark the smb session (uid) 145 /* before reconnecting the tcp session, mark the smb session (uid)
146 and the tid bad so they are not used until reconnected */ 146 and the tid bad so they are not used until reconnected */
147 read_lock(&GlobalSMBSeslock); 147 read_lock(&cifs_tcp_ses_lock);
148 list_for_each(tmp, &GlobalSMBSessionList) { 148 list_for_each(tmp, &server->smb_ses_list) {
149 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 149 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
150 if (ses->server) { 150 ses->need_reconnect = true;
151 if (ses->server == server) { 151 ses->ipc_tid = 0;
152 ses->need_reconnect = true;
153 ses->ipc_tid = 0;
154 }
155 }
156 /* else tcp and smb sessions need reconnection */
157 } 152 }
153 read_unlock(&cifs_tcp_ses_lock);
158 list_for_each(tmp, &GlobalTreeConnectionList) { 154 list_for_each(tmp, &GlobalTreeConnectionList) {
159 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
160 if ((tcon->ses) && (tcon->ses->server == server)) 156 if ((tcon->ses) && (tcon->ses->server == server))
161 tcon->need_reconnect = true; 157 tcon->need_reconnect = true;
162 } 158 }
163 read_unlock(&GlobalSMBSeslock);
164 /* do not want to be sending data on a socket we are freeing */ 159 /* do not want to be sending data on a socket we are freeing */
165 down(&server->tcpSem); 160 down(&server->tcpSem);
166 if (server->ssocket) { 161 if (server->ssocket) {
@@ -696,29 +691,29 @@ multi_t2_fnd:
696 if (smallbuf) /* no sense logging a debug message if NULL */ 691 if (smallbuf) /* no sense logging a debug message if NULL */
697 cifs_small_buf_release(smallbuf); 692 cifs_small_buf_release(smallbuf);
698 693
699 read_lock(&GlobalSMBSeslock); 694 /*
695 * BB: we shouldn't have to do any of this. It shouldn't be
696 * possible to exit from the thread with active SMB sessions
697 */
698 read_lock(&cifs_tcp_ses_lock);
700 if (list_empty(&server->pending_mid_q)) { 699 if (list_empty(&server->pending_mid_q)) {
701 /* loop through server session structures attached to this and 700 /* loop through server session structures attached to this and
702 mark them dead */ 701 mark them dead */
703 list_for_each(tmp, &GlobalSMBSessionList) { 702 list_for_each(tmp, &server->smb_ses_list) {
704 ses = 703 ses = list_entry(tmp, struct cifsSesInfo,
705 list_entry(tmp, struct cifsSesInfo, 704 smb_ses_list);
706 cifsSessionList); 705 ses->status = CifsExiting;
707 if (ses->server == server) { 706 ses->server = NULL;
708 ses->status = CifsExiting;
709 ses->server = NULL;
710 }
711 } 707 }
712 read_unlock(&GlobalSMBSeslock); 708 read_unlock(&cifs_tcp_ses_lock);
713 } else { 709 } else {
714 /* although we can not zero the server struct pointer yet, 710 /* although we can not zero the server struct pointer yet,
715 since there are active requests which may depnd on them, 711 since there are active requests which may depnd on them,
716 mark the corresponding SMB sessions as exiting too */ 712 mark the corresponding SMB sessions as exiting too */
717 list_for_each(tmp, &GlobalSMBSessionList) { 713 list_for_each(tmp, &server->smb_ses_list) {
718 ses = list_entry(tmp, struct cifsSesInfo, 714 ses = list_entry(tmp, struct cifsSesInfo,
719 cifsSessionList); 715 smb_ses_list);
720 if (ses->server == server) 716 ses->status = CifsExiting;
721 ses->status = CifsExiting;
722 } 717 }
723 718
724 spin_lock(&GlobalMid_Lock); 719 spin_lock(&GlobalMid_Lock);
@@ -733,7 +728,7 @@ multi_t2_fnd:
733 } 728 }
734 } 729 }
735 spin_unlock(&GlobalMid_Lock); 730 spin_unlock(&GlobalMid_Lock);
736 read_unlock(&GlobalSMBSeslock); 731 read_unlock(&cifs_tcp_ses_lock);
737 /* 1/8th of sec is more than enough time for them to exit */ 732 /* 1/8th of sec is more than enough time for them to exit */
738 msleep(125); 733 msleep(125);
739 } 734 }
@@ -755,14 +750,13 @@ multi_t2_fnd:
755 if there are any pointing to this (e.g 750 if there are any pointing to this (e.g
756 if a crazy root user tried to kill cifsd 751 if a crazy root user tried to kill cifsd
757 kernel thread explicitly this might happen) */ 752 kernel thread explicitly this might happen) */
758 write_lock(&GlobalSMBSeslock); 753 /* BB: This shouldn't be necessary, see above */
759 list_for_each(tmp, &GlobalSMBSessionList) { 754 read_lock(&cifs_tcp_ses_lock);
760 ses = list_entry(tmp, struct cifsSesInfo, 755 list_for_each(tmp, &server->smb_ses_list) {
761 cifsSessionList); 756 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
762 if (ses->server == server) 757 ses->server = NULL;
763 ses->server = NULL;
764 } 758 }
765 write_unlock(&GlobalSMBSeslock); 759 read_unlock(&cifs_tcp_ses_lock);
766 760
767 kfree(server->hostname); 761 kfree(server->hostname);
768 task_to_wake = xchg(&server->tsk, NULL); 762 task_to_wake = xchg(&server->tsk, NULL);
@@ -1401,7 +1395,7 @@ cifs_find_tcp_session(struct sockaddr *addr)
1401 return NULL; 1395 return NULL;
1402} 1396}
1403 1397
1404void 1398static void
1405cifs_put_tcp_session(struct TCP_Server_Info *server) 1399cifs_put_tcp_session(struct TCP_Server_Info *server)
1406{ 1400{
1407 struct task_struct *task; 1401 struct task_struct *task;
@@ -1424,6 +1418,50 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
1424 force_sig(SIGKILL, task); 1418 force_sig(SIGKILL, task);
1425} 1419}
1426 1420
1421static struct cifsSesInfo *
1422cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1423{
1424 struct list_head *tmp;
1425 struct cifsSesInfo *ses;
1426
1427 write_lock(&cifs_tcp_ses_lock);
1428 list_for_each(tmp, &server->smb_ses_list) {
1429 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1430 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1431 continue;
1432
1433 ++ses->ses_count;
1434 write_unlock(&cifs_tcp_ses_lock);
1435 return ses;
1436 }
1437 write_unlock(&cifs_tcp_ses_lock);
1438 return NULL;
1439}
1440
1441static void
1442cifs_put_smb_ses(struct cifsSesInfo *ses)
1443{
1444 int xid;
1445 struct TCP_Server_Info *server = ses->server;
1446
1447 write_lock(&cifs_tcp_ses_lock);
1448 if (--ses->ses_count > 0) {
1449 write_unlock(&cifs_tcp_ses_lock);
1450 return;
1451 }
1452
1453 list_del_init(&ses->smb_ses_list);
1454 write_unlock(&cifs_tcp_ses_lock);
1455
1456 if (ses->status == CifsGood) {
1457 xid = GetXid();
1458 CIFSSMBLogoff(xid, ses);
1459 _FreeXid(xid);
1460 }
1461 sesInfoFree(ses);
1462 cifs_put_tcp_session(server);
1463}
1464
1427int 1465int
1428get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1466get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1429 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 1467 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -1958,7 +1996,6 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1958 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; 1996 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1959 struct smb_vol volume_info; 1997 struct smb_vol volume_info;
1960 struct cifsSesInfo *pSesInfo = NULL; 1998 struct cifsSesInfo *pSesInfo = NULL;
1961 struct cifsSesInfo *existingCifsSes = NULL;
1962 struct cifsTconInfo *tcon = NULL; 1999 struct cifsTconInfo *tcon = NULL;
1963 struct TCP_Server_Info *srvTcp = NULL; 2000 struct TCP_Server_Info *srvTcp = NULL;
1964 2001
@@ -2112,6 +2149,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2112 volume_info.target_rfc1001_name, 16); 2149 volume_info.target_rfc1001_name, 16);
2113 srvTcp->sequence_number = 0; 2150 srvTcp->sequence_number = 0;
2114 INIT_LIST_HEAD(&srvTcp->tcp_ses_list); 2151 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
2152 INIT_LIST_HEAD(&srvTcp->smb_ses_list);
2115 ++srvTcp->srv_count; 2153 ++srvTcp->srv_count;
2116 write_lock(&cifs_tcp_ses_lock); 2154 write_lock(&cifs_tcp_ses_lock);
2117 list_add(&srvTcp->tcp_ses_list, 2155 list_add(&srvTcp->tcp_ses_list,
@@ -2120,10 +2158,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2120 } 2158 }
2121 } 2159 }
2122 2160
2123 if (existingCifsSes) { 2161 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
2124 pSesInfo = existingCifsSes; 2162 if (pSesInfo) {
2125 cFYI(1, ("Existing smb sess found (status=%d)", 2163 cFYI(1, ("Existing smb sess found (status=%d)",
2126 pSesInfo->status)); 2164 pSesInfo->status));
2165 /*
2166 * The existing SMB session already has a reference to srvTcp,
2167 * so we can put back the extra one we got before
2168 */
2169 cifs_put_tcp_session(srvTcp);
2170
2127 down(&pSesInfo->sesSem); 2171 down(&pSesInfo->sesSem);
2128 if (pSesInfo->need_reconnect) { 2172 if (pSesInfo->need_reconnect) {
2129 cFYI(1, ("Session needs reconnect")); 2173 cFYI(1, ("Session needs reconnect"));
@@ -2134,41 +2178,44 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2134 } else if (!rc) { 2178 } else if (!rc) {
2135 cFYI(1, ("Existing smb sess not found")); 2179 cFYI(1, ("Existing smb sess not found"));
2136 pSesInfo = sesInfoAlloc(); 2180 pSesInfo = sesInfoAlloc();
2137 if (pSesInfo == NULL) 2181 if (pSesInfo == NULL) {
2138 rc = -ENOMEM; 2182 rc = -ENOMEM;
2139 else { 2183 goto mount_fail_check;
2140 pSesInfo->server = srvTcp;
2141 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2142 NIPQUAD(sin_server->sin_addr.s_addr));
2143 } 2184 }
2144 2185
2145 if (!rc) { 2186 /* new SMB session uses our srvTcp ref */
2146 /* volume_info.password freed at unmount */ 2187 pSesInfo->server = srvTcp;
2147 if (volume_info.password) { 2188 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2148 pSesInfo->password = volume_info.password; 2189 NIPQUAD(sin_server->sin_addr.s_addr));
2149 /* set to NULL to prevent freeing on exit */ 2190
2150 volume_info.password = NULL; 2191 write_lock(&cifs_tcp_ses_lock);
2151 } 2192 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2152 if (volume_info.username) 2193 write_unlock(&cifs_tcp_ses_lock);
2153 strncpy(pSesInfo->userName, 2194
2154 volume_info.username, 2195 /* volume_info.password freed at unmount */
2155 MAX_USERNAME_SIZE); 2196 if (volume_info.password) {
2156 if (volume_info.domainname) { 2197 pSesInfo->password = volume_info.password;
2157 int len = strlen(volume_info.domainname); 2198 /* set to NULL to prevent freeing on exit */
2158 pSesInfo->domainName = 2199 volume_info.password = NULL;
2159 kmalloc(len + 1, GFP_KERNEL); 2200 }
2160 if (pSesInfo->domainName) 2201 if (volume_info.username)
2161 strcpy(pSesInfo->domainName, 2202 strncpy(pSesInfo->userName, volume_info.username,
2162 volume_info.domainname); 2203 MAX_USERNAME_SIZE);
2163 } 2204 if (volume_info.domainname) {
2164 pSesInfo->linux_uid = volume_info.linux_uid; 2205 int len = strlen(volume_info.domainname);
2165 pSesInfo->overrideSecFlg = volume_info.secFlg; 2206 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2166 down(&pSesInfo->sesSem); 2207 if (pSesInfo->domainName)
2167 /* BB FIXME need to pass vol->secFlgs BB */ 2208 strcpy(pSesInfo->domainName,
2168 rc = cifs_setup_session(xid, pSesInfo, 2209 volume_info.domainname);
2169 cifs_sb->local_nls); 2210 }
2170 up(&pSesInfo->sesSem); 2211 pSesInfo->linux_uid = volume_info.linux_uid;
2171 } 2212 pSesInfo->overrideSecFlg = volume_info.secFlg;
2213 down(&pSesInfo->sesSem);
2214
2215 /* BB FIXME need to pass vol->secFlgs BB */
2216 rc = cifs_setup_session(xid, pSesInfo,
2217 cifs_sb->local_nls);
2218 up(&pSesInfo->sesSem);
2172 } 2219 }
2173 2220
2174 /* search for existing tcon to this server share */ 2221 /* search for existing tcon to this server share */
@@ -2209,11 +2256,9 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2209 tcon->Flags)); 2256 tcon->Flags));
2210 } 2257 }
2211 } 2258 }
2212 if (!rc) { 2259 if (rc)
2213 atomic_inc(&pSesInfo->inUse);
2214 tcon->seal = volume_info.seal;
2215 } else
2216 goto mount_fail_check; 2260 goto mount_fail_check;
2261 tcon->seal = volume_info.seal;
2217 } 2262 }
2218 2263
2219 /* we can have only one retry value for a connection 2264 /* we can have only one retry value for a connection
@@ -2234,29 +2279,19 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2234 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2279 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
2235 sb->s_time_gran = 100; 2280 sb->s_time_gran = 100;
2236 2281
2237/* on error free sesinfo and tcon struct if needed */
2238mount_fail_check: 2282mount_fail_check:
2283 /* on error free sesinfo and tcon struct if needed */
2239 if (rc) { 2284 if (rc) {
2240 /* If find_unc succeeded then rc == 0 so we can not end */ 2285 /* If find_unc succeeded then rc == 0 so we can not end */
2241 /* up accidently freeing someone elses tcon struct */ 2286 /* up accidently freeing someone elses tcon struct */
2242 if (tcon) 2287 if (tcon)
2243 tconInfoFree(tcon); 2288 tconInfoFree(tcon);
2244 2289
2245 if (existingCifsSes == NULL) { 2290 /* should also end up putting our tcp session ref if needed */
2246 if (pSesInfo) { 2291 if (pSesInfo)
2247 if ((pSesInfo->server) && 2292 cifs_put_smb_ses(pSesInfo);
2248 (pSesInfo->status == CifsGood)) 2293 else
2249 CIFSSMBLogoff(xid, pSesInfo); 2294 cifs_put_tcp_session(srvTcp);
2250 else {
2251 cFYI(1, ("No session or bad tcon"));
2252 if (pSesInfo->server)
2253 cifs_put_tcp_session(
2254 pSesInfo->server);
2255 }
2256 sesInfoFree(pSesInfo);
2257 /* pSesInfo = NULL; */
2258 }
2259 }
2260 } else { 2295 } else {
2261 atomic_inc(&tcon->useCount); 2296 atomic_inc(&tcon->useCount);
2262 cifs_sb->tcon = tcon; 2297 cifs_sb->tcon = tcon;
@@ -3551,16 +3586,7 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3551 } 3586 }
3552 DeleteTconOplockQEntries(cifs_sb->tcon); 3587 DeleteTconOplockQEntries(cifs_sb->tcon);
3553 tconInfoFree(cifs_sb->tcon); 3588 tconInfoFree(cifs_sb->tcon);
3554 if ((ses) && (ses->server)) { 3589 cifs_put_smb_ses(ses);
3555 /* save off task so we do not refer to ses later */
3556 cFYI(1, ("About to do SMBLogoff "));
3557 rc = CIFSSMBLogoff(xid, ses);
3558 if (rc == -EBUSY) {
3559 FreeXid(xid);
3560 return 0;
3561 }
3562 } else
3563 cFYI(1, ("No session or bad tcon"));
3564 } 3590 }
3565 3591
3566 cifs_sb->tcon = NULL; 3592 cifs_sb->tcon = NULL;
@@ -3568,8 +3594,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3568 cifs_sb->prepathlen = 0; 3594 cifs_sb->prepathlen = 0;
3569 cifs_sb->prepath = NULL; 3595 cifs_sb->prepath = NULL;
3570 kfree(tmp); 3596 kfree(tmp);
3571 if (ses)
3572 sesInfoFree(ses);
3573 3597
3574 FreeXid(xid); 3598 FreeXid(xid);
3575 return rc; 3599 return rc;