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.c534
1 files changed, 478 insertions, 56 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 88c84a38bccb..7e73176acb58 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -47,7 +47,6 @@
47#include "ntlmssp.h" 47#include "ntlmssp.h"
48#include "nterr.h" 48#include "nterr.h"
49#include "rfc1002pdu.h" 49#include "rfc1002pdu.h"
50#include "cn_cifs.h"
51#include "fscache.h" 50#include "fscache.h"
52 51
53#define CIFS_PORT 445 52#define CIFS_PORT 445
@@ -100,16 +99,24 @@ struct smb_vol {
100 bool noautotune:1; 99 bool noautotune:1;
101 bool nostrictsync:1; /* do not force expensive SMBflush on every sync */ 100 bool nostrictsync:1; /* do not force expensive SMBflush on every sync */
102 bool fsc:1; /* enable fscache */ 101 bool fsc:1; /* enable fscache */
102 bool mfsymlinks:1; /* use Minshall+French Symlinks */
103 bool multiuser:1;
103 unsigned int rsize; 104 unsigned int rsize;
104 unsigned int wsize; 105 unsigned int wsize;
105 bool sockopt_tcp_nodelay:1; 106 bool sockopt_tcp_nodelay:1;
106 unsigned short int port; 107 unsigned short int port;
107 char *prepath; 108 char *prepath;
109 struct sockaddr_storage srcaddr; /* allow binding to a local IP */
108 struct nls_table *local_nls; 110 struct nls_table *local_nls;
109}; 111};
110 112
113/* FIXME: should these be tunable? */
114#define TLINK_ERROR_EXPIRE (1 * HZ)
115#define TLINK_IDLE_EXPIRE (600 * HZ)
116
111static int ipv4_connect(struct TCP_Server_Info *server); 117static int ipv4_connect(struct TCP_Server_Info *server);
112static int ipv6_connect(struct TCP_Server_Info *server); 118static int ipv6_connect(struct TCP_Server_Info *server);
119static void cifs_prune_tlinks(struct work_struct *work);
113 120
114/* 121/*
115 * cifs tcp session reconnection 122 * cifs tcp session reconnection
@@ -143,7 +150,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
143 150
144 /* before reconnecting the tcp session, mark the smb session (uid) 151 /* before reconnecting the tcp session, mark the smb session (uid)
145 and the tid bad so they are not used until reconnected */ 152 and the tid bad so they are not used until reconnected */
146 read_lock(&cifs_tcp_ses_lock); 153 spin_lock(&cifs_tcp_ses_lock);
147 list_for_each(tmp, &server->smb_ses_list) { 154 list_for_each(tmp, &server->smb_ses_list) {
148 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 155 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
149 ses->need_reconnect = true; 156 ses->need_reconnect = true;
@@ -153,7 +160,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
153 tcon->need_reconnect = true; 160 tcon->need_reconnect = true;
154 } 161 }
155 } 162 }
156 read_unlock(&cifs_tcp_ses_lock); 163 spin_unlock(&cifs_tcp_ses_lock);
157 /* do not want to be sending data on a socket we are freeing */ 164 /* do not want to be sending data on a socket we are freeing */
158 mutex_lock(&server->srv_mutex); 165 mutex_lock(&server->srv_mutex);
159 if (server->ssocket) { 166 if (server->ssocket) {
@@ -166,6 +173,8 @@ cifs_reconnect(struct TCP_Server_Info *server)
166 sock_release(server->ssocket); 173 sock_release(server->ssocket);
167 server->ssocket = NULL; 174 server->ssocket = NULL;
168 } 175 }
176 server->sequence_number = 0;
177 server->session_estab = false;
169 178
170 spin_lock(&GlobalMid_Lock); 179 spin_lock(&GlobalMid_Lock);
171 list_for_each(tmp, &server->pending_mid_q) { 180 list_for_each(tmp, &server->pending_mid_q) {
@@ -198,7 +207,6 @@ cifs_reconnect(struct TCP_Server_Info *server)
198 spin_lock(&GlobalMid_Lock); 207 spin_lock(&GlobalMid_Lock);
199 if (server->tcpStatus != CifsExiting) 208 if (server->tcpStatus != CifsExiting)
200 server->tcpStatus = CifsGood; 209 server->tcpStatus = CifsGood;
201 server->sequence_number = 0;
202 spin_unlock(&GlobalMid_Lock); 210 spin_unlock(&GlobalMid_Lock);
203 /* atomic_set(&server->inFlight,0);*/ 211 /* atomic_set(&server->inFlight,0);*/
204 wake_up(&server->response_q); 212 wake_up(&server->response_q);
@@ -629,9 +637,9 @@ multi_t2_fnd:
629 } /* end while !EXITING */ 637 } /* end while !EXITING */
630 638
631 /* take it off the list, if it's not already */ 639 /* take it off the list, if it's not already */
632 write_lock(&cifs_tcp_ses_lock); 640 spin_lock(&cifs_tcp_ses_lock);
633 list_del_init(&server->tcp_ses_list); 641 list_del_init(&server->tcp_ses_list);
634 write_unlock(&cifs_tcp_ses_lock); 642 spin_unlock(&cifs_tcp_ses_lock);
635 643
636 spin_lock(&GlobalMid_Lock); 644 spin_lock(&GlobalMid_Lock);
637 server->tcpStatus = CifsExiting; 645 server->tcpStatus = CifsExiting;
@@ -669,7 +677,7 @@ multi_t2_fnd:
669 * BB: we shouldn't have to do any of this. It shouldn't be 677 * BB: we shouldn't have to do any of this. It shouldn't be
670 * possible to exit from the thread with active SMB sessions 678 * possible to exit from the thread with active SMB sessions
671 */ 679 */
672 read_lock(&cifs_tcp_ses_lock); 680 spin_lock(&cifs_tcp_ses_lock);
673 if (list_empty(&server->pending_mid_q)) { 681 if (list_empty(&server->pending_mid_q)) {
674 /* loop through server session structures attached to this and 682 /* loop through server session structures attached to this and
675 mark them dead */ 683 mark them dead */
@@ -679,7 +687,7 @@ multi_t2_fnd:
679 ses->status = CifsExiting; 687 ses->status = CifsExiting;
680 ses->server = NULL; 688 ses->server = NULL;
681 } 689 }
682 read_unlock(&cifs_tcp_ses_lock); 690 spin_unlock(&cifs_tcp_ses_lock);
683 } else { 691 } else {
684 /* although we can not zero the server struct pointer yet, 692 /* although we can not zero the server struct pointer yet,
685 since there are active requests which may depnd on them, 693 since there are active requests which may depnd on them,
@@ -702,7 +710,7 @@ multi_t2_fnd:
702 } 710 }
703 } 711 }
704 spin_unlock(&GlobalMid_Lock); 712 spin_unlock(&GlobalMid_Lock);
705 read_unlock(&cifs_tcp_ses_lock); 713 spin_unlock(&cifs_tcp_ses_lock);
706 /* 1/8th of sec is more than enough time for them to exit */ 714 /* 1/8th of sec is more than enough time for them to exit */
707 msleep(125); 715 msleep(125);
708 } 716 }
@@ -725,12 +733,12 @@ multi_t2_fnd:
725 if a crazy root user tried to kill cifsd 733 if a crazy root user tried to kill cifsd
726 kernel thread explicitly this might happen) */ 734 kernel thread explicitly this might happen) */
727 /* BB: This shouldn't be necessary, see above */ 735 /* BB: This shouldn't be necessary, see above */
728 read_lock(&cifs_tcp_ses_lock); 736 spin_lock(&cifs_tcp_ses_lock);
729 list_for_each(tmp, &server->smb_ses_list) { 737 list_for_each(tmp, &server->smb_ses_list) {
730 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 738 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
731 ses->server = NULL; 739 ses->server = NULL;
732 } 740 }
733 read_unlock(&cifs_tcp_ses_lock); 741 spin_unlock(&cifs_tcp_ses_lock);
734 742
735 kfree(server->hostname); 743 kfree(server->hostname);
736 task_to_wake = xchg(&server->tsk, NULL); 744 task_to_wake = xchg(&server->tsk, NULL);
@@ -1046,6 +1054,22 @@ cifs_parse_mount_options(char *options, const char *devname,
1046 "long\n"); 1054 "long\n");
1047 return 1; 1055 return 1;
1048 } 1056 }
1057 } else if (strnicmp(data, "srcaddr", 7) == 0) {
1058 vol->srcaddr.ss_family = AF_UNSPEC;
1059
1060 if (!value || !*value) {
1061 printk(KERN_WARNING "CIFS: srcaddr value"
1062 " not specified.\n");
1063 return 1; /* needs_arg; */
1064 }
1065 i = cifs_convert_address((struct sockaddr *)&vol->srcaddr,
1066 value, strlen(value));
1067 if (i < 0) {
1068 printk(KERN_WARNING "CIFS: Could not parse"
1069 " srcaddr: %s\n",
1070 value);
1071 return 1;
1072 }
1049 } else if (strnicmp(data, "prefixpath", 10) == 0) { 1073 } else if (strnicmp(data, "prefixpath", 10) == 0) {
1050 if (!value || !*value) { 1074 if (!value || !*value) {
1051 printk(KERN_WARNING 1075 printk(KERN_WARNING
@@ -1325,6 +1349,10 @@ cifs_parse_mount_options(char *options, const char *devname,
1325 "/proc/fs/cifs/LookupCacheEnabled to 0\n"); 1349 "/proc/fs/cifs/LookupCacheEnabled to 0\n");
1326 } else if (strnicmp(data, "fsc", 3) == 0) { 1350 } else if (strnicmp(data, "fsc", 3) == 0) {
1327 vol->fsc = true; 1351 vol->fsc = true;
1352 } else if (strnicmp(data, "mfsymlinks", 10) == 0) {
1353 vol->mfsymlinks = true;
1354 } else if (strnicmp(data, "multiuser", 8) == 0) {
1355 vol->multiuser = true;
1328 } else 1356 } else
1329 printk(KERN_WARNING "CIFS: Unknown mount option %s\n", 1357 printk(KERN_WARNING "CIFS: Unknown mount option %s\n",
1330 data); 1358 data);
@@ -1356,6 +1384,13 @@ cifs_parse_mount_options(char *options, const char *devname,
1356 return 1; 1384 return 1;
1357 } 1385 }
1358 } 1386 }
1387
1388 if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) {
1389 cERROR(1, "Multiuser mounts currently require krb5 "
1390 "authentication!");
1391 return 1;
1392 }
1393
1359 if (vol->UNCip == NULL) 1394 if (vol->UNCip == NULL)
1360 vol->UNCip = &vol->UNC[2]; 1395 vol->UNCip = &vol->UNC[2];
1361 1396
@@ -1374,8 +1409,36 @@ cifs_parse_mount_options(char *options, const char *devname,
1374 return 0; 1409 return 0;
1375} 1410}
1376 1411
1412/** Returns true if srcaddr isn't specified and rhs isn't
1413 * specified, or if srcaddr is specified and
1414 * matches the IP address of the rhs argument.
1415 */
1416static bool
1417srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs)
1418{
1419 switch (srcaddr->sa_family) {
1420 case AF_UNSPEC:
1421 return (rhs->sa_family == AF_UNSPEC);
1422 case AF_INET: {
1423 struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr;
1424 struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs;
1425 return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr);
1426 }
1427 case AF_INET6: {
1428 struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr;
1429 struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs;
1430 return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr);
1431 }
1432 default:
1433 WARN_ON(1);
1434 return false; /* don't expect to be here */
1435 }
1436}
1437
1438
1377static bool 1439static bool
1378match_address(struct TCP_Server_Info *server, struct sockaddr *addr) 1440match_address(struct TCP_Server_Info *server, struct sockaddr *addr,
1441 struct sockaddr *srcaddr)
1379{ 1442{
1380 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; 1443 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr;
1381 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; 1444 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
@@ -1402,6 +1465,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr)
1402 break; 1465 break;
1403 } 1466 }
1404 1467
1468 if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr))
1469 return false;
1470
1405 return true; 1471 return true;
1406} 1472}
1407 1473
@@ -1458,29 +1524,21 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol)
1458{ 1524{
1459 struct TCP_Server_Info *server; 1525 struct TCP_Server_Info *server;
1460 1526
1461 write_lock(&cifs_tcp_ses_lock); 1527 spin_lock(&cifs_tcp_ses_lock);
1462 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { 1528 list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) {
1463 /* 1529 if (!match_address(server, addr,
1464 * the demux thread can exit on its own while still in CifsNew 1530 (struct sockaddr *)&vol->srcaddr))
1465 * so don't accept any sockets in that state. Since the
1466 * tcpStatus never changes back to CifsNew it's safe to check
1467 * for this without a lock.
1468 */
1469 if (server->tcpStatus == CifsNew)
1470 continue;
1471
1472 if (!match_address(server, addr))
1473 continue; 1531 continue;
1474 1532
1475 if (!match_security(server, vol)) 1533 if (!match_security(server, vol))
1476 continue; 1534 continue;
1477 1535
1478 ++server->srv_count; 1536 ++server->srv_count;
1479 write_unlock(&cifs_tcp_ses_lock); 1537 spin_unlock(&cifs_tcp_ses_lock);
1480 cFYI(1, "Existing tcp session with server found"); 1538 cFYI(1, "Existing tcp session with server found");
1481 return server; 1539 return server;
1482 } 1540 }
1483 write_unlock(&cifs_tcp_ses_lock); 1541 spin_unlock(&cifs_tcp_ses_lock);
1484 return NULL; 1542 return NULL;
1485} 1543}
1486 1544
@@ -1489,14 +1547,14 @@ cifs_put_tcp_session(struct TCP_Server_Info *server)
1489{ 1547{
1490 struct task_struct *task; 1548 struct task_struct *task;
1491 1549
1492 write_lock(&cifs_tcp_ses_lock); 1550 spin_lock(&cifs_tcp_ses_lock);
1493 if (--server->srv_count > 0) { 1551 if (--server->srv_count > 0) {
1494 write_unlock(&cifs_tcp_ses_lock); 1552 spin_unlock(&cifs_tcp_ses_lock);
1495 return; 1553 return;
1496 } 1554 }
1497 1555
1498 list_del_init(&server->tcp_ses_list); 1556 list_del_init(&server->tcp_ses_list);
1499 write_unlock(&cifs_tcp_ses_lock); 1557 spin_unlock(&cifs_tcp_ses_lock);
1500 1558
1501 spin_lock(&GlobalMid_Lock); 1559 spin_lock(&GlobalMid_Lock);
1502 server->tcpStatus = CifsExiting; 1560 server->tcpStatus = CifsExiting;
@@ -1574,6 +1632,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1574 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); 1632 volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1575 memcpy(tcp_ses->server_RFC1001_name, 1633 memcpy(tcp_ses->server_RFC1001_name,
1576 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); 1634 volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL);
1635 tcp_ses->session_estab = false;
1577 tcp_ses->sequence_number = 0; 1636 tcp_ses->sequence_number = 0;
1578 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); 1637 INIT_LIST_HEAD(&tcp_ses->tcp_ses_list);
1579 INIT_LIST_HEAD(&tcp_ses->smb_ses_list); 1638 INIT_LIST_HEAD(&tcp_ses->smb_ses_list);
@@ -1584,6 +1643,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1584 * no need to spinlock this init of tcpStatus or srv_count 1643 * no need to spinlock this init of tcpStatus or srv_count
1585 */ 1644 */
1586 tcp_ses->tcpStatus = CifsNew; 1645 tcp_ses->tcpStatus = CifsNew;
1646 memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr,
1647 sizeof(tcp_ses->srcaddr));
1587 ++tcp_ses->srv_count; 1648 ++tcp_ses->srv_count;
1588 1649
1589 if (addr.ss_family == AF_INET6) { 1650 if (addr.ss_family == AF_INET6) {
@@ -1618,9 +1679,9 @@ cifs_get_tcp_session(struct smb_vol *volume_info)
1618 } 1679 }
1619 1680
1620 /* thread spawned, put it on the list */ 1681 /* thread spawned, put it on the list */
1621 write_lock(&cifs_tcp_ses_lock); 1682 spin_lock(&cifs_tcp_ses_lock);
1622 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); 1683 list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list);
1623 write_unlock(&cifs_tcp_ses_lock); 1684 spin_unlock(&cifs_tcp_ses_lock);
1624 1685
1625 cifs_fscache_get_client_cookie(tcp_ses); 1686 cifs_fscache_get_client_cookie(tcp_ses);
1626 1687
@@ -1642,7 +1703,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
1642{ 1703{
1643 struct cifsSesInfo *ses; 1704 struct cifsSesInfo *ses;
1644 1705
1645 write_lock(&cifs_tcp_ses_lock); 1706 spin_lock(&cifs_tcp_ses_lock);
1646 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { 1707 list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) {
1647 switch (server->secType) { 1708 switch (server->secType) {
1648 case Kerberos: 1709 case Kerberos:
@@ -1662,10 +1723,10 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol)
1662 continue; 1723 continue;
1663 } 1724 }
1664 ++ses->ses_count; 1725 ++ses->ses_count;
1665 write_unlock(&cifs_tcp_ses_lock); 1726 spin_unlock(&cifs_tcp_ses_lock);
1666 return ses; 1727 return ses;
1667 } 1728 }
1668 write_unlock(&cifs_tcp_ses_lock); 1729 spin_unlock(&cifs_tcp_ses_lock);
1669 return NULL; 1730 return NULL;
1670} 1731}
1671 1732
@@ -1676,14 +1737,14 @@ cifs_put_smb_ses(struct cifsSesInfo *ses)
1676 struct TCP_Server_Info *server = ses->server; 1737 struct TCP_Server_Info *server = ses->server;
1677 1738
1678 cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count); 1739 cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count);
1679 write_lock(&cifs_tcp_ses_lock); 1740 spin_lock(&cifs_tcp_ses_lock);
1680 if (--ses->ses_count > 0) { 1741 if (--ses->ses_count > 0) {
1681 write_unlock(&cifs_tcp_ses_lock); 1742 spin_unlock(&cifs_tcp_ses_lock);
1682 return; 1743 return;
1683 } 1744 }
1684 1745
1685 list_del_init(&ses->smb_ses_list); 1746 list_del_init(&ses->smb_ses_list);
1686 write_unlock(&cifs_tcp_ses_lock); 1747 spin_unlock(&cifs_tcp_ses_lock);
1687 1748
1688 if (ses->status == CifsGood) { 1749 if (ses->status == CifsGood) {
1689 xid = GetXid(); 1750 xid = GetXid();
@@ -1740,6 +1801,8 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1740 if (ses == NULL) 1801 if (ses == NULL)
1741 goto get_ses_fail; 1802 goto get_ses_fail;
1742 1803
1804 ses->tilen = 0;
1805 ses->tiblob = NULL;
1743 /* new SMB session uses our server ref */ 1806 /* new SMB session uses our server ref */
1744 ses->server = server; 1807 ses->server = server;
1745 if (server->addr.sockAddr6.sin6_family == AF_INET6) 1808 if (server->addr.sockAddr6.sin6_family == AF_INET6)
@@ -1778,9 +1841,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info)
1778 goto get_ses_fail; 1841 goto get_ses_fail;
1779 1842
1780 /* success, put it on the list */ 1843 /* success, put it on the list */
1781 write_lock(&cifs_tcp_ses_lock); 1844 spin_lock(&cifs_tcp_ses_lock);
1782 list_add(&ses->smb_ses_list, &server->smb_ses_list); 1845 list_add(&ses->smb_ses_list, &server->smb_ses_list);
1783 write_unlock(&cifs_tcp_ses_lock); 1846 spin_unlock(&cifs_tcp_ses_lock);
1784 1847
1785 FreeXid(xid); 1848 FreeXid(xid);
1786 return ses; 1849 return ses;
@@ -1797,7 +1860,7 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1797 struct list_head *tmp; 1860 struct list_head *tmp;
1798 struct cifsTconInfo *tcon; 1861 struct cifsTconInfo *tcon;
1799 1862
1800 write_lock(&cifs_tcp_ses_lock); 1863 spin_lock(&cifs_tcp_ses_lock);
1801 list_for_each(tmp, &ses->tcon_list) { 1864 list_for_each(tmp, &ses->tcon_list) {
1802 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); 1865 tcon = list_entry(tmp, struct cifsTconInfo, tcon_list);
1803 if (tcon->tidStatus == CifsExiting) 1866 if (tcon->tidStatus == CifsExiting)
@@ -1806,10 +1869,10 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1806 continue; 1869 continue;
1807 1870
1808 ++tcon->tc_count; 1871 ++tcon->tc_count;
1809 write_unlock(&cifs_tcp_ses_lock); 1872 spin_unlock(&cifs_tcp_ses_lock);
1810 return tcon; 1873 return tcon;
1811 } 1874 }
1812 write_unlock(&cifs_tcp_ses_lock); 1875 spin_unlock(&cifs_tcp_ses_lock);
1813 return NULL; 1876 return NULL;
1814} 1877}
1815 1878
@@ -1820,14 +1883,14 @@ cifs_put_tcon(struct cifsTconInfo *tcon)
1820 struct cifsSesInfo *ses = tcon->ses; 1883 struct cifsSesInfo *ses = tcon->ses;
1821 1884
1822 cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); 1885 cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count);
1823 write_lock(&cifs_tcp_ses_lock); 1886 spin_lock(&cifs_tcp_ses_lock);
1824 if (--tcon->tc_count > 0) { 1887 if (--tcon->tc_count > 0) {
1825 write_unlock(&cifs_tcp_ses_lock); 1888 spin_unlock(&cifs_tcp_ses_lock);
1826 return; 1889 return;
1827 } 1890 }
1828 1891
1829 list_del_init(&tcon->tcon_list); 1892 list_del_init(&tcon->tcon_list);
1830 write_unlock(&cifs_tcp_ses_lock); 1893 spin_unlock(&cifs_tcp_ses_lock);
1831 1894
1832 xid = GetXid(); 1895 xid = GetXid();
1833 CIFSSMBTDis(xid, tcon); 1896 CIFSSMBTDis(xid, tcon);
@@ -1900,9 +1963,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info)
1900 tcon->nocase = volume_info->nocase; 1963 tcon->nocase = volume_info->nocase;
1901 tcon->local_lease = volume_info->local_lease; 1964 tcon->local_lease = volume_info->local_lease;
1902 1965
1903 write_lock(&cifs_tcp_ses_lock); 1966 spin_lock(&cifs_tcp_ses_lock);
1904 list_add(&tcon->tcon_list, &ses->tcon_list); 1967 list_add(&tcon->tcon_list, &ses->tcon_list);
1905 write_unlock(&cifs_tcp_ses_lock); 1968 spin_unlock(&cifs_tcp_ses_lock);
1906 1969
1907 cifs_fscache_get_super_cookie(tcon); 1970 cifs_fscache_get_super_cookie(tcon);
1908 1971
@@ -1913,6 +1976,23 @@ out_fail:
1913 return ERR_PTR(rc); 1976 return ERR_PTR(rc);
1914} 1977}
1915 1978
1979void
1980cifs_put_tlink(struct tcon_link *tlink)
1981{
1982 if (!tlink || IS_ERR(tlink))
1983 return;
1984
1985 if (!atomic_dec_and_test(&tlink->tl_count) ||
1986 test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) {
1987 tlink->tl_time = jiffies;
1988 return;
1989 }
1990
1991 if (!IS_ERR(tlink_tcon(tlink)))
1992 cifs_put_tcon(tlink_tcon(tlink));
1993 kfree(tlink);
1994 return;
1995}
1916 1996
1917int 1997int
1918get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1998get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
@@ -1997,6 +2077,33 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
1997 2077
1998} 2078}
1999 2079
2080static int
2081bind_socket(struct TCP_Server_Info *server)
2082{
2083 int rc = 0;
2084 if (server->srcaddr.ss_family != AF_UNSPEC) {
2085 /* Bind to the specified local IP address */
2086 struct socket *socket = server->ssocket;
2087 rc = socket->ops->bind(socket,
2088 (struct sockaddr *) &server->srcaddr,
2089 sizeof(server->srcaddr));
2090 if (rc < 0) {
2091 struct sockaddr_in *saddr4;
2092 struct sockaddr_in6 *saddr6;
2093 saddr4 = (struct sockaddr_in *)&server->srcaddr;
2094 saddr6 = (struct sockaddr_in6 *)&server->srcaddr;
2095 if (saddr6->sin6_family == AF_INET6)
2096 cERROR(1, "cifs: "
2097 "Failed to bind to: %pI6c, error: %d\n",
2098 &saddr6->sin6_addr, rc);
2099 else
2100 cERROR(1, "cifs: "
2101 "Failed to bind to: %pI4, error: %d\n",
2102 &saddr4->sin_addr.s_addr, rc);
2103 }
2104 }
2105 return rc;
2106}
2000 2107
2001static int 2108static int
2002ipv4_connect(struct TCP_Server_Info *server) 2109ipv4_connect(struct TCP_Server_Info *server)
@@ -2022,6 +2129,10 @@ ipv4_connect(struct TCP_Server_Info *server)
2022 cifs_reclassify_socket4(socket); 2129 cifs_reclassify_socket4(socket);
2023 } 2130 }
2024 2131
2132 rc = bind_socket(server);
2133 if (rc < 0)
2134 return rc;
2135
2025 /* user overrode default port */ 2136 /* user overrode default port */
2026 if (server->addr.sockAddr.sin_port) { 2137 if (server->addr.sockAddr.sin_port) {
2027 rc = socket->ops->connect(socket, (struct sockaddr *) 2138 rc = socket->ops->connect(socket, (struct sockaddr *)
@@ -2184,6 +2295,10 @@ ipv6_connect(struct TCP_Server_Info *server)
2184 cifs_reclassify_socket6(socket); 2295 cifs_reclassify_socket6(socket);
2185 } 2296 }
2186 2297
2298 rc = bind_socket(server);
2299 if (rc < 0)
2300 return rc;
2301
2187 /* user overrode default port */ 2302 /* user overrode default port */
2188 if (server->addr.sockAddr6.sin6_port) { 2303 if (server->addr.sockAddr6.sin6_port) {
2189 rc = socket->ops->connect(socket, 2304 rc = socket->ops->connect(socket,
@@ -2383,6 +2498,8 @@ convert_delimiter(char *path, char delim)
2383static void setup_cifs_sb(struct smb_vol *pvolume_info, 2498static void setup_cifs_sb(struct smb_vol *pvolume_info,
2384 struct cifs_sb_info *cifs_sb) 2499 struct cifs_sb_info *cifs_sb)
2385{ 2500{
2501 INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks);
2502
2386 if (pvolume_info->rsize > CIFSMaxBufSize) { 2503 if (pvolume_info->rsize > CIFSMaxBufSize) {
2387 cERROR(1, "rsize %d too large, using MaxBufSize", 2504 cERROR(1, "rsize %d too large, using MaxBufSize",
2388 pvolume_info->rsize); 2505 pvolume_info->rsize);
@@ -2462,10 +2579,21 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
2462 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; 2579 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2463 if (pvolume_info->fsc) 2580 if (pvolume_info->fsc)
2464 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; 2581 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE;
2582 if (pvolume_info->multiuser)
2583 cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER |
2584 CIFS_MOUNT_NO_PERM);
2465 if (pvolume_info->direct_io) { 2585 if (pvolume_info->direct_io) {
2466 cFYI(1, "mounting share using direct i/o"); 2586 cFYI(1, "mounting share using direct i/o");
2467 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; 2587 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2468 } 2588 }
2589 if (pvolume_info->mfsymlinks) {
2590 if (pvolume_info->sfu_emul) {
2591 cERROR(1, "mount option mfsymlinks ignored if sfu "
2592 "mount option is used");
2593 } else {
2594 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS;
2595 }
2596 }
2469 2597
2470 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) 2598 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2471 cERROR(1, "mount option dynperm ignored if cifsacl " 2599 cERROR(1, "mount option dynperm ignored if cifsacl "
@@ -2552,6 +2680,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2552 struct TCP_Server_Info *srvTcp; 2680 struct TCP_Server_Info *srvTcp;
2553 char *full_path; 2681 char *full_path;
2554 char *mount_data = mount_data_global; 2682 char *mount_data = mount_data_global;
2683 struct tcon_link *tlink;
2555#ifdef CONFIG_CIFS_DFS_UPCALL 2684#ifdef CONFIG_CIFS_DFS_UPCALL
2556 struct dfs_info3_param *referrals = NULL; 2685 struct dfs_info3_param *referrals = NULL;
2557 unsigned int num_referrals = 0; 2686 unsigned int num_referrals = 0;
@@ -2563,6 +2692,7 @@ try_mount_again:
2563 pSesInfo = NULL; 2692 pSesInfo = NULL;
2564 srvTcp = NULL; 2693 srvTcp = NULL;
2565 full_path = NULL; 2694 full_path = NULL;
2695 tlink = NULL;
2566 2696
2567 xid = GetXid(); 2697 xid = GetXid();
2568 2698
@@ -2638,8 +2768,6 @@ try_mount_again:
2638 goto remote_path_check; 2768 goto remote_path_check;
2639 } 2769 }
2640 2770
2641 cifs_sb->tcon = tcon;
2642
2643 /* do not care if following two calls succeed - informational */ 2771 /* do not care if following two calls succeed - informational */
2644 if (!tcon->ipc) { 2772 if (!tcon->ipc) {
2645 CIFSSMBQFSDeviceInfo(xid, tcon); 2773 CIFSSMBQFSDeviceInfo(xid, tcon);
@@ -2748,6 +2876,38 @@ remote_path_check:
2748#endif 2876#endif
2749 } 2877 }
2750 2878
2879 if (rc)
2880 goto mount_fail_check;
2881
2882 /* now, hang the tcon off of the superblock */
2883 tlink = kzalloc(sizeof *tlink, GFP_KERNEL);
2884 if (tlink == NULL) {
2885 rc = -ENOMEM;
2886 goto mount_fail_check;
2887 }
2888
2889 tlink->tl_index = pSesInfo->linux_uid;
2890 tlink->tl_tcon = tcon;
2891 tlink->tl_time = jiffies;
2892 set_bit(TCON_LINK_MASTER, &tlink->tl_flags);
2893 set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags);
2894
2895 rc = radix_tree_preload(GFP_KERNEL);
2896 if (rc == -ENOMEM) {
2897 kfree(tlink);
2898 goto mount_fail_check;
2899 }
2900
2901 spin_lock(&cifs_sb->tlink_tree_lock);
2902 radix_tree_insert(&cifs_sb->tlink_tree, pSesInfo->linux_uid, tlink);
2903 radix_tree_tag_set(&cifs_sb->tlink_tree, pSesInfo->linux_uid,
2904 CIFS_TLINK_MASTER_TAG);
2905 spin_unlock(&cifs_sb->tlink_tree_lock);
2906 radix_tree_preload_end();
2907
2908 queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
2909 TLINK_IDLE_EXPIRE);
2910
2751mount_fail_check: 2911mount_fail_check:
2752 /* on error free sesinfo and tcon struct if needed */ 2912 /* on error free sesinfo and tcon struct if needed */
2753 if (rc) { 2913 if (rc) {
@@ -2825,14 +2985,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2825#ifdef CONFIG_CIFS_WEAK_PW_HASH 2985#ifdef CONFIG_CIFS_WEAK_PW_HASH
2826 if ((global_secflags & CIFSSEC_MAY_LANMAN) && 2986 if ((global_secflags & CIFSSEC_MAY_LANMAN) &&
2827 (ses->server->secType == LANMAN)) 2987 (ses->server->secType == LANMAN))
2828 calc_lanman_hash(tcon->password, ses->server->cryptKey, 2988 calc_lanman_hash(tcon->password, ses->cryptKey,
2829 ses->server->secMode & 2989 ses->server->secMode &
2830 SECMODE_PW_ENCRYPT ? true : false, 2990 SECMODE_PW_ENCRYPT ? true : false,
2831 bcc_ptr); 2991 bcc_ptr);
2832 else 2992 else
2833#endif /* CIFS_WEAK_PW_HASH */ 2993#endif /* CIFS_WEAK_PW_HASH */
2834 SMBNTencrypt(tcon->password, ses->server->cryptKey, 2994 SMBNTencrypt(tcon->password, ses->cryptKey, bcc_ptr);
2835 bcc_ptr);
2836 2995
2837 bcc_ptr += CIFS_SESS_KEY_SIZE; 2996 bcc_ptr += CIFS_SESS_KEY_SIZE;
2838 if (ses->capabilities & CAP_UNICODE) { 2997 if (ses->capabilities & CAP_UNICODE) {
@@ -2934,19 +3093,39 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
2934int 3093int
2935cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3094cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
2936{ 3095{
2937 int rc = 0; 3096 int i, ret;
2938 char *tmp; 3097 char *tmp;
3098 struct tcon_link *tlink[8];
3099 unsigned long index = 0;
3100
3101 cancel_delayed_work_sync(&cifs_sb->prune_tlinks);
3102
3103 do {
3104 spin_lock(&cifs_sb->tlink_tree_lock);
3105 ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
3106 (void **)tlink, index,
3107 ARRAY_SIZE(tlink));
3108 /* increment index for next pass */
3109 if (ret > 0)
3110 index = tlink[ret - 1]->tl_index + 1;
3111 for (i = 0; i < ret; i++) {
3112 cifs_get_tlink(tlink[i]);
3113 clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
3114 radix_tree_delete(&cifs_sb->tlink_tree,
3115 tlink[i]->tl_index);
3116 }
3117 spin_unlock(&cifs_sb->tlink_tree_lock);
2939 3118
2940 if (cifs_sb->tcon) 3119 for (i = 0; i < ret; i++)
2941 cifs_put_tcon(cifs_sb->tcon); 3120 cifs_put_tlink(tlink[i]);
3121 } while (ret != 0);
2942 3122
2943 cifs_sb->tcon = NULL;
2944 tmp = cifs_sb->prepath; 3123 tmp = cifs_sb->prepath;
2945 cifs_sb->prepathlen = 0; 3124 cifs_sb->prepathlen = 0;
2946 cifs_sb->prepath = NULL; 3125 cifs_sb->prepath = NULL;
2947 kfree(tmp); 3126 kfree(tmp);
2948 3127
2949 return rc; 3128 return 0;
2950} 3129}
2951 3130
2952int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) 3131int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses)
@@ -2997,6 +3176,15 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
2997 if (rc) { 3176 if (rc) {
2998 cERROR(1, "Send error in SessSetup = %d", rc); 3177 cERROR(1, "Send error in SessSetup = %d", rc);
2999 } else { 3178 } else {
3179 mutex_lock(&ses->server->srv_mutex);
3180 if (!server->session_estab) {
3181 memcpy(&server->session_key.data,
3182 &ses->auth_key.data, ses->auth_key.len);
3183 server->session_key.len = ses->auth_key.len;
3184 ses->server->session_estab = true;
3185 }
3186 mutex_unlock(&server->srv_mutex);
3187
3000 cFYI(1, "CIFS Session Established successfully"); 3188 cFYI(1, "CIFS Session Established successfully");
3001 spin_lock(&GlobalMid_Lock); 3189 spin_lock(&GlobalMid_Lock);
3002 ses->status = CifsGood; 3190 ses->status = CifsGood;
@@ -3007,3 +3195,237 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses,
3007 return rc; 3195 return rc;
3008} 3196}
3009 3197
3198static struct cifsTconInfo *
3199cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid)
3200{
3201 struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb);
3202 struct cifsSesInfo *ses;
3203 struct cifsTconInfo *tcon = NULL;
3204 struct smb_vol *vol_info;
3205 char username[MAX_USERNAME_SIZE + 1];
3206
3207 vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL);
3208 if (vol_info == NULL) {
3209 tcon = ERR_PTR(-ENOMEM);
3210 goto out;
3211 }
3212
3213 snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid);
3214 vol_info->username = username;
3215 vol_info->local_nls = cifs_sb->local_nls;
3216 vol_info->linux_uid = fsuid;
3217 vol_info->cred_uid = fsuid;
3218 vol_info->UNC = master_tcon->treeName;
3219 vol_info->retry = master_tcon->retry;
3220 vol_info->nocase = master_tcon->nocase;
3221 vol_info->local_lease = master_tcon->local_lease;
3222 vol_info->no_linux_ext = !master_tcon->unix_ext;
3223
3224 /* FIXME: allow for other secFlg settings */
3225 vol_info->secFlg = CIFSSEC_MUST_KRB5;
3226
3227 /* get a reference for the same TCP session */
3228 spin_lock(&cifs_tcp_ses_lock);
3229 ++master_tcon->ses->server->srv_count;
3230 spin_unlock(&cifs_tcp_ses_lock);
3231
3232 ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info);
3233 if (IS_ERR(ses)) {
3234 tcon = (struct cifsTconInfo *)ses;
3235 cifs_put_tcp_session(master_tcon->ses->server);
3236 goto out;
3237 }
3238
3239 tcon = cifs_get_tcon(ses, vol_info);
3240 if (IS_ERR(tcon)) {
3241 cifs_put_smb_ses(ses);
3242 goto out;
3243 }
3244
3245 if (ses->capabilities & CAP_UNIX)
3246 reset_cifs_unix_caps(0, tcon, NULL, vol_info);
3247out:
3248 kfree(vol_info);
3249
3250 return tcon;
3251}
3252
3253static struct tcon_link *
3254cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb)
3255{
3256 struct tcon_link *tlink;
3257 unsigned int ret;
3258
3259 spin_lock(&cifs_sb->tlink_tree_lock);
3260 ret = radix_tree_gang_lookup_tag(&cifs_sb->tlink_tree, (void **)&tlink,
3261 0, 1, CIFS_TLINK_MASTER_TAG);
3262 spin_unlock(&cifs_sb->tlink_tree_lock);
3263
3264 /* the master tcon should always be present */
3265 if (ret == 0)
3266 BUG();
3267
3268 return tlink;
3269}
3270
3271struct cifsTconInfo *
3272cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb)
3273{
3274 return tlink_tcon(cifs_sb_master_tlink(cifs_sb));
3275}
3276
3277static int
3278cifs_sb_tcon_pending_wait(void *unused)
3279{
3280 schedule();
3281 return signal_pending(current) ? -ERESTARTSYS : 0;
3282}
3283
3284/*
3285 * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the
3286 * current task.
3287 *
3288 * If the superblock doesn't refer to a multiuser mount, then just return
3289 * the master tcon for the mount.
3290 *
3291 * First, search the radix tree for an existing tcon for this fsuid. If one
3292 * exists, then check to see if it's pending construction. If it is then wait
3293 * for construction to complete. Once it's no longer pending, check to see if
3294 * it failed and either return an error or retry construction, depending on
3295 * the timeout.
3296 *
3297 * If one doesn't exist then insert a new tcon_link struct into the tree and
3298 * try to construct a new one.
3299 */
3300struct tcon_link *
3301cifs_sb_tlink(struct cifs_sb_info *cifs_sb)
3302{
3303 int ret;
3304 unsigned long fsuid = (unsigned long) current_fsuid();
3305 struct tcon_link *tlink, *newtlink;
3306
3307 if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER))
3308 return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb));
3309
3310 spin_lock(&cifs_sb->tlink_tree_lock);
3311 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3312 if (tlink)
3313 cifs_get_tlink(tlink);
3314 spin_unlock(&cifs_sb->tlink_tree_lock);
3315
3316 if (tlink == NULL) {
3317 newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL);
3318 if (newtlink == NULL)
3319 return ERR_PTR(-ENOMEM);
3320 newtlink->tl_index = fsuid;
3321 newtlink->tl_tcon = ERR_PTR(-EACCES);
3322 set_bit(TCON_LINK_PENDING, &newtlink->tl_flags);
3323 set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags);
3324 cifs_get_tlink(newtlink);
3325
3326 ret = radix_tree_preload(GFP_KERNEL);
3327 if (ret != 0) {
3328 kfree(newtlink);
3329 return ERR_PTR(ret);
3330 }
3331
3332 spin_lock(&cifs_sb->tlink_tree_lock);
3333 /* was one inserted after previous search? */
3334 tlink = radix_tree_lookup(&cifs_sb->tlink_tree, fsuid);
3335 if (tlink) {
3336 cifs_get_tlink(tlink);
3337 spin_unlock(&cifs_sb->tlink_tree_lock);
3338 radix_tree_preload_end();
3339 kfree(newtlink);
3340 goto wait_for_construction;
3341 }
3342 ret = radix_tree_insert(&cifs_sb->tlink_tree, fsuid, newtlink);
3343 spin_unlock(&cifs_sb->tlink_tree_lock);
3344 radix_tree_preload_end();
3345 if (ret) {
3346 kfree(newtlink);
3347 return ERR_PTR(ret);
3348 }
3349 tlink = newtlink;
3350 } else {
3351wait_for_construction:
3352 ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING,
3353 cifs_sb_tcon_pending_wait,
3354 TASK_INTERRUPTIBLE);
3355 if (ret) {
3356 cifs_put_tlink(tlink);
3357 return ERR_PTR(ret);
3358 }
3359
3360 /* if it's good, return it */
3361 if (!IS_ERR(tlink->tl_tcon))
3362 return tlink;
3363
3364 /* return error if we tried this already recently */
3365 if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) {
3366 cifs_put_tlink(tlink);
3367 return ERR_PTR(-EACCES);
3368 }
3369
3370 if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags))
3371 goto wait_for_construction;
3372 }
3373
3374 tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid);
3375 clear_bit(TCON_LINK_PENDING, &tlink->tl_flags);
3376 wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING);
3377
3378 if (IS_ERR(tlink->tl_tcon)) {
3379 cifs_put_tlink(tlink);
3380 return ERR_PTR(-EACCES);
3381 }
3382
3383 return tlink;
3384}
3385
3386/*
3387 * periodic workqueue job that scans tcon_tree for a superblock and closes
3388 * out tcons.
3389 */
3390static void
3391cifs_prune_tlinks(struct work_struct *work)
3392{
3393 struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info,
3394 prune_tlinks.work);
3395 struct tcon_link *tlink[8];
3396 unsigned long now = jiffies;
3397 unsigned long index = 0;
3398 int i, ret;
3399
3400 do {
3401 spin_lock(&cifs_sb->tlink_tree_lock);
3402 ret = radix_tree_gang_lookup(&cifs_sb->tlink_tree,
3403 (void **)tlink, index,
3404 ARRAY_SIZE(tlink));
3405 /* increment index for next pass */
3406 if (ret > 0)
3407 index = tlink[ret - 1]->tl_index + 1;
3408 for (i = 0; i < ret; i++) {
3409 if (test_bit(TCON_LINK_MASTER, &tlink[i]->tl_flags) ||
3410 atomic_read(&tlink[i]->tl_count) != 0 ||
3411 time_after(tlink[i]->tl_time + TLINK_IDLE_EXPIRE,
3412 now)) {
3413 tlink[i] = NULL;
3414 continue;
3415 }
3416 cifs_get_tlink(tlink[i]);
3417 clear_bit(TCON_LINK_IN_TREE, &tlink[i]->tl_flags);
3418 radix_tree_delete(&cifs_sb->tlink_tree,
3419 tlink[i]->tl_index);
3420 }
3421 spin_unlock(&cifs_sb->tlink_tree_lock);
3422
3423 for (i = 0; i < ret; i++) {
3424 if (tlink[i] != NULL)
3425 cifs_put_tlink(tlink[i]);
3426 }
3427 } while (ret != 0);
3428
3429 queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks,
3430 TLINK_IDLE_EXPIRE);
3431}