aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorJeff Layton <jlayton@redhat.com>2008-11-15 11:12:47 -0500
committerSteve French <sfrench@us.ibm.com>2008-11-16 22:14:12 -0500
commitf1987b44f642e96176adc88b7ce23a1d74806f89 (patch)
treefceaebf6b6d7eb1d1150120c44a842cbce8347f6 /fs/cifs/connect.c
parentd82c2df54e2f7e447476350848d8eccc8d2fe46a (diff)
cifs: reinstate sharing of tree connections
Use a similar approach to the SMB session sharing. Add a list of tcons attached to each SMB session. Move the refcount to non-atomic. Protect all of the above with the cifs_tcp_ses_lock. Add functions to properly find and put references to the tcons. Signed-off-by: Jeff Layton <jlayton@redhat.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c93
1 files changed, 62 insertions, 31 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index a3dc0d7cafc3..2f2be8faabb3 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -124,7 +124,7 @@ static int
124cifs_reconnect(struct TCP_Server_Info *server) 124cifs_reconnect(struct TCP_Server_Info *server)
125{ 125{
126 int rc = 0; 126 int rc = 0;
127 struct list_head *tmp; 127 struct list_head *tmp, *tmp2;
128 struct cifsSesInfo *ses; 128 struct cifsSesInfo *ses;
129 struct cifsTconInfo *tcon; 129 struct cifsTconInfo *tcon;
130 struct mid_q_entry *mid_entry; 130 struct mid_q_entry *mid_entry;
@@ -149,13 +149,12 @@ cifs_reconnect(struct TCP_Server_Info *server)
149 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 149 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
150 ses->need_reconnect = true; 150 ses->need_reconnect = true;
151 ses->ipc_tid = 0; 151 ses->ipc_tid = 0;
152 } 152 list_for_each(tmp2, &ses->tcon_list) {
153 read_unlock(&cifs_tcp_ses_lock); 153 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
154 list_for_each(tmp, &GlobalTreeConnectionList) {
155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
156 if ((tcon->ses) && (tcon->ses->server == server))
157 tcon->need_reconnect = true; 154 tcon->need_reconnect = true;
155 }
158 } 156 }
157 read_unlock(&cifs_tcp_ses_lock);
159 /* do not want to be sending data on a socket we are freeing */ 158 /* do not want to be sending data on a socket we are freeing */
160 down(&server->tcpSem); 159 down(&server->tcpSem);
161 if (server->ssocket) { 160 if (server->ssocket) {
@@ -1462,6 +1461,52 @@ cifs_put_smb_ses(struct cifsSesInfo *ses)
1462 cifs_put_tcp_session(server); 1461 cifs_put_tcp_session(server);
1463} 1462}
1464 1463
1464static struct cifsTconInfo *
1465cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1466{
1467 struct list_head *tmp;
1468 struct cifsTconInfo *tcon;
1469
1470 write_lock(&cifs_tcp_ses_lock);
1471 list_for_each(tmp, &ses->tcon_list) {
1472 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1473 if (tcon->tidStatus == CifsExiting)
1474 continue;
1475 if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE))
1476 continue;
1477
1478 ++tcon->tc_count;
1479 write_unlock(&cifs_tcp_ses_lock);
1480 return tcon;
1481 }
1482 write_unlock(&cifs_tcp_ses_lock);
1483 return NULL;
1484}
1485
1486static void
1487cifs_put_tcon(struct cifsTconInfo *tcon)
1488{
1489 int xid;
1490 struct cifsSesInfo *ses = tcon->ses;
1491
1492 write_lock(&cifs_tcp_ses_lock);
1493 if (--tcon->tc_count > 0) {
1494 write_unlock(&cifs_tcp_ses_lock);
1495 return;
1496 }
1497
1498 list_del_init(&tcon->tcon_list);
1499 write_unlock(&cifs_tcp_ses_lock);
1500
1501 xid = GetXid();
1502 CIFSSMBTDis(xid, tcon);
1503 _FreeXid(xid);
1504
1505 DeleteTconOplockQEntries(tcon);
1506 tconInfoFree(tcon);
1507 cifs_put_smb_ses(ses);
1508}
1509
1465int 1510int
1466get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1511get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1467 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 1512 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -2220,11 +2265,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2220 if (!rc) { 2265 if (!rc) {
2221 setup_cifs_sb(&volume_info, cifs_sb); 2266 setup_cifs_sb(&volume_info, cifs_sb);
2222 2267
2268 tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
2223 if (tcon) { 2269 if (tcon) {
2224 cFYI(1, ("Found match on UNC path")); 2270 cFYI(1, ("Found match on UNC path"));
2225 if (tcon->seal != volume_info.seal) 2271 /* existing tcon already has a reference */
2226 cERROR(1, ("transport encryption setting " 2272 cifs_put_smb_ses(pSesInfo);
2227 "conflicts with existing tid"));
2228 } else { 2273 } else {
2229 tcon = tconInfoAlloc(); 2274 tcon = tconInfoAlloc();
2230 if (tcon == NULL) { 2275 if (tcon == NULL) {
@@ -2257,6 +2302,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2257 if (rc) 2302 if (rc)
2258 goto mount_fail_check; 2303 goto mount_fail_check;
2259 tcon->seal = volume_info.seal; 2304 tcon->seal = volume_info.seal;
2305 tcon->ses = pSesInfo;
2306 write_lock(&cifs_tcp_ses_lock);
2307 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2308 write_unlock(&cifs_tcp_ses_lock);
2260 } 2309 }
2261 2310
2262 /* we can have only one retry value for a connection 2311 /* we can have only one retry value for a connection
@@ -2283,18 +2332,14 @@ mount_fail_check:
2283 /* If find_unc succeeded then rc == 0 so we can not end */ 2332 /* If find_unc succeeded then rc == 0 so we can not end */
2284 /* up accidently freeing someone elses tcon struct */ 2333 /* up accidently freeing someone elses tcon struct */
2285 if (tcon) 2334 if (tcon)
2286 tconInfoFree(tcon); 2335 cifs_put_tcon(tcon);
2287 2336 else if (pSesInfo)
2288 /* should also end up putting our tcp session ref if needed */
2289 if (pSesInfo)
2290 cifs_put_smb_ses(pSesInfo); 2337 cifs_put_smb_ses(pSesInfo);
2291 else 2338 else
2292 cifs_put_tcp_session(srvTcp); 2339 cifs_put_tcp_session(srvTcp);
2293 goto out; 2340 goto out;
2294 } 2341 }
2295 atomic_inc(&tcon->useCount);
2296 cifs_sb->tcon = tcon; 2342 cifs_sb->tcon = tcon;
2297 tcon->ses = pSesInfo;
2298 2343
2299 /* do not care if following two calls succeed - informational */ 2344 /* do not care if following two calls succeed - informational */
2300 if (!tcon->ipc) { 2345 if (!tcon->ipc) {
@@ -3565,23 +3610,10 @@ int
3565cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3610cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3566{ 3611{
3567 int rc = 0; 3612 int rc = 0;
3568 int xid;
3569 struct cifsSesInfo *ses = NULL;
3570 char *tmp; 3613 char *tmp;
3571 3614
3572 xid = GetXid(); 3615 if (cifs_sb->tcon)
3573 3616 cifs_put_tcon(cifs_sb->tcon);
3574 if (cifs_sb->tcon) {
3575 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3576 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3577 if (rc == -EBUSY) {
3578 FreeXid(xid);
3579 return 0;
3580 }
3581 DeleteTconOplockQEntries(cifs_sb->tcon);
3582 tconInfoFree(cifs_sb->tcon);
3583 cifs_put_smb_ses(ses);
3584 }
3585 3617
3586 cifs_sb->tcon = NULL; 3618 cifs_sb->tcon = NULL;
3587 tmp = cifs_sb->prepath; 3619 tmp = cifs_sb->prepath;
@@ -3589,7 +3621,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3589 cifs_sb->prepath = NULL; 3621 cifs_sb->prepath = NULL;
3590 kfree(tmp); 3622 kfree(tmp);
3591 3623
3592 FreeXid(xid);
3593 return rc; 3624 return rc;
3594} 3625}
3595 3626