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.c873
1 files changed, 447 insertions, 426 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 71b7661e2260..c7d341714586 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -92,6 +92,8 @@ struct smb_vol {
92 bool seal:1; /* request transport encryption on share */ 92 bool seal:1; /* request transport encryption on share */
93 bool nodfs:1; /* Do not request DFS, even if available */ 93 bool nodfs:1; /* Do not request DFS, even if available */
94 bool local_lease:1; /* check leases only on local system, not remote */ 94 bool local_lease:1; /* check leases only on local system, not remote */
95 bool noblocksnd:1;
96 bool noautotune:1;
95 unsigned int rsize; 97 unsigned int rsize;
96 unsigned int wsize; 98 unsigned int wsize;
97 unsigned int sockopt; 99 unsigned int sockopt;
@@ -102,9 +104,11 @@ struct smb_vol {
102static int ipv4_connect(struct sockaddr_in *psin_server, 104static int ipv4_connect(struct sockaddr_in *psin_server,
103 struct socket **csocket, 105 struct socket **csocket,
104 char *netb_name, 106 char *netb_name,
105 char *server_netb_name); 107 char *server_netb_name,
108 bool noblocksnd,
109 bool nosndbuf); /* ipv6 never set sndbuf size */
106static int ipv6_connect(struct sockaddr_in6 *psin_server, 110static int ipv6_connect(struct sockaddr_in6 *psin_server,
107 struct socket **csocket); 111 struct socket **csocket, bool noblocksnd);
108 112
109 113
110 /* 114 /*
@@ -120,7 +124,7 @@ static int
120cifs_reconnect(struct TCP_Server_Info *server) 124cifs_reconnect(struct TCP_Server_Info *server)
121{ 125{
122 int rc = 0; 126 int rc = 0;
123 struct list_head *tmp; 127 struct list_head *tmp, *tmp2;
124 struct cifsSesInfo *ses; 128 struct cifsSesInfo *ses;
125 struct cifsTconInfo *tcon; 129 struct cifsTconInfo *tcon;
126 struct mid_q_entry *mid_entry; 130 struct mid_q_entry *mid_entry;
@@ -140,23 +144,17 @@ cifs_reconnect(struct TCP_Server_Info *server)
140 144
141 /* before reconnecting the tcp session, mark the smb session (uid) 145 /* before reconnecting the tcp session, mark the smb session (uid)
142 and the tid bad so they are not used until reconnected */ 146 and the tid bad so they are not used until reconnected */
143 read_lock(&GlobalSMBSeslock); 147 read_lock(&cifs_tcp_ses_lock);
144 list_for_each(tmp, &GlobalSMBSessionList) { 148 list_for_each(tmp, &server->smb_ses_list) {
145 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 149 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
146 if (ses->server) { 150 ses->need_reconnect = true;
147 if (ses->server == server) { 151 ses->ipc_tid = 0;
148 ses->status = CifsNeedReconnect; 152 list_for_each(tmp2, &ses->tcon_list) {
149 ses->ipc_tid = 0; 153 tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list);
150 } 154 tcon->need_reconnect = true;
151 } 155 }
152 /* else tcp and smb sessions need reconnection */
153 }
154 list_for_each(tmp, &GlobalTreeConnectionList) {
155 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
156 if ((tcon->ses) && (tcon->ses->server == server))
157 tcon->tidStatus = CifsNeedReconnect;
158 } 156 }
159 read_unlock(&GlobalSMBSeslock); 157 read_unlock(&cifs_tcp_ses_lock);
160 /* 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 */
161 down(&server->tcpSem); 159 down(&server->tcpSem);
162 if (server->ssocket) { 160 if (server->ssocket) {
@@ -189,14 +187,15 @@ cifs_reconnect(struct TCP_Server_Info *server)
189 while ((server->tcpStatus != CifsExiting) && 187 while ((server->tcpStatus != CifsExiting) &&
190 (server->tcpStatus != CifsGood)) { 188 (server->tcpStatus != CifsGood)) {
191 try_to_freeze(); 189 try_to_freeze();
192 if (server->protocolType == IPV6) { 190 if (server->addr.sockAddr6.sin6_family == AF_INET6) {
193 rc = ipv6_connect(&server->addr.sockAddr6, 191 rc = ipv6_connect(&server->addr.sockAddr6,
194 &server->ssocket); 192 &server->ssocket, server->noautotune);
195 } else { 193 } else {
196 rc = ipv4_connect(&server->addr.sockAddr, 194 rc = ipv4_connect(&server->addr.sockAddr,
197 &server->ssocket, 195 &server->ssocket,
198 server->workstation_RFC1001_name, 196 server->workstation_RFC1001_name,
199 server->server_RFC1001_name); 197 server->server_RFC1001_name,
198 server->noblocksnd, server->noautotune);
200 } 199 }
201 if (rc) { 200 if (rc) {
202 cFYI(1, ("reconnect error %d", rc)); 201 cFYI(1, ("reconnect error %d", rc));
@@ -412,9 +411,14 @@ incomplete_rcv:
412 msleep(1); /* minimum sleep to prevent looping 411 msleep(1); /* minimum sleep to prevent looping
413 allowing socket to clear and app threads to set 412 allowing socket to clear and app threads to set
414 tcpStatus CifsNeedReconnect if server hung */ 413 tcpStatus CifsNeedReconnect if server hung */
415 if (pdu_length < 4) 414 if (pdu_length < 4) {
415 iov.iov_base = (4 - pdu_length) +
416 (char *)smb_buffer;
417 iov.iov_len = pdu_length;
418 smb_msg.msg_control = NULL;
419 smb_msg.msg_controllen = 0;
416 goto incomplete_rcv; 420 goto incomplete_rcv;
417 else 421 } else
418 continue; 422 continue;
419 } else if (length <= 0) { 423 } else if (length <= 0) {
420 if (server->tcpStatus == CifsNew) { 424 if (server->tcpStatus == CifsNew) {
@@ -649,6 +653,11 @@ multi_t2_fnd:
649 } 653 }
650 } /* end while !EXITING */ 654 } /* end while !EXITING */
651 655
656 /* take it off the list, if it's not already */
657 write_lock(&cifs_tcp_ses_lock);
658 list_del_init(&server->tcp_ses_list);
659 write_unlock(&cifs_tcp_ses_lock);
660
652 spin_lock(&GlobalMid_Lock); 661 spin_lock(&GlobalMid_Lock);
653 server->tcpStatus = CifsExiting; 662 server->tcpStatus = CifsExiting;
654 spin_unlock(&GlobalMid_Lock); 663 spin_unlock(&GlobalMid_Lock);
@@ -681,29 +690,29 @@ multi_t2_fnd:
681 if (smallbuf) /* no sense logging a debug message if NULL */ 690 if (smallbuf) /* no sense logging a debug message if NULL */
682 cifs_small_buf_release(smallbuf); 691 cifs_small_buf_release(smallbuf);
683 692
684 read_lock(&GlobalSMBSeslock); 693 /*
694 * BB: we shouldn't have to do any of this. It shouldn't be
695 * possible to exit from the thread with active SMB sessions
696 */
697 read_lock(&cifs_tcp_ses_lock);
685 if (list_empty(&server->pending_mid_q)) { 698 if (list_empty(&server->pending_mid_q)) {
686 /* loop through server session structures attached to this and 699 /* loop through server session structures attached to this and
687 mark them dead */ 700 mark them dead */
688 list_for_each(tmp, &GlobalSMBSessionList) { 701 list_for_each(tmp, &server->smb_ses_list) {
689 ses = 702 ses = list_entry(tmp, struct cifsSesInfo,
690 list_entry(tmp, struct cifsSesInfo, 703 smb_ses_list);
691 cifsSessionList); 704 ses->status = CifsExiting;
692 if (ses->server == server) { 705 ses->server = NULL;
693 ses->status = CifsExiting;
694 ses->server = NULL;
695 }
696 } 706 }
697 read_unlock(&GlobalSMBSeslock); 707 read_unlock(&cifs_tcp_ses_lock);
698 } else { 708 } else {
699 /* although we can not zero the server struct pointer yet, 709 /* although we can not zero the server struct pointer yet,
700 since there are active requests which may depnd on them, 710 since there are active requests which may depnd on them,
701 mark the corresponding SMB sessions as exiting too */ 711 mark the corresponding SMB sessions as exiting too */
702 list_for_each(tmp, &GlobalSMBSessionList) { 712 list_for_each(tmp, &server->smb_ses_list) {
703 ses = list_entry(tmp, struct cifsSesInfo, 713 ses = list_entry(tmp, struct cifsSesInfo,
704 cifsSessionList); 714 smb_ses_list);
705 if (ses->server == server) 715 ses->status = CifsExiting;
706 ses->status = CifsExiting;
707 } 716 }
708 717
709 spin_lock(&GlobalMid_Lock); 718 spin_lock(&GlobalMid_Lock);
@@ -718,7 +727,7 @@ multi_t2_fnd:
718 } 727 }
719 } 728 }
720 spin_unlock(&GlobalMid_Lock); 729 spin_unlock(&GlobalMid_Lock);
721 read_unlock(&GlobalSMBSeslock); 730 read_unlock(&cifs_tcp_ses_lock);
722 /* 1/8th of sec is more than enough time for them to exit */ 731 /* 1/8th of sec is more than enough time for them to exit */
723 msleep(125); 732 msleep(125);
724 } 733 }
@@ -740,14 +749,13 @@ multi_t2_fnd:
740 if there are any pointing to this (e.g 749 if there are any pointing to this (e.g
741 if a crazy root user tried to kill cifsd 750 if a crazy root user tried to kill cifsd
742 kernel thread explicitly this might happen) */ 751 kernel thread explicitly this might happen) */
743 write_lock(&GlobalSMBSeslock); 752 /* BB: This shouldn't be necessary, see above */
744 list_for_each(tmp, &GlobalSMBSessionList) { 753 read_lock(&cifs_tcp_ses_lock);
745 ses = list_entry(tmp, struct cifsSesInfo, 754 list_for_each(tmp, &server->smb_ses_list) {
746 cifsSessionList); 755 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
747 if (ses->server == server) 756 ses->server = NULL;
748 ses->server = NULL;
749 } 757 }
750 write_unlock(&GlobalSMBSeslock); 758 read_unlock(&cifs_tcp_ses_lock);
751 759
752 kfree(server->hostname); 760 kfree(server->hostname);
753 task_to_wake = xchg(&server->tsk, NULL); 761 task_to_wake = xchg(&server->tsk, NULL);
@@ -1192,6 +1200,10 @@ cifs_parse_mount_options(char *options, const char *devname,
1192 /* ignore */ 1200 /* ignore */
1193 } else if (strnicmp(data, "rw", 2) == 0) { 1201 } else if (strnicmp(data, "rw", 2) == 0) {
1194 vol->rw = true; 1202 vol->rw = true;
1203 } else if (strnicmp(data, "noblocksend", 11) == 0) {
1204 vol->noblocksnd = 1;
1205 } else if (strnicmp(data, "noautotune", 10) == 0) {
1206 vol->noautotune = 1;
1195 } else if ((strnicmp(data, "suid", 4) == 0) || 1207 } else if ((strnicmp(data, "suid", 4) == 0) ||
1196 (strnicmp(data, "nosuid", 6) == 0) || 1208 (strnicmp(data, "nosuid", 6) == 0) ||
1197 (strnicmp(data, "exec", 4) == 0) || 1209 (strnicmp(data, "exec", 4) == 0) ||
@@ -1343,94 +1355,158 @@ cifs_parse_mount_options(char *options, const char *devname,
1343 return 0; 1355 return 0;
1344} 1356}
1345 1357
1346static struct cifsSesInfo * 1358static struct TCP_Server_Info *
1347cifs_find_tcp_session(struct in_addr *target_ip_addr, 1359cifs_find_tcp_session(struct sockaddr *addr)
1348 struct in6_addr *target_ip6_addr,
1349 char *userName, struct TCP_Server_Info **psrvTcp)
1350{ 1360{
1351 struct list_head *tmp; 1361 struct list_head *tmp;
1352 struct cifsSesInfo *ses; 1362 struct TCP_Server_Info *server;
1353 1363 struct sockaddr_in *addr4 = (struct sockaddr_in *) addr;
1354 *psrvTcp = NULL; 1364 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr;
1365
1366 write_lock(&cifs_tcp_ses_lock);
1367 list_for_each(tmp, &cifs_tcp_ses_list) {
1368 server = list_entry(tmp, struct TCP_Server_Info,
1369 tcp_ses_list);
1370 /*
1371 * the demux thread can exit on its own while still in CifsNew
1372 * so don't accept any sockets in that state. Since the
1373 * tcpStatus never changes back to CifsNew it's safe to check
1374 * for this without a lock.
1375 */
1376 if (server->tcpStatus == CifsNew)
1377 continue;
1355 1378
1356 read_lock(&GlobalSMBSeslock); 1379 if (addr->sa_family == AF_INET &&
1357 list_for_each(tmp, &GlobalSMBSessionList) { 1380 (addr4->sin_addr.s_addr !=
1358 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 1381 server->addr.sockAddr.sin_addr.s_addr))
1359 if (!ses->server) 1382 continue;
1383 else if (addr->sa_family == AF_INET6 &&
1384 memcmp(&server->addr.sockAddr6.sin6_addr,
1385 &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
1360 continue; 1386 continue;
1361 1387
1362 if (target_ip_addr && 1388 ++server->srv_count;
1363 ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) 1389 write_unlock(&cifs_tcp_ses_lock);
1364 continue; 1390 cFYI(1, ("Existing tcp session with server found"));
1365 else if (target_ip6_addr && 1391 return server;
1366 memcmp(&ses->server->addr.sockAddr6.sin6_addr, 1392 }
1367 target_ip6_addr, sizeof(*target_ip6_addr))) 1393 write_unlock(&cifs_tcp_ses_lock);
1368 continue; 1394 return NULL;
1369 /* BB lock server and tcp session; increment use count here?? */ 1395}
1370 1396
1371 /* found a match on the TCP session */ 1397static void
1372 *psrvTcp = ses->server; 1398cifs_put_tcp_session(struct TCP_Server_Info *server)
1399{
1400 struct task_struct *task;
1373 1401
1374 /* BB check if reconnection needed */ 1402 write_lock(&cifs_tcp_ses_lock);
1375 if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { 1403 if (--server->srv_count > 0) {
1376 read_unlock(&GlobalSMBSeslock); 1404 write_unlock(&cifs_tcp_ses_lock);
1377 /* Found exact match on both TCP and 1405 return;
1378 SMB sessions */
1379 return ses;
1380 }
1381 /* else tcp and smb sessions need reconnection */
1382 } 1406 }
1383 read_unlock(&GlobalSMBSeslock);
1384 1407
1385 return NULL; 1408 list_del_init(&server->tcp_ses_list);
1409 write_unlock(&cifs_tcp_ses_lock);
1410
1411 spin_lock(&GlobalMid_Lock);
1412 server->tcpStatus = CifsExiting;
1413 spin_unlock(&GlobalMid_Lock);
1414
1415 task = xchg(&server->tsk, NULL);
1416 if (task)
1417 force_sig(SIGKILL, task);
1386} 1418}
1387 1419
1388static struct cifsTconInfo * 1420static struct cifsSesInfo *
1389find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) 1421cifs_find_smb_ses(struct TCP_Server_Info *server, char *username)
1390{ 1422{
1391 struct list_head *tmp; 1423 struct list_head *tmp;
1392 struct cifsTconInfo *tcon; 1424 struct cifsSesInfo *ses;
1393 __be32 old_ip;
1394
1395 read_lock(&GlobalSMBSeslock);
1396 1425
1397 list_for_each(tmp, &GlobalTreeConnectionList) { 1426 write_lock(&cifs_tcp_ses_lock);
1398 cFYI(1, ("Next tcon")); 1427 list_for_each(tmp, &server->smb_ses_list) {
1399 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 1428 ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list);
1400 if (!tcon->ses || !tcon->ses->server) 1429 if (strncmp(ses->userName, username, MAX_USERNAME_SIZE))
1401 continue; 1430 continue;
1402 1431
1403 old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr; 1432 ++ses->ses_count;
1404 cFYI(1, ("old ip addr: %x == new ip %x ?", 1433 write_unlock(&cifs_tcp_ses_lock);
1405 old_ip, new_target_ip_addr)); 1434 return ses;
1435 }
1436 write_unlock(&cifs_tcp_ses_lock);
1437 return NULL;
1438}
1439
1440static void
1441cifs_put_smb_ses(struct cifsSesInfo *ses)
1442{
1443 int xid;
1444 struct TCP_Server_Info *server = ses->server;
1406 1445
1407 if (old_ip != new_target_ip_addr) 1446 write_lock(&cifs_tcp_ses_lock);
1408 continue; 1447 if (--ses->ses_count > 0) {
1448 write_unlock(&cifs_tcp_ses_lock);
1449 return;
1450 }
1409 1451
1410 /* BB lock tcon, server, tcp session and increment use count? */ 1452 list_del_init(&ses->smb_ses_list);
1411 /* found a match on the TCP session */ 1453 write_unlock(&cifs_tcp_ses_lock);
1412 /* BB check if reconnection needed */
1413 cFYI(1, ("IP match, old UNC: %s new: %s",
1414 tcon->treeName, uncName));
1415 1454
1416 if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE)) 1455 if (ses->status == CifsGood) {
1417 continue; 1456 xid = GetXid();
1457 CIFSSMBLogoff(xid, ses);
1458 _FreeXid(xid);
1459 }
1460 sesInfoFree(ses);
1461 cifs_put_tcp_session(server);
1462}
1418 1463
1419 cFYI(1, ("and old usr: %s new: %s", 1464static struct cifsTconInfo *
1420 tcon->treeName, uncName)); 1465cifs_find_tcon(struct cifsSesInfo *ses, const char *unc)
1466{
1467 struct list_head *tmp;
1468 struct cifsTconInfo *tcon;
1421 1469
1422 if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE)) 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))
1423 continue; 1476 continue;
1424 1477
1425 /* matched smb session (user name) */ 1478 ++tcon->tc_count;
1426 read_unlock(&GlobalSMBSeslock); 1479 write_unlock(&cifs_tcp_ses_lock);
1427 return tcon; 1480 return tcon;
1428 } 1481 }
1429 1482 write_unlock(&cifs_tcp_ses_lock);
1430 read_unlock(&GlobalSMBSeslock);
1431 return NULL; 1483 return NULL;
1432} 1484}
1433 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
1434int 1510int
1435get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, 1511get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path,
1436 const struct nls_table *nls_codepage, unsigned int *pnum_referrals, 1512 const struct nls_table *nls_codepage, unsigned int *pnum_referrals,
@@ -1518,7 +1594,8 @@ static void rfc1002mangle(char *target, char *source, unsigned int length)
1518 1594
1519static int 1595static int
1520ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket, 1596ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1521 char *netbios_name, char *target_name) 1597 char *netbios_name, char *target_name,
1598 bool noblocksnd, bool noautotune)
1522{ 1599{
1523 int rc = 0; 1600 int rc = 0;
1524 int connected = 0; 1601 int connected = 0;
@@ -1590,11 +1667,16 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1590 (*csocket)->sk->sk_sndbuf, 1667 (*csocket)->sk->sk_sndbuf,
1591 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo)); 1668 (*csocket)->sk->sk_rcvbuf, (*csocket)->sk->sk_rcvtimeo));
1592 (*csocket)->sk->sk_rcvtimeo = 7 * HZ; 1669 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1670 if (!noblocksnd)
1671 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1672
1593 /* make the bufsizes depend on wsize/rsize and max requests */ 1673 /* make the bufsizes depend on wsize/rsize and max requests */
1594 if ((*csocket)->sk->sk_sndbuf < (200 * 1024)) 1674 if (noautotune) {
1595 (*csocket)->sk->sk_sndbuf = 200 * 1024; 1675 if ((*csocket)->sk->sk_sndbuf < (200 * 1024))
1596 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024)) 1676 (*csocket)->sk->sk_sndbuf = 200 * 1024;
1597 (*csocket)->sk->sk_rcvbuf = 140 * 1024; 1677 if ((*csocket)->sk->sk_rcvbuf < (140 * 1024))
1678 (*csocket)->sk->sk_rcvbuf = 140 * 1024;
1679 }
1598 1680
1599 /* send RFC1001 sessinit */ 1681 /* send RFC1001 sessinit */
1600 if (psin_server->sin_port == htons(RFC1001_PORT)) { 1682 if (psin_server->sin_port == htons(RFC1001_PORT)) {
@@ -1631,7 +1713,7 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1631 /* sizeof RFC1002_SESSION_REQUEST with no scope */ 1713 /* sizeof RFC1002_SESSION_REQUEST with no scope */
1632 smb_buf->smb_buf_length = 0x81000044; 1714 smb_buf->smb_buf_length = 0x81000044;
1633 rc = smb_send(*csocket, smb_buf, 0x44, 1715 rc = smb_send(*csocket, smb_buf, 0x44,
1634 (struct sockaddr *)psin_server); 1716 (struct sockaddr *)psin_server, noblocksnd);
1635 kfree(ses_init_buf); 1717 kfree(ses_init_buf);
1636 msleep(1); /* RFC1001 layer in at least one server 1718 msleep(1); /* RFC1001 layer in at least one server
1637 requires very short break before negprot 1719 requires very short break before negprot
@@ -1651,7 +1733,8 @@ ipv4_connect(struct sockaddr_in *psin_server, struct socket **csocket,
1651} 1733}
1652 1734
1653static int 1735static int
1654ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket) 1736ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket,
1737 bool noblocksnd)
1655{ 1738{
1656 int rc = 0; 1739 int rc = 0;
1657 int connected = 0; 1740 int connected = 0;
@@ -1720,6 +1803,9 @@ ipv6_connect(struct sockaddr_in6 *psin_server, struct socket **csocket)
1720 the default. sock_setsockopt not used because it expects 1803 the default. sock_setsockopt not used because it expects
1721 user space buffer */ 1804 user space buffer */
1722 (*csocket)->sk->sk_rcvtimeo = 7 * HZ; 1805 (*csocket)->sk->sk_rcvtimeo = 7 * HZ;
1806 if (!noblocksnd)
1807 (*csocket)->sk->sk_sndtimeo = 3 * HZ;
1808
1723 1809
1724 return rc; 1810 return rc;
1725} 1811}
@@ -1857,14 +1943,90 @@ convert_delimiter(char *path, char delim)
1857 } 1943 }
1858} 1944}
1859 1945
1860static void 1946static void setup_cifs_sb(struct smb_vol *pvolume_info,
1861kill_cifsd(struct TCP_Server_Info *server) 1947 struct cifs_sb_info *cifs_sb)
1862{ 1948{
1863 struct task_struct *task; 1949 if (pvolume_info->rsize > CIFSMaxBufSize) {
1864 1950 cERROR(1, ("rsize %d too large, using MaxBufSize",
1865 task = xchg(&server->tsk, NULL); 1951 pvolume_info->rsize));
1866 if (task) 1952 cifs_sb->rsize = CIFSMaxBufSize;
1867 force_sig(SIGKILL, task); 1953 } else if ((pvolume_info->rsize) &&
1954 (pvolume_info->rsize <= CIFSMaxBufSize))
1955 cifs_sb->rsize = pvolume_info->rsize;
1956 else /* default */
1957 cifs_sb->rsize = CIFSMaxBufSize;
1958
1959 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1960 cERROR(1, ("wsize %d too large, using 4096 instead",
1961 pvolume_info->wsize));
1962 cifs_sb->wsize = 4096;
1963 } else if (pvolume_info->wsize)
1964 cifs_sb->wsize = pvolume_info->wsize;
1965 else
1966 cifs_sb->wsize = min_t(const int,
1967 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1968 127*1024);
1969 /* old default of CIFSMaxBufSize was too small now
1970 that SMB Write2 can send multiple pages in kvec.
1971 RFC1001 does not describe what happens when frame
1972 bigger than 128K is sent so use that as max in
1973 conjunction with 52K kvec constraint on arch with 4K
1974 page size */
1975
1976 if (cifs_sb->rsize < 2048) {
1977 cifs_sb->rsize = 2048;
1978 /* Windows ME may prefer this */
1979 cFYI(1, ("readsize set to minimum: 2048"));
1980 }
1981 /* calculate prepath */
1982 cifs_sb->prepath = pvolume_info->prepath;
1983 if (cifs_sb->prepath) {
1984 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1985 /* we can not convert the / to \ in the path
1986 separators in the prefixpath yet because we do not
1987 know (until reset_cifs_unix_caps is called later)
1988 whether POSIX PATH CAP is available. We normalize
1989 the / to \ after reset_cifs_unix_caps is called */
1990 pvolume_info->prepath = NULL;
1991 } else
1992 cifs_sb->prepathlen = 0;
1993 cifs_sb->mnt_uid = pvolume_info->linux_uid;
1994 cifs_sb->mnt_gid = pvolume_info->linux_gid;
1995 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
1996 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
1997 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
1998 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
1999
2000 if (pvolume_info->noperm)
2001 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2002 if (pvolume_info->setuids)
2003 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2004 if (pvolume_info->server_ino)
2005 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2006 if (pvolume_info->remap)
2007 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2008 if (pvolume_info->no_xattr)
2009 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2010 if (pvolume_info->sfu_emul)
2011 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2012 if (pvolume_info->nobrl)
2013 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
2014 if (pvolume_info->cifs_acl)
2015 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2016 if (pvolume_info->override_uid)
2017 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2018 if (pvolume_info->override_gid)
2019 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2020 if (pvolume_info->dynperm)
2021 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2022 if (pvolume_info->direct_io) {
2023 cFYI(1, ("mounting share using direct i/o"));
2024 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2025 }
2026
2027 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
2028 cERROR(1, ("mount option dynperm ignored if cifsacl "
2029 "mount option supported"));
1868} 2030}
1869 2031
1870int 2032int
@@ -1873,13 +2035,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1873{ 2035{
1874 int rc = 0; 2036 int rc = 0;
1875 int xid; 2037 int xid;
1876 int address_type = AF_INET;
1877 struct socket *csocket = NULL; 2038 struct socket *csocket = NULL;
1878 struct sockaddr_in sin_server; 2039 struct sockaddr addr;
1879 struct sockaddr_in6 sin_server6; 2040 struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr;
2041 struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr;
1880 struct smb_vol volume_info; 2042 struct smb_vol volume_info;
1881 struct cifsSesInfo *pSesInfo = NULL; 2043 struct cifsSesInfo *pSesInfo = NULL;
1882 struct cifsSesInfo *existingCifsSes = NULL;
1883 struct cifsTconInfo *tcon = NULL; 2044 struct cifsTconInfo *tcon = NULL;
1884 struct TCP_Server_Info *srvTcp = NULL; 2045 struct TCP_Server_Info *srvTcp = NULL;
1885 2046
@@ -1887,6 +2048,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1887 2048
1888/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ 2049/* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */
1889 2050
2051 memset(&addr, 0, sizeof(struct sockaddr));
1890 memset(&volume_info, 0, sizeof(struct smb_vol)); 2052 memset(&volume_info, 0, sizeof(struct smb_vol));
1891 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { 2053 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) {
1892 rc = -EINVAL; 2054 rc = -EINVAL;
@@ -1909,16 +2071,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1909 2071
1910 if (volume_info.UNCip && volume_info.UNC) { 2072 if (volume_info.UNCip && volume_info.UNC) {
1911 rc = cifs_inet_pton(AF_INET, volume_info.UNCip, 2073 rc = cifs_inet_pton(AF_INET, volume_info.UNCip,
1912 &sin_server.sin_addr.s_addr); 2074 &sin_server->sin_addr.s_addr);
1913 2075
1914 if (rc <= 0) { 2076 if (rc <= 0) {
1915 /* not ipv4 address, try ipv6 */ 2077 /* not ipv4 address, try ipv6 */
1916 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, 2078 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip,
1917 &sin_server6.sin6_addr.in6_u); 2079 &sin_server6->sin6_addr.in6_u);
1918 if (rc > 0) 2080 if (rc > 0)
1919 address_type = AF_INET6; 2081 addr.sa_family = AF_INET6;
1920 } else { 2082 } else {
1921 address_type = AF_INET; 2083 addr.sa_family = AF_INET;
1922 } 2084 }
1923 2085
1924 if (rc <= 0) { 2086 if (rc <= 0) {
@@ -1958,38 +2120,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1958 } 2120 }
1959 } 2121 }
1960 2122
1961 if (address_type == AF_INET) 2123 srvTcp = cifs_find_tcp_session(&addr);
1962 existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, 2124 if (!srvTcp) { /* create socket */
1963 NULL /* no ipv6 addr */, 2125 if (addr.sa_family == AF_INET6) {
1964 volume_info.username, &srvTcp);
1965 else if (address_type == AF_INET6) {
1966 cFYI(1, ("looking for ipv6 address"));
1967 existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */,
1968 &sin_server6.sin6_addr,
1969 volume_info.username, &srvTcp);
1970 } else {
1971 rc = -EINVAL;
1972 goto out;
1973 }
1974
1975 if (srvTcp) {
1976 cFYI(1, ("Existing tcp session with server found"));
1977 } else { /* create socket */
1978 if (volume_info.port)
1979 sin_server.sin_port = htons(volume_info.port);
1980 else
1981 sin_server.sin_port = 0;
1982 if (address_type == AF_INET6) {
1983 cFYI(1, ("attempting ipv6 connect")); 2126 cFYI(1, ("attempting ipv6 connect"));
1984 /* BB should we allow ipv6 on port 139? */ 2127 /* BB should we allow ipv6 on port 139? */
1985 /* other OS never observed in Wild doing 139 with v6 */ 2128 /* other OS never observed in Wild doing 139 with v6 */
1986 rc = ipv6_connect(&sin_server6, &csocket); 2129 sin_server6->sin6_port = htons(volume_info.port);
1987 } else 2130 rc = ipv6_connect(sin_server6, &csocket,
1988 rc = ipv4_connect(&sin_server, &csocket, 2131 volume_info.noblocksnd);
2132 } else {
2133 sin_server->sin_port = htons(volume_info.port);
2134 rc = ipv4_connect(sin_server, &csocket,
1989 volume_info.source_rfc1001_name, 2135 volume_info.source_rfc1001_name,
1990 volume_info.target_rfc1001_name); 2136 volume_info.target_rfc1001_name,
2137 volume_info.noblocksnd,
2138 volume_info.noautotune);
2139 }
1991 if (rc < 0) { 2140 if (rc < 0) {
1992 cERROR(1, ("Error connecting to IPv4 socket. " 2141 cERROR(1, ("Error connecting to socket. "
1993 "Aborting operation")); 2142 "Aborting operation"));
1994 if (csocket != NULL) 2143 if (csocket != NULL)
1995 sock_release(csocket); 2144 sock_release(csocket);
@@ -2002,12 +2151,17 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2002 sock_release(csocket); 2151 sock_release(csocket);
2003 goto out; 2152 goto out;
2004 } else { 2153 } else {
2005 memcpy(&srvTcp->addr.sockAddr, &sin_server, 2154 srvTcp->noblocksnd = volume_info.noblocksnd;
2006 sizeof(struct sockaddr_in)); 2155 srvTcp->noautotune = volume_info.noautotune;
2156 if (addr.sa_family == AF_INET6)
2157 memcpy(&srvTcp->addr.sockAddr6, sin_server6,
2158 sizeof(struct sockaddr_in6));
2159 else
2160 memcpy(&srvTcp->addr.sockAddr, sin_server,
2161 sizeof(struct sockaddr_in));
2007 atomic_set(&srvTcp->inFlight, 0); 2162 atomic_set(&srvTcp->inFlight, 0);
2008 /* BB Add code for ipv6 case too */ 2163 /* BB Add code for ipv6 case too */
2009 srvTcp->ssocket = csocket; 2164 srvTcp->ssocket = csocket;
2010 srvTcp->protocolType = IPV4;
2011 srvTcp->hostname = extract_hostname(volume_info.UNC); 2165 srvTcp->hostname = extract_hostname(volume_info.UNC);
2012 if (IS_ERR(srvTcp->hostname)) { 2166 if (IS_ERR(srvTcp->hostname)) {
2013 rc = PTR_ERR(srvTcp->hostname); 2167 rc = PTR_ERR(srvTcp->hostname);
@@ -2037,15 +2191,28 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2037 memcpy(srvTcp->server_RFC1001_name, 2191 memcpy(srvTcp->server_RFC1001_name,
2038 volume_info.target_rfc1001_name, 16); 2192 volume_info.target_rfc1001_name, 16);
2039 srvTcp->sequence_number = 0; 2193 srvTcp->sequence_number = 0;
2194 INIT_LIST_HEAD(&srvTcp->tcp_ses_list);
2195 INIT_LIST_HEAD(&srvTcp->smb_ses_list);
2196 ++srvTcp->srv_count;
2197 write_lock(&cifs_tcp_ses_lock);
2198 list_add(&srvTcp->tcp_ses_list,
2199 &cifs_tcp_ses_list);
2200 write_unlock(&cifs_tcp_ses_lock);
2040 } 2201 }
2041 } 2202 }
2042 2203
2043 if (existingCifsSes) { 2204 pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username);
2044 pSesInfo = existingCifsSes; 2205 if (pSesInfo) {
2045 cFYI(1, ("Existing smb sess found (status=%d)", 2206 cFYI(1, ("Existing smb sess found (status=%d)",
2046 pSesInfo->status)); 2207 pSesInfo->status));
2208 /*
2209 * The existing SMB session already has a reference to srvTcp,
2210 * so we can put back the extra one we got before
2211 */
2212 cifs_put_tcp_session(srvTcp);
2213
2047 down(&pSesInfo->sesSem); 2214 down(&pSesInfo->sesSem);
2048 if (pSesInfo->status == CifsNeedReconnect) { 2215 if (pSesInfo->need_reconnect) {
2049 cFYI(1, ("Session needs reconnect")); 2216 cFYI(1, ("Session needs reconnect"));
2050 rc = cifs_setup_session(xid, pSesInfo, 2217 rc = cifs_setup_session(xid, pSesInfo,
2051 cifs_sb->local_nls); 2218 cifs_sb->local_nls);
@@ -2054,187 +2221,101 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2054 } else if (!rc) { 2221 } else if (!rc) {
2055 cFYI(1, ("Existing smb sess not found")); 2222 cFYI(1, ("Existing smb sess not found"));
2056 pSesInfo = sesInfoAlloc(); 2223 pSesInfo = sesInfoAlloc();
2057 if (pSesInfo == NULL) 2224 if (pSesInfo == NULL) {
2058 rc = -ENOMEM; 2225 rc = -ENOMEM;
2059 else { 2226 goto mount_fail_check;
2060 pSesInfo->server = srvTcp; 2227 }
2061 sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2228
2062 NIPQUAD(sin_server.sin_addr.s_addr)); 2229 /* new SMB session uses our srvTcp ref */
2063 } 2230 pSesInfo->server = srvTcp;
2231 sprintf(pSesInfo->serverName, "%u.%u.%u.%u",
2232 NIPQUAD(sin_server->sin_addr.s_addr));
2233
2234 write_lock(&cifs_tcp_ses_lock);
2235 list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list);
2236 write_unlock(&cifs_tcp_ses_lock);
2237
2238 /* volume_info.password freed at unmount */
2239 if (volume_info.password) {
2240 pSesInfo->password = volume_info.password;
2241 /* set to NULL to prevent freeing on exit */
2242 volume_info.password = NULL;
2243 }
2244 if (volume_info.username)
2245 strncpy(pSesInfo->userName, volume_info.username,
2246 MAX_USERNAME_SIZE);
2247 if (volume_info.domainname) {
2248 int len = strlen(volume_info.domainname);
2249 pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL);
2250 if (pSesInfo->domainName)
2251 strcpy(pSesInfo->domainName,
2252 volume_info.domainname);
2253 }
2254 pSesInfo->linux_uid = volume_info.linux_uid;
2255 pSesInfo->overrideSecFlg = volume_info.secFlg;
2256 down(&pSesInfo->sesSem);
2064 2257
2065 if (!rc) { 2258 /* BB FIXME need to pass vol->secFlgs BB */
2066 /* volume_info.password freed at unmount */ 2259 rc = cifs_setup_session(xid, pSesInfo,
2067 if (volume_info.password) { 2260 cifs_sb->local_nls);
2068 pSesInfo->password = volume_info.password; 2261 up(&pSesInfo->sesSem);
2069 /* set to NULL to prevent freeing on exit */
2070 volume_info.password = NULL;
2071 }
2072 if (volume_info.username)
2073 strncpy(pSesInfo->userName,
2074 volume_info.username,
2075 MAX_USERNAME_SIZE);
2076 if (volume_info.domainname) {
2077 int len = strlen(volume_info.domainname);
2078 pSesInfo->domainName =
2079 kmalloc(len + 1, GFP_KERNEL);
2080 if (pSesInfo->domainName)
2081 strcpy(pSesInfo->domainName,
2082 volume_info.domainname);
2083 }
2084 pSesInfo->linux_uid = volume_info.linux_uid;
2085 pSesInfo->overrideSecFlg = volume_info.secFlg;
2086 down(&pSesInfo->sesSem);
2087 /* BB FIXME need to pass vol->secFlgs BB */
2088 rc = cifs_setup_session(xid, pSesInfo,
2089 cifs_sb->local_nls);
2090 up(&pSesInfo->sesSem);
2091 if (!rc)
2092 atomic_inc(&srvTcp->socketUseCount);
2093 }
2094 } 2262 }
2095 2263
2096 /* search for existing tcon to this server share */ 2264 /* search for existing tcon to this server share */
2097 if (!rc) { 2265 if (!rc) {
2098 if (volume_info.rsize > CIFSMaxBufSize) { 2266 setup_cifs_sb(&volume_info, cifs_sb);
2099 cERROR(1, ("rsize %d too large, using MaxBufSize",
2100 volume_info.rsize));
2101 cifs_sb->rsize = CIFSMaxBufSize;
2102 } else if ((volume_info.rsize) &&
2103 (volume_info.rsize <= CIFSMaxBufSize))
2104 cifs_sb->rsize = volume_info.rsize;
2105 else /* default */
2106 cifs_sb->rsize = CIFSMaxBufSize;
2107
2108 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2109 cERROR(1, ("wsize %d too large, using 4096 instead",
2110 volume_info.wsize));
2111 cifs_sb->wsize = 4096;
2112 } else if (volume_info.wsize)
2113 cifs_sb->wsize = volume_info.wsize;
2114 else
2115 cifs_sb->wsize =
2116 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2117 127*1024);
2118 /* old default of CIFSMaxBufSize was too small now
2119 that SMB Write2 can send multiple pages in kvec.
2120 RFC1001 does not describe what happens when frame
2121 bigger than 128K is sent so use that as max in
2122 conjunction with 52K kvec constraint on arch with 4K
2123 page size */
2124
2125 if (cifs_sb->rsize < 2048) {
2126 cifs_sb->rsize = 2048;
2127 /* Windows ME may prefer this */
2128 cFYI(1, ("readsize set to minimum: 2048"));
2129 }
2130 /* calculate prepath */
2131 cifs_sb->prepath = volume_info.prepath;
2132 if (cifs_sb->prepath) {
2133 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2134 /* we can not convert the / to \ in the path
2135 separators in the prefixpath yet because we do not
2136 know (until reset_cifs_unix_caps is called later)
2137 whether POSIX PATH CAP is available. We normalize
2138 the / to \ after reset_cifs_unix_caps is called */
2139 volume_info.prepath = NULL;
2140 } else
2141 cifs_sb->prepathlen = 0;
2142 cifs_sb->mnt_uid = volume_info.linux_uid;
2143 cifs_sb->mnt_gid = volume_info.linux_gid;
2144 cifs_sb->mnt_file_mode = volume_info.file_mode;
2145 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
2146 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2147 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2148
2149 if (volume_info.noperm)
2150 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2151 if (volume_info.setuids)
2152 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2153 if (volume_info.server_ino)
2154 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2155 if (volume_info.remap)
2156 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2157 if (volume_info.no_xattr)
2158 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2159 if (volume_info.sfu_emul)
2160 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2161 if (volume_info.nobrl)
2162 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
2163 if (volume_info.cifs_acl)
2164 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2165 if (volume_info.override_uid)
2166 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2167 if (volume_info.override_gid)
2168 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2169 if (volume_info.dynperm)
2170 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2171 if (volume_info.direct_io) {
2172 cFYI(1, ("mounting share using direct i/o"));
2173 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2174 }
2175
2176 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2177 cERROR(1, ("mount option dynperm ignored if cifsacl "
2178 "mount option supported"));
2179 2267
2180 tcon = 2268 tcon = cifs_find_tcon(pSesInfo, volume_info.UNC);
2181 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2182 volume_info.username);
2183 if (tcon) { 2269 if (tcon) {
2184 cFYI(1, ("Found match on UNC path")); 2270 cFYI(1, ("Found match on UNC path"));
2185 /* we can have only one retry value for a connection 2271 /* existing tcon already has a reference */
2186 to a share so for resources mounted more than once 2272 cifs_put_smb_ses(pSesInfo);
2187 to the same server share the last value passed in
2188 for the retry flag is used */
2189 tcon->retry = volume_info.retry;
2190 tcon->nocase = volume_info.nocase;
2191 tcon->local_lease = volume_info.local_lease;
2192 if (tcon->seal != volume_info.seal) 2273 if (tcon->seal != volume_info.seal)
2193 cERROR(1, ("transport encryption setting " 2274 cERROR(1, ("transport encryption setting "
2194 "conflicts with existing tid")); 2275 "conflicts with existing tid"));
2195 } else { 2276 } else {
2196 tcon = tconInfoAlloc(); 2277 tcon = tconInfoAlloc();
2197 if (tcon == NULL) 2278 if (tcon == NULL) {
2198 rc = -ENOMEM; 2279 rc = -ENOMEM;
2199 else { 2280 goto mount_fail_check;
2200 /* check for null share name ie connecting to 2281 }
2201 * dfs root */ 2282 tcon->ses = pSesInfo;
2202 2283
2203 /* BB check if this works for exactly length 2284 /* check for null share name ie connect to dfs root */
2204 * three strings */ 2285 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2205 if ((strchr(volume_info.UNC + 3, '\\') == NULL) 2286 && (strchr(volume_info.UNC + 3, '/') == NULL)) {
2206 && (strchr(volume_info.UNC + 3, '/') == 2287 /* rc = connect_to_dfs_path(...) */
2207 NULL)) { 2288 cFYI(1, ("DFS root not supported"));
2208/* rc = connect_to_dfs_path(xid, pSesInfo, 2289 rc = -ENODEV;
2209 "", cifs_sb->local_nls, 2290 goto mount_fail_check;
2210 cifs_sb->mnt_cifs_flags & 2291 } else {
2211 CIFS_MOUNT_MAP_SPECIAL_CHR);*/ 2292 /* BB Do we need to wrap sesSem around
2212 cFYI(1, ("DFS root not supported")); 2293 * this TCon call and Unix SetFS as
2213 rc = -ENODEV; 2294 * we do on SessSetup and reconnect? */
2214 goto out; 2295 rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
2215 } else { 2296 tcon, cifs_sb->local_nls);
2216 /* BB Do we need to wrap sesSem around 2297 cFYI(1, ("CIFS Tcon rc = %d", rc));
2217 * this TCon call and Unix SetFS as 2298 if (volume_info.nodfs) {
2218 * we do on SessSetup and reconnect? */ 2299 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2219 rc = CIFSTCon(xid, pSesInfo, 2300 cFYI(1, ("DFS disabled (%d)",
2220 volume_info.UNC, 2301 tcon->Flags));
2221 tcon, cifs_sb->local_nls);
2222 cFYI(1, ("CIFS Tcon rc = %d", rc));
2223 if (volume_info.nodfs) {
2224 tcon->Flags &=
2225 ~SMB_SHARE_IS_IN_DFS;
2226 cFYI(1, ("DFS disabled (%d)",
2227 tcon->Flags));
2228 }
2229 }
2230 if (!rc) {
2231 atomic_inc(&pSesInfo->inUse);
2232 tcon->retry = volume_info.retry;
2233 tcon->nocase = volume_info.nocase;
2234 tcon->seal = volume_info.seal;
2235 } 2302 }
2236 } 2303 }
2237 } 2304 if (rc)
2305 goto mount_fail_check;
2306 tcon->seal = volume_info.seal;
2307 write_lock(&cifs_tcp_ses_lock);
2308 list_add(&tcon->tcon_list, &pSesInfo->tcon_list);
2309 write_unlock(&cifs_tcp_ses_lock);
2310 }
2311
2312 /* we can have only one retry value for a connection
2313 to a share so for resources mounted more than once
2314 to the same server share the last value passed in
2315 for the retry flag is used */
2316 tcon->retry = volume_info.retry;
2317 tcon->nocase = volume_info.nocase;
2318 tcon->local_lease = volume_info.local_lease;
2238 } 2319 }
2239 if (pSesInfo) { 2320 if (pSesInfo) {
2240 if (pSesInfo->capabilities & CAP_LARGE_FILES) { 2321 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
@@ -2246,80 +2327,49 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2246 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2327 /* BB FIXME fix time_gran to be larger for LANMAN sessions */
2247 sb->s_time_gran = 100; 2328 sb->s_time_gran = 100;
2248 2329
2249/* on error free sesinfo and tcon struct if needed */ 2330mount_fail_check:
2331 /* on error free sesinfo and tcon struct if needed */
2250 if (rc) { 2332 if (rc) {
2251 /* if session setup failed, use count is zero but 2333 /* If find_unc succeeded then rc == 0 so we can not end */
2252 we still need to free cifsd thread */ 2334 /* up accidently freeing someone elses tcon struct */
2253 if (atomic_read(&srvTcp->socketUseCount) == 0) { 2335 if (tcon)
2254 spin_lock(&GlobalMid_Lock); 2336 cifs_put_tcon(tcon);
2255 srvTcp->tcpStatus = CifsExiting; 2337 else if (pSesInfo)
2256 spin_unlock(&GlobalMid_Lock); 2338 cifs_put_smb_ses(pSesInfo);
2257 kill_cifsd(srvTcp);
2258 }
2259 /* If find_unc succeeded then rc == 0 so we can not end */
2260 if (tcon) /* up accidently freeing someone elses tcon struct */
2261 tconInfoFree(tcon);
2262 if (existingCifsSes == NULL) {
2263 if (pSesInfo) {
2264 if ((pSesInfo->server) &&
2265 (pSesInfo->status == CifsGood)) {
2266 int temp_rc;
2267 temp_rc = CIFSSMBLogoff(xid, pSesInfo);
2268 /* if the socketUseCount is now zero */
2269 if ((temp_rc == -ESHUTDOWN) &&
2270 (pSesInfo->server))
2271 kill_cifsd(pSesInfo->server);
2272 } else {
2273 cFYI(1, ("No session or bad tcon"));
2274 if (pSesInfo->server) {
2275 spin_lock(&GlobalMid_Lock);
2276 srvTcp->tcpStatus = CifsExiting;
2277 spin_unlock(&GlobalMid_Lock);
2278 kill_cifsd(pSesInfo->server);
2279 }
2280 }
2281 sesInfoFree(pSesInfo);
2282 /* pSesInfo = NULL; */
2283 }
2284 }
2285 } else {
2286 atomic_inc(&tcon->useCount);
2287 cifs_sb->tcon = tcon;
2288 tcon->ses = pSesInfo;
2289
2290 /* do not care if following two calls succeed - informational */
2291 if (!tcon->ipc) {
2292 CIFSSMBQFSDeviceInfo(xid, tcon);
2293 CIFSSMBQFSAttributeInfo(xid, tcon);
2294 }
2295
2296 /* tell server which Unix caps we support */
2297 if (tcon->ses->capabilities & CAP_UNIX)
2298 /* reset of caps checks mount to see if unix extensions
2299 disabled for just this mount */
2300 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
2301 else 2339 else
2302 tcon->unix_ext = 0; /* server does not support them */ 2340 cifs_put_tcp_session(srvTcp);
2341 goto out;
2342 }
2343 cifs_sb->tcon = tcon;
2303 2344
2304 /* convert forward to back slashes in prepath here if needed */ 2345 /* do not care if following two calls succeed - informational */
2305 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) 2346 if (!tcon->ipc) {
2306 convert_delimiter(cifs_sb->prepath, 2347 CIFSSMBQFSDeviceInfo(xid, tcon);
2307 CIFS_DIR_SEP(cifs_sb)); 2348 CIFSSMBQFSAttributeInfo(xid, tcon);
2349 }
2308 2350
2309 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { 2351 /* tell server which Unix caps we support */
2310 cifs_sb->rsize = 1024 * 127; 2352 if (tcon->ses->capabilities & CAP_UNIX)
2311 cFYI(DBG2, 2353 /* reset of caps checks mount to see if unix extensions
2312 ("no very large read support, rsize now 127K")); 2354 disabled for just this mount */
2313 } 2355 reset_cifs_unix_caps(xid, tcon, sb, &volume_info);
2314 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) 2356 else
2315 cifs_sb->wsize = min(cifs_sb->wsize, 2357 tcon->unix_ext = 0; /* server does not support them */
2316 (tcon->ses->server->maxBuf - 2358
2317 MAX_CIFS_HDR_SIZE)); 2359 /* convert forward to back slashes in prepath here if needed */
2318 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) 2360 if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0)
2319 cifs_sb->rsize = min(cifs_sb->rsize, 2361 convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb));
2320 (tcon->ses->server->maxBuf - 2362
2321 MAX_CIFS_HDR_SIZE)); 2363 if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) {
2364 cifs_sb->rsize = 1024 * 127;
2365 cFYI(DBG2, ("no very large read support, rsize now 127K"));
2322 } 2366 }
2367 if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X))
2368 cifs_sb->wsize = min(cifs_sb->wsize,
2369 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2370 if (!(tcon->ses->capabilities & CAP_LARGE_READ_X))
2371 cifs_sb->rsize = min(cifs_sb->rsize,
2372 (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
2323 2373
2324 /* volume_info.password is freed above when existing session found 2374 /* volume_info.password is freed above when existing session found
2325 (in which case it is not needed anymore) but when new sesion is created 2375 (in which case it is not needed anymore) but when new sesion is created
@@ -3489,6 +3539,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3489 /* above now done in SendReceive */ 3539 /* above now done in SendReceive */
3490 if ((rc == 0) && (tcon != NULL)) { 3540 if ((rc == 0) && (tcon != NULL)) {
3491 tcon->tidStatus = CifsGood; 3541 tcon->tidStatus = CifsGood;
3542 tcon->need_reconnect = false;
3492 tcon->tid = smb_buffer_response->Tid; 3543 tcon->tid = smb_buffer_response->Tid;
3493 bcc_ptr = pByteArea(smb_buffer_response); 3544 bcc_ptr = pByteArea(smb_buffer_response);
3494 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); 3545 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
@@ -3560,48 +3611,17 @@ int
3560cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3611cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb)
3561{ 3612{
3562 int rc = 0; 3613 int rc = 0;
3563 int xid;
3564 struct cifsSesInfo *ses = NULL;
3565 char *tmp; 3614 char *tmp;
3566 3615
3567 xid = GetXid(); 3616 if (cifs_sb->tcon)
3568 3617 cifs_put_tcon(cifs_sb->tcon);
3569 if (cifs_sb->tcon) {
3570 ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/
3571 rc = CIFSSMBTDis(xid, cifs_sb->tcon);
3572 if (rc == -EBUSY) {
3573 FreeXid(xid);
3574 return 0;
3575 }
3576 DeleteTconOplockQEntries(cifs_sb->tcon);
3577 tconInfoFree(cifs_sb->tcon);
3578 if ((ses) && (ses->server)) {
3579 /* save off task so we do not refer to ses later */
3580 cFYI(1, ("About to do SMBLogoff "));
3581 rc = CIFSSMBLogoff(xid, ses);
3582 if (rc == -EBUSY) {
3583 FreeXid(xid);
3584 return 0;
3585 } else if (rc == -ESHUTDOWN) {
3586 cFYI(1, ("Waking up socket by sending signal"));
3587 if (ses->server)
3588 kill_cifsd(ses->server);
3589 rc = 0;
3590 } /* else - we have an smb session
3591 left on this socket do not kill cifsd */
3592 } else
3593 cFYI(1, ("No session or bad tcon"));
3594 }
3595 3618
3596 cifs_sb->tcon = NULL; 3619 cifs_sb->tcon = NULL;
3597 tmp = cifs_sb->prepath; 3620 tmp = cifs_sb->prepath;
3598 cifs_sb->prepathlen = 0; 3621 cifs_sb->prepathlen = 0;
3599 cifs_sb->prepath = NULL; 3622 cifs_sb->prepath = NULL;
3600 kfree(tmp); 3623 kfree(tmp);
3601 if (ses)
3602 sesInfoFree(ses);
3603 3624
3604 FreeXid(xid);
3605 return rc; 3625 return rc;
3606} 3626}
3607 3627
@@ -3717,6 +3737,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3717 cFYI(1, ("CIFS Session Established successfully")); 3737 cFYI(1, ("CIFS Session Established successfully"));
3718 spin_lock(&GlobalMid_Lock); 3738 spin_lock(&GlobalMid_Lock);
3719 pSesInfo->status = CifsGood; 3739 pSesInfo->status = CifsGood;
3740 pSesInfo->need_reconnect = false;
3720 spin_unlock(&GlobalMid_Lock); 3741 spin_unlock(&GlobalMid_Lock);
3721 } 3742 }
3722 3743