diff options
author | Jeff Layton <jlayton@redhat.com> | 2008-11-15 11:12:47 -0500 |
---|---|---|
committer | Steve French <sfrench@us.ibm.com> | 2008-11-16 22:14:12 -0500 |
commit | f1987b44f642e96176adc88b7ce23a1d74806f89 (patch) | |
tree | fceaebf6b6d7eb1d1150120c44a842cbce8347f6 /fs/cifs/connect.c | |
parent | d82c2df54e2f7e447476350848d8eccc8d2fe46a (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.c | 93 |
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 | |||
124 | cifs_reconnect(struct TCP_Server_Info *server) | 124 | cifs_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 | ||
1464 | static struct cifsTconInfo * | ||
1465 | cifs_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 | |||
1486 | static void | ||
1487 | cifs_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 | |||
1465 | int | 1510 | int |
1466 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1511 | get_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 | |||
3565 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3610 | cifs_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 | ||