diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 572 |
1 files changed, 509 insertions, 63 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 88c84a38bccb..251a17c03545 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,25 @@ 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 | |||
111 | static int ipv4_connect(struct TCP_Server_Info *server); | 117 | static int ipv4_connect(struct TCP_Server_Info *server); |
112 | static int ipv6_connect(struct TCP_Server_Info *server); | 118 | static int ipv6_connect(struct TCP_Server_Info *server); |
119 | static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink); | ||
120 | static void cifs_prune_tlinks(struct work_struct *work); | ||
113 | 121 | ||
114 | /* | 122 | /* |
115 | * cifs tcp session reconnection | 123 | * cifs tcp session reconnection |
@@ -143,7 +151,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
143 | 151 | ||
144 | /* before reconnecting the tcp session, mark the smb session (uid) | 152 | /* before reconnecting the tcp session, mark the smb session (uid) |
145 | and the tid bad so they are not used until reconnected */ | 153 | and the tid bad so they are not used until reconnected */ |
146 | read_lock(&cifs_tcp_ses_lock); | 154 | spin_lock(&cifs_tcp_ses_lock); |
147 | list_for_each(tmp, &server->smb_ses_list) { | 155 | list_for_each(tmp, &server->smb_ses_list) { |
148 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 156 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
149 | ses->need_reconnect = true; | 157 | ses->need_reconnect = true; |
@@ -153,7 +161,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
153 | tcon->need_reconnect = true; | 161 | tcon->need_reconnect = true; |
154 | } | 162 | } |
155 | } | 163 | } |
156 | read_unlock(&cifs_tcp_ses_lock); | 164 | spin_unlock(&cifs_tcp_ses_lock); |
157 | /* do not want to be sending data on a socket we are freeing */ | 165 | /* do not want to be sending data on a socket we are freeing */ |
158 | mutex_lock(&server->srv_mutex); | 166 | mutex_lock(&server->srv_mutex); |
159 | if (server->ssocket) { | 167 | if (server->ssocket) { |
@@ -166,6 +174,11 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
166 | sock_release(server->ssocket); | 174 | sock_release(server->ssocket); |
167 | server->ssocket = NULL; | 175 | server->ssocket = NULL; |
168 | } | 176 | } |
177 | server->sequence_number = 0; | ||
178 | server->session_estab = false; | ||
179 | kfree(server->session_key.response); | ||
180 | server->session_key.response = NULL; | ||
181 | server->session_key.len = 0; | ||
169 | 182 | ||
170 | spin_lock(&GlobalMid_Lock); | 183 | spin_lock(&GlobalMid_Lock); |
171 | list_for_each(tmp, &server->pending_mid_q) { | 184 | list_for_each(tmp, &server->pending_mid_q) { |
@@ -198,7 +211,6 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
198 | spin_lock(&GlobalMid_Lock); | 211 | spin_lock(&GlobalMid_Lock); |
199 | if (server->tcpStatus != CifsExiting) | 212 | if (server->tcpStatus != CifsExiting) |
200 | server->tcpStatus = CifsGood; | 213 | server->tcpStatus = CifsGood; |
201 | server->sequence_number = 0; | ||
202 | spin_unlock(&GlobalMid_Lock); | 214 | spin_unlock(&GlobalMid_Lock); |
203 | /* atomic_set(&server->inFlight,0);*/ | 215 | /* atomic_set(&server->inFlight,0);*/ |
204 | wake_up(&server->response_q); | 216 | wake_up(&server->response_q); |
@@ -629,9 +641,9 @@ multi_t2_fnd: | |||
629 | } /* end while !EXITING */ | 641 | } /* end while !EXITING */ |
630 | 642 | ||
631 | /* take it off the list, if it's not already */ | 643 | /* take it off the list, if it's not already */ |
632 | write_lock(&cifs_tcp_ses_lock); | 644 | spin_lock(&cifs_tcp_ses_lock); |
633 | list_del_init(&server->tcp_ses_list); | 645 | list_del_init(&server->tcp_ses_list); |
634 | write_unlock(&cifs_tcp_ses_lock); | 646 | spin_unlock(&cifs_tcp_ses_lock); |
635 | 647 | ||
636 | spin_lock(&GlobalMid_Lock); | 648 | spin_lock(&GlobalMid_Lock); |
637 | server->tcpStatus = CifsExiting; | 649 | server->tcpStatus = CifsExiting; |
@@ -669,7 +681,7 @@ multi_t2_fnd: | |||
669 | * BB: we shouldn't have to do any of this. It shouldn't be | 681 | * 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 | 682 | * possible to exit from the thread with active SMB sessions |
671 | */ | 683 | */ |
672 | read_lock(&cifs_tcp_ses_lock); | 684 | spin_lock(&cifs_tcp_ses_lock); |
673 | if (list_empty(&server->pending_mid_q)) { | 685 | if (list_empty(&server->pending_mid_q)) { |
674 | /* loop through server session structures attached to this and | 686 | /* loop through server session structures attached to this and |
675 | mark them dead */ | 687 | mark them dead */ |
@@ -679,7 +691,7 @@ multi_t2_fnd: | |||
679 | ses->status = CifsExiting; | 691 | ses->status = CifsExiting; |
680 | ses->server = NULL; | 692 | ses->server = NULL; |
681 | } | 693 | } |
682 | read_unlock(&cifs_tcp_ses_lock); | 694 | spin_unlock(&cifs_tcp_ses_lock); |
683 | } else { | 695 | } else { |
684 | /* although we can not zero the server struct pointer yet, | 696 | /* although we can not zero the server struct pointer yet, |
685 | since there are active requests which may depnd on them, | 697 | since there are active requests which may depnd on them, |
@@ -702,7 +714,7 @@ multi_t2_fnd: | |||
702 | } | 714 | } |
703 | } | 715 | } |
704 | spin_unlock(&GlobalMid_Lock); | 716 | spin_unlock(&GlobalMid_Lock); |
705 | read_unlock(&cifs_tcp_ses_lock); | 717 | spin_unlock(&cifs_tcp_ses_lock); |
706 | /* 1/8th of sec is more than enough time for them to exit */ | 718 | /* 1/8th of sec is more than enough time for them to exit */ |
707 | msleep(125); | 719 | msleep(125); |
708 | } | 720 | } |
@@ -725,12 +737,12 @@ multi_t2_fnd: | |||
725 | if a crazy root user tried to kill cifsd | 737 | if a crazy root user tried to kill cifsd |
726 | kernel thread explicitly this might happen) */ | 738 | kernel thread explicitly this might happen) */ |
727 | /* BB: This shouldn't be necessary, see above */ | 739 | /* BB: This shouldn't be necessary, see above */ |
728 | read_lock(&cifs_tcp_ses_lock); | 740 | spin_lock(&cifs_tcp_ses_lock); |
729 | list_for_each(tmp, &server->smb_ses_list) { | 741 | list_for_each(tmp, &server->smb_ses_list) { |
730 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 742 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
731 | ses->server = NULL; | 743 | ses->server = NULL; |
732 | } | 744 | } |
733 | read_unlock(&cifs_tcp_ses_lock); | 745 | spin_unlock(&cifs_tcp_ses_lock); |
734 | 746 | ||
735 | kfree(server->hostname); | 747 | kfree(server->hostname); |
736 | task_to_wake = xchg(&server->tsk, NULL); | 748 | task_to_wake = xchg(&server->tsk, NULL); |
@@ -1046,6 +1058,22 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1046 | "long\n"); | 1058 | "long\n"); |
1047 | return 1; | 1059 | return 1; |
1048 | } | 1060 | } |
1061 | } else if (strnicmp(data, "srcaddr", 7) == 0) { | ||
1062 | vol->srcaddr.ss_family = AF_UNSPEC; | ||
1063 | |||
1064 | if (!value || !*value) { | ||
1065 | printk(KERN_WARNING "CIFS: srcaddr value" | ||
1066 | " not specified.\n"); | ||
1067 | return 1; /* needs_arg; */ | ||
1068 | } | ||
1069 | i = cifs_convert_address((struct sockaddr *)&vol->srcaddr, | ||
1070 | value, strlen(value)); | ||
1071 | if (i == 0) { | ||
1072 | printk(KERN_WARNING "CIFS: Could not parse" | ||
1073 | " srcaddr: %s\n", | ||
1074 | value); | ||
1075 | return 1; | ||
1076 | } | ||
1049 | } else if (strnicmp(data, "prefixpath", 10) == 0) { | 1077 | } else if (strnicmp(data, "prefixpath", 10) == 0) { |
1050 | if (!value || !*value) { | 1078 | if (!value || !*value) { |
1051 | printk(KERN_WARNING | 1079 | printk(KERN_WARNING |
@@ -1325,6 +1353,10 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1325 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); | 1353 | "/proc/fs/cifs/LookupCacheEnabled to 0\n"); |
1326 | } else if (strnicmp(data, "fsc", 3) == 0) { | 1354 | } else if (strnicmp(data, "fsc", 3) == 0) { |
1327 | vol->fsc = true; | 1355 | vol->fsc = true; |
1356 | } else if (strnicmp(data, "mfsymlinks", 10) == 0) { | ||
1357 | vol->mfsymlinks = true; | ||
1358 | } else if (strnicmp(data, "multiuser", 8) == 0) { | ||
1359 | vol->multiuser = true; | ||
1328 | } else | 1360 | } else |
1329 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", | 1361 | printk(KERN_WARNING "CIFS: Unknown mount option %s\n", |
1330 | data); | 1362 | data); |
@@ -1356,6 +1388,13 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1356 | return 1; | 1388 | return 1; |
1357 | } | 1389 | } |
1358 | } | 1390 | } |
1391 | |||
1392 | if (vol->multiuser && !(vol->secFlg & CIFSSEC_MAY_KRB5)) { | ||
1393 | cERROR(1, "Multiuser mounts currently require krb5 " | ||
1394 | "authentication!"); | ||
1395 | return 1; | ||
1396 | } | ||
1397 | |||
1359 | if (vol->UNCip == NULL) | 1398 | if (vol->UNCip == NULL) |
1360 | vol->UNCip = &vol->UNC[2]; | 1399 | vol->UNCip = &vol->UNC[2]; |
1361 | 1400 | ||
@@ -1374,8 +1413,36 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
1374 | return 0; | 1413 | return 0; |
1375 | } | 1414 | } |
1376 | 1415 | ||
1416 | /** Returns true if srcaddr isn't specified and rhs isn't | ||
1417 | * specified, or if srcaddr is specified and | ||
1418 | * matches the IP address of the rhs argument. | ||
1419 | */ | ||
1420 | static bool | ||
1421 | srcip_matches(struct sockaddr *srcaddr, struct sockaddr *rhs) | ||
1422 | { | ||
1423 | switch (srcaddr->sa_family) { | ||
1424 | case AF_UNSPEC: | ||
1425 | return (rhs->sa_family == AF_UNSPEC); | ||
1426 | case AF_INET: { | ||
1427 | struct sockaddr_in *saddr4 = (struct sockaddr_in *)srcaddr; | ||
1428 | struct sockaddr_in *vaddr4 = (struct sockaddr_in *)rhs; | ||
1429 | return (saddr4->sin_addr.s_addr == vaddr4->sin_addr.s_addr); | ||
1430 | } | ||
1431 | case AF_INET6: { | ||
1432 | struct sockaddr_in6 *saddr6 = (struct sockaddr_in6 *)srcaddr; | ||
1433 | struct sockaddr_in6 *vaddr6 = (struct sockaddr_in6 *)&rhs; | ||
1434 | return ipv6_addr_equal(&saddr6->sin6_addr, &vaddr6->sin6_addr); | ||
1435 | } | ||
1436 | default: | ||
1437 | WARN_ON(1); | ||
1438 | return false; /* don't expect to be here */ | ||
1439 | } | ||
1440 | } | ||
1441 | |||
1442 | |||
1377 | static bool | 1443 | static bool |
1378 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | 1444 | match_address(struct TCP_Server_Info *server, struct sockaddr *addr, |
1445 | struct sockaddr *srcaddr) | ||
1379 | { | 1446 | { |
1380 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; | 1447 | struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; |
1381 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; | 1448 | struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; |
@@ -1402,6 +1469,9 @@ match_address(struct TCP_Server_Info *server, struct sockaddr *addr) | |||
1402 | break; | 1469 | break; |
1403 | } | 1470 | } |
1404 | 1471 | ||
1472 | if (!srcip_matches(srcaddr, (struct sockaddr *)&server->srcaddr)) | ||
1473 | return false; | ||
1474 | |||
1405 | return true; | 1475 | return true; |
1406 | } | 1476 | } |
1407 | 1477 | ||
@@ -1458,29 +1528,21 @@ cifs_find_tcp_session(struct sockaddr *addr, struct smb_vol *vol) | |||
1458 | { | 1528 | { |
1459 | struct TCP_Server_Info *server; | 1529 | struct TCP_Server_Info *server; |
1460 | 1530 | ||
1461 | write_lock(&cifs_tcp_ses_lock); | 1531 | spin_lock(&cifs_tcp_ses_lock); |
1462 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { | 1532 | list_for_each_entry(server, &cifs_tcp_ses_list, tcp_ses_list) { |
1463 | /* | 1533 | if (!match_address(server, addr, |
1464 | * the demux thread can exit on its own while still in CifsNew | 1534 | (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; | 1535 | continue; |
1474 | 1536 | ||
1475 | if (!match_security(server, vol)) | 1537 | if (!match_security(server, vol)) |
1476 | continue; | 1538 | continue; |
1477 | 1539 | ||
1478 | ++server->srv_count; | 1540 | ++server->srv_count; |
1479 | write_unlock(&cifs_tcp_ses_lock); | 1541 | spin_unlock(&cifs_tcp_ses_lock); |
1480 | cFYI(1, "Existing tcp session with server found"); | 1542 | cFYI(1, "Existing tcp session with server found"); |
1481 | return server; | 1543 | return server; |
1482 | } | 1544 | } |
1483 | write_unlock(&cifs_tcp_ses_lock); | 1545 | spin_unlock(&cifs_tcp_ses_lock); |
1484 | return NULL; | 1546 | return NULL; |
1485 | } | 1547 | } |
1486 | 1548 | ||
@@ -1489,21 +1551,26 @@ cifs_put_tcp_session(struct TCP_Server_Info *server) | |||
1489 | { | 1551 | { |
1490 | struct task_struct *task; | 1552 | struct task_struct *task; |
1491 | 1553 | ||
1492 | write_lock(&cifs_tcp_ses_lock); | 1554 | spin_lock(&cifs_tcp_ses_lock); |
1493 | if (--server->srv_count > 0) { | 1555 | if (--server->srv_count > 0) { |
1494 | write_unlock(&cifs_tcp_ses_lock); | 1556 | spin_unlock(&cifs_tcp_ses_lock); |
1495 | return; | 1557 | return; |
1496 | } | 1558 | } |
1497 | 1559 | ||
1498 | list_del_init(&server->tcp_ses_list); | 1560 | list_del_init(&server->tcp_ses_list); |
1499 | write_unlock(&cifs_tcp_ses_lock); | 1561 | spin_unlock(&cifs_tcp_ses_lock); |
1500 | 1562 | ||
1501 | spin_lock(&GlobalMid_Lock); | 1563 | spin_lock(&GlobalMid_Lock); |
1502 | server->tcpStatus = CifsExiting; | 1564 | server->tcpStatus = CifsExiting; |
1503 | spin_unlock(&GlobalMid_Lock); | 1565 | spin_unlock(&GlobalMid_Lock); |
1504 | 1566 | ||
1567 | cifs_crypto_shash_release(server); | ||
1505 | cifs_fscache_release_client_cookie(server); | 1568 | cifs_fscache_release_client_cookie(server); |
1506 | 1569 | ||
1570 | kfree(server->session_key.response); | ||
1571 | server->session_key.response = NULL; | ||
1572 | server->session_key.len = 0; | ||
1573 | |||
1507 | task = xchg(&server->tsk, NULL); | 1574 | task = xchg(&server->tsk, NULL); |
1508 | if (task) | 1575 | if (task) |
1509 | force_sig(SIGKILL, task); | 1576 | force_sig(SIGKILL, task); |
@@ -1556,10 +1623,16 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1556 | goto out_err; | 1623 | goto out_err; |
1557 | } | 1624 | } |
1558 | 1625 | ||
1626 | rc = cifs_crypto_shash_allocate(tcp_ses); | ||
1627 | if (rc) { | ||
1628 | cERROR(1, "could not setup hash structures rc %d", rc); | ||
1629 | goto out_err; | ||
1630 | } | ||
1631 | |||
1559 | tcp_ses->hostname = extract_hostname(volume_info->UNC); | 1632 | tcp_ses->hostname = extract_hostname(volume_info->UNC); |
1560 | if (IS_ERR(tcp_ses->hostname)) { | 1633 | if (IS_ERR(tcp_ses->hostname)) { |
1561 | rc = PTR_ERR(tcp_ses->hostname); | 1634 | rc = PTR_ERR(tcp_ses->hostname); |
1562 | goto out_err; | 1635 | goto out_err_crypto_release; |
1563 | } | 1636 | } |
1564 | 1637 | ||
1565 | tcp_ses->noblocksnd = volume_info->noblocksnd; | 1638 | tcp_ses->noblocksnd = volume_info->noblocksnd; |
@@ -1574,6 +1647,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1574 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1647 | volume_info->source_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
1575 | memcpy(tcp_ses->server_RFC1001_name, | 1648 | memcpy(tcp_ses->server_RFC1001_name, |
1576 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); | 1649 | volume_info->target_rfc1001_name, RFC1001_NAME_LEN_WITH_NULL); |
1650 | tcp_ses->session_estab = false; | ||
1577 | tcp_ses->sequence_number = 0; | 1651 | tcp_ses->sequence_number = 0; |
1578 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); | 1652 | INIT_LIST_HEAD(&tcp_ses->tcp_ses_list); |
1579 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); | 1653 | INIT_LIST_HEAD(&tcp_ses->smb_ses_list); |
@@ -1584,6 +1658,8 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1584 | * no need to spinlock this init of tcpStatus or srv_count | 1658 | * no need to spinlock this init of tcpStatus or srv_count |
1585 | */ | 1659 | */ |
1586 | tcp_ses->tcpStatus = CifsNew; | 1660 | tcp_ses->tcpStatus = CifsNew; |
1661 | memcpy(&tcp_ses->srcaddr, &volume_info->srcaddr, | ||
1662 | sizeof(tcp_ses->srcaddr)); | ||
1587 | ++tcp_ses->srv_count; | 1663 | ++tcp_ses->srv_count; |
1588 | 1664 | ||
1589 | if (addr.ss_family == AF_INET6) { | 1665 | if (addr.ss_family == AF_INET6) { |
@@ -1600,7 +1676,7 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1600 | } | 1676 | } |
1601 | if (rc < 0) { | 1677 | if (rc < 0) { |
1602 | cERROR(1, "Error connecting to socket. Aborting operation"); | 1678 | cERROR(1, "Error connecting to socket. Aborting operation"); |
1603 | goto out_err; | 1679 | goto out_err_crypto_release; |
1604 | } | 1680 | } |
1605 | 1681 | ||
1606 | /* | 1682 | /* |
@@ -1614,18 +1690,21 @@ cifs_get_tcp_session(struct smb_vol *volume_info) | |||
1614 | rc = PTR_ERR(tcp_ses->tsk); | 1690 | rc = PTR_ERR(tcp_ses->tsk); |
1615 | cERROR(1, "error %d create cifsd thread", rc); | 1691 | cERROR(1, "error %d create cifsd thread", rc); |
1616 | module_put(THIS_MODULE); | 1692 | module_put(THIS_MODULE); |
1617 | goto out_err; | 1693 | goto out_err_crypto_release; |
1618 | } | 1694 | } |
1619 | 1695 | ||
1620 | /* thread spawned, put it on the list */ | 1696 | /* thread spawned, put it on the list */ |
1621 | write_lock(&cifs_tcp_ses_lock); | 1697 | spin_lock(&cifs_tcp_ses_lock); |
1622 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); | 1698 | list_add(&tcp_ses->tcp_ses_list, &cifs_tcp_ses_list); |
1623 | write_unlock(&cifs_tcp_ses_lock); | 1699 | spin_unlock(&cifs_tcp_ses_lock); |
1624 | 1700 | ||
1625 | cifs_fscache_get_client_cookie(tcp_ses); | 1701 | cifs_fscache_get_client_cookie(tcp_ses); |
1626 | 1702 | ||
1627 | return tcp_ses; | 1703 | return tcp_ses; |
1628 | 1704 | ||
1705 | out_err_crypto_release: | ||
1706 | cifs_crypto_shash_release(tcp_ses); | ||
1707 | |||
1629 | out_err: | 1708 | out_err: |
1630 | if (tcp_ses) { | 1709 | if (tcp_ses) { |
1631 | if (!IS_ERR(tcp_ses->hostname)) | 1710 | if (!IS_ERR(tcp_ses->hostname)) |
@@ -1642,7 +1721,7 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1642 | { | 1721 | { |
1643 | struct cifsSesInfo *ses; | 1722 | struct cifsSesInfo *ses; |
1644 | 1723 | ||
1645 | write_lock(&cifs_tcp_ses_lock); | 1724 | spin_lock(&cifs_tcp_ses_lock); |
1646 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { | 1725 | list_for_each_entry(ses, &server->smb_ses_list, smb_ses_list) { |
1647 | switch (server->secType) { | 1726 | switch (server->secType) { |
1648 | case Kerberos: | 1727 | case Kerberos: |
@@ -1662,10 +1741,10 @@ cifs_find_smb_ses(struct TCP_Server_Info *server, struct smb_vol *vol) | |||
1662 | continue; | 1741 | continue; |
1663 | } | 1742 | } |
1664 | ++ses->ses_count; | 1743 | ++ses->ses_count; |
1665 | write_unlock(&cifs_tcp_ses_lock); | 1744 | spin_unlock(&cifs_tcp_ses_lock); |
1666 | return ses; | 1745 | return ses; |
1667 | } | 1746 | } |
1668 | write_unlock(&cifs_tcp_ses_lock); | 1747 | spin_unlock(&cifs_tcp_ses_lock); |
1669 | return NULL; | 1748 | return NULL; |
1670 | } | 1749 | } |
1671 | 1750 | ||
@@ -1676,14 +1755,14 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) | |||
1676 | struct TCP_Server_Info *server = ses->server; | 1755 | struct TCP_Server_Info *server = ses->server; |
1677 | 1756 | ||
1678 | cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count); | 1757 | cFYI(1, "%s: ses_count=%d\n", __func__, ses->ses_count); |
1679 | write_lock(&cifs_tcp_ses_lock); | 1758 | spin_lock(&cifs_tcp_ses_lock); |
1680 | if (--ses->ses_count > 0) { | 1759 | if (--ses->ses_count > 0) { |
1681 | write_unlock(&cifs_tcp_ses_lock); | 1760 | spin_unlock(&cifs_tcp_ses_lock); |
1682 | return; | 1761 | return; |
1683 | } | 1762 | } |
1684 | 1763 | ||
1685 | list_del_init(&ses->smb_ses_list); | 1764 | list_del_init(&ses->smb_ses_list); |
1686 | write_unlock(&cifs_tcp_ses_lock); | 1765 | spin_unlock(&cifs_tcp_ses_lock); |
1687 | 1766 | ||
1688 | if (ses->status == CifsGood) { | 1767 | if (ses->status == CifsGood) { |
1689 | xid = GetXid(); | 1768 | xid = GetXid(); |
@@ -1760,10 +1839,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1760 | goto get_ses_fail; | 1839 | goto get_ses_fail; |
1761 | } | 1840 | } |
1762 | if (volume_info->domainname) { | 1841 | if (volume_info->domainname) { |
1763 | int len = strlen(volume_info->domainname); | 1842 | ses->domainName = kstrdup(volume_info->domainname, GFP_KERNEL); |
1764 | ses->domainName = kmalloc(len + 1, GFP_KERNEL); | 1843 | if (!ses->domainName) |
1765 | if (ses->domainName) | 1844 | goto get_ses_fail; |
1766 | strcpy(ses->domainName, volume_info->domainname); | ||
1767 | } | 1845 | } |
1768 | ses->cred_uid = volume_info->cred_uid; | 1846 | ses->cred_uid = volume_info->cred_uid; |
1769 | ses->linux_uid = volume_info->linux_uid; | 1847 | ses->linux_uid = volume_info->linux_uid; |
@@ -1778,9 +1856,9 @@ cifs_get_smb_ses(struct TCP_Server_Info *server, struct smb_vol *volume_info) | |||
1778 | goto get_ses_fail; | 1856 | goto get_ses_fail; |
1779 | 1857 | ||
1780 | /* success, put it on the list */ | 1858 | /* success, put it on the list */ |
1781 | write_lock(&cifs_tcp_ses_lock); | 1859 | spin_lock(&cifs_tcp_ses_lock); |
1782 | list_add(&ses->smb_ses_list, &server->smb_ses_list); | 1860 | list_add(&ses->smb_ses_list, &server->smb_ses_list); |
1783 | write_unlock(&cifs_tcp_ses_lock); | 1861 | spin_unlock(&cifs_tcp_ses_lock); |
1784 | 1862 | ||
1785 | FreeXid(xid); | 1863 | FreeXid(xid); |
1786 | return ses; | 1864 | return ses; |
@@ -1797,7 +1875,7 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) | |||
1797 | struct list_head *tmp; | 1875 | struct list_head *tmp; |
1798 | struct cifsTconInfo *tcon; | 1876 | struct cifsTconInfo *tcon; |
1799 | 1877 | ||
1800 | write_lock(&cifs_tcp_ses_lock); | 1878 | spin_lock(&cifs_tcp_ses_lock); |
1801 | list_for_each(tmp, &ses->tcon_list) { | 1879 | list_for_each(tmp, &ses->tcon_list) { |
1802 | tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); | 1880 | tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); |
1803 | if (tcon->tidStatus == CifsExiting) | 1881 | if (tcon->tidStatus == CifsExiting) |
@@ -1806,10 +1884,10 @@ cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) | |||
1806 | continue; | 1884 | continue; |
1807 | 1885 | ||
1808 | ++tcon->tc_count; | 1886 | ++tcon->tc_count; |
1809 | write_unlock(&cifs_tcp_ses_lock); | 1887 | spin_unlock(&cifs_tcp_ses_lock); |
1810 | return tcon; | 1888 | return tcon; |
1811 | } | 1889 | } |
1812 | write_unlock(&cifs_tcp_ses_lock); | 1890 | spin_unlock(&cifs_tcp_ses_lock); |
1813 | return NULL; | 1891 | return NULL; |
1814 | } | 1892 | } |
1815 | 1893 | ||
@@ -1820,14 +1898,14 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1820 | struct cifsSesInfo *ses = tcon->ses; | 1898 | struct cifsSesInfo *ses = tcon->ses; |
1821 | 1899 | ||
1822 | cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); | 1900 | cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); |
1823 | write_lock(&cifs_tcp_ses_lock); | 1901 | spin_lock(&cifs_tcp_ses_lock); |
1824 | if (--tcon->tc_count > 0) { | 1902 | if (--tcon->tc_count > 0) { |
1825 | write_unlock(&cifs_tcp_ses_lock); | 1903 | spin_unlock(&cifs_tcp_ses_lock); |
1826 | return; | 1904 | return; |
1827 | } | 1905 | } |
1828 | 1906 | ||
1829 | list_del_init(&tcon->tcon_list); | 1907 | list_del_init(&tcon->tcon_list); |
1830 | write_unlock(&cifs_tcp_ses_lock); | 1908 | spin_unlock(&cifs_tcp_ses_lock); |
1831 | 1909 | ||
1832 | xid = GetXid(); | 1910 | xid = GetXid(); |
1833 | CIFSSMBTDis(xid, tcon); | 1911 | CIFSSMBTDis(xid, tcon); |
@@ -1900,9 +1978,9 @@ cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | |||
1900 | tcon->nocase = volume_info->nocase; | 1978 | tcon->nocase = volume_info->nocase; |
1901 | tcon->local_lease = volume_info->local_lease; | 1979 | tcon->local_lease = volume_info->local_lease; |
1902 | 1980 | ||
1903 | write_lock(&cifs_tcp_ses_lock); | 1981 | spin_lock(&cifs_tcp_ses_lock); |
1904 | list_add(&tcon->tcon_list, &ses->tcon_list); | 1982 | list_add(&tcon->tcon_list, &ses->tcon_list); |
1905 | write_unlock(&cifs_tcp_ses_lock); | 1983 | spin_unlock(&cifs_tcp_ses_lock); |
1906 | 1984 | ||
1907 | cifs_fscache_get_super_cookie(tcon); | 1985 | cifs_fscache_get_super_cookie(tcon); |
1908 | 1986 | ||
@@ -1913,6 +1991,23 @@ out_fail: | |||
1913 | return ERR_PTR(rc); | 1991 | return ERR_PTR(rc); |
1914 | } | 1992 | } |
1915 | 1993 | ||
1994 | void | ||
1995 | cifs_put_tlink(struct tcon_link *tlink) | ||
1996 | { | ||
1997 | if (!tlink || IS_ERR(tlink)) | ||
1998 | return; | ||
1999 | |||
2000 | if (!atomic_dec_and_test(&tlink->tl_count) || | ||
2001 | test_bit(TCON_LINK_IN_TREE, &tlink->tl_flags)) { | ||
2002 | tlink->tl_time = jiffies; | ||
2003 | return; | ||
2004 | } | ||
2005 | |||
2006 | if (!IS_ERR(tlink_tcon(tlink))) | ||
2007 | cifs_put_tcon(tlink_tcon(tlink)); | ||
2008 | kfree(tlink); | ||
2009 | return; | ||
2010 | } | ||
1916 | 2011 | ||
1917 | int | 2012 | int |
1918 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 2013 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, |
@@ -1997,6 +2092,33 @@ static void rfc1002mangle(char *target, char *source, unsigned int length) | |||
1997 | 2092 | ||
1998 | } | 2093 | } |
1999 | 2094 | ||
2095 | static int | ||
2096 | bind_socket(struct TCP_Server_Info *server) | ||
2097 | { | ||
2098 | int rc = 0; | ||
2099 | if (server->srcaddr.ss_family != AF_UNSPEC) { | ||
2100 | /* Bind to the specified local IP address */ | ||
2101 | struct socket *socket = server->ssocket; | ||
2102 | rc = socket->ops->bind(socket, | ||
2103 | (struct sockaddr *) &server->srcaddr, | ||
2104 | sizeof(server->srcaddr)); | ||
2105 | if (rc < 0) { | ||
2106 | struct sockaddr_in *saddr4; | ||
2107 | struct sockaddr_in6 *saddr6; | ||
2108 | saddr4 = (struct sockaddr_in *)&server->srcaddr; | ||
2109 | saddr6 = (struct sockaddr_in6 *)&server->srcaddr; | ||
2110 | if (saddr6->sin6_family == AF_INET6) | ||
2111 | cERROR(1, "cifs: " | ||
2112 | "Failed to bind to: %pI6c, error: %d\n", | ||
2113 | &saddr6->sin6_addr, rc); | ||
2114 | else | ||
2115 | cERROR(1, "cifs: " | ||
2116 | "Failed to bind to: %pI4, error: %d\n", | ||
2117 | &saddr4->sin_addr.s_addr, rc); | ||
2118 | } | ||
2119 | } | ||
2120 | return rc; | ||
2121 | } | ||
2000 | 2122 | ||
2001 | static int | 2123 | static int |
2002 | ipv4_connect(struct TCP_Server_Info *server) | 2124 | ipv4_connect(struct TCP_Server_Info *server) |
@@ -2022,6 +2144,10 @@ ipv4_connect(struct TCP_Server_Info *server) | |||
2022 | cifs_reclassify_socket4(socket); | 2144 | cifs_reclassify_socket4(socket); |
2023 | } | 2145 | } |
2024 | 2146 | ||
2147 | rc = bind_socket(server); | ||
2148 | if (rc < 0) | ||
2149 | return rc; | ||
2150 | |||
2025 | /* user overrode default port */ | 2151 | /* user overrode default port */ |
2026 | if (server->addr.sockAddr.sin_port) { | 2152 | if (server->addr.sockAddr.sin_port) { |
2027 | rc = socket->ops->connect(socket, (struct sockaddr *) | 2153 | rc = socket->ops->connect(socket, (struct sockaddr *) |
@@ -2184,6 +2310,10 @@ ipv6_connect(struct TCP_Server_Info *server) | |||
2184 | cifs_reclassify_socket6(socket); | 2310 | cifs_reclassify_socket6(socket); |
2185 | } | 2311 | } |
2186 | 2312 | ||
2313 | rc = bind_socket(server); | ||
2314 | if (rc < 0) | ||
2315 | return rc; | ||
2316 | |||
2187 | /* user overrode default port */ | 2317 | /* user overrode default port */ |
2188 | if (server->addr.sockAddr6.sin6_port) { | 2318 | if (server->addr.sockAddr6.sin6_port) { |
2189 | rc = socket->ops->connect(socket, | 2319 | rc = socket->ops->connect(socket, |
@@ -2383,6 +2513,8 @@ convert_delimiter(char *path, char delim) | |||
2383 | static void setup_cifs_sb(struct smb_vol *pvolume_info, | 2513 | static void setup_cifs_sb(struct smb_vol *pvolume_info, |
2384 | struct cifs_sb_info *cifs_sb) | 2514 | struct cifs_sb_info *cifs_sb) |
2385 | { | 2515 | { |
2516 | INIT_DELAYED_WORK(&cifs_sb->prune_tlinks, cifs_prune_tlinks); | ||
2517 | |||
2386 | if (pvolume_info->rsize > CIFSMaxBufSize) { | 2518 | if (pvolume_info->rsize > CIFSMaxBufSize) { |
2387 | cERROR(1, "rsize %d too large, using MaxBufSize", | 2519 | cERROR(1, "rsize %d too large, using MaxBufSize", |
2388 | pvolume_info->rsize); | 2520 | pvolume_info->rsize); |
@@ -2462,10 +2594,21 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info, | |||
2462 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | 2594 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; |
2463 | if (pvolume_info->fsc) | 2595 | if (pvolume_info->fsc) |
2464 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; | 2596 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_FSCACHE; |
2597 | if (pvolume_info->multiuser) | ||
2598 | cifs_sb->mnt_cifs_flags |= (CIFS_MOUNT_MULTIUSER | | ||
2599 | CIFS_MOUNT_NO_PERM); | ||
2465 | if (pvolume_info->direct_io) { | 2600 | if (pvolume_info->direct_io) { |
2466 | cFYI(1, "mounting share using direct i/o"); | 2601 | cFYI(1, "mounting share using direct i/o"); |
2467 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | 2602 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; |
2468 | } | 2603 | } |
2604 | if (pvolume_info->mfsymlinks) { | ||
2605 | if (pvolume_info->sfu_emul) { | ||
2606 | cERROR(1, "mount option mfsymlinks ignored if sfu " | ||
2607 | "mount option is used"); | ||
2608 | } else { | ||
2609 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MF_SYMLINKS; | ||
2610 | } | ||
2611 | } | ||
2469 | 2612 | ||
2470 | if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) | 2613 | if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) |
2471 | cERROR(1, "mount option dynperm ignored if cifsacl " | 2614 | cERROR(1, "mount option dynperm ignored if cifsacl " |
@@ -2552,6 +2695,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
2552 | struct TCP_Server_Info *srvTcp; | 2695 | struct TCP_Server_Info *srvTcp; |
2553 | char *full_path; | 2696 | char *full_path; |
2554 | char *mount_data = mount_data_global; | 2697 | char *mount_data = mount_data_global; |
2698 | struct tcon_link *tlink; | ||
2555 | #ifdef CONFIG_CIFS_DFS_UPCALL | 2699 | #ifdef CONFIG_CIFS_DFS_UPCALL |
2556 | struct dfs_info3_param *referrals = NULL; | 2700 | struct dfs_info3_param *referrals = NULL; |
2557 | unsigned int num_referrals = 0; | 2701 | unsigned int num_referrals = 0; |
@@ -2563,6 +2707,7 @@ try_mount_again: | |||
2563 | pSesInfo = NULL; | 2707 | pSesInfo = NULL; |
2564 | srvTcp = NULL; | 2708 | srvTcp = NULL; |
2565 | full_path = NULL; | 2709 | full_path = NULL; |
2710 | tlink = NULL; | ||
2566 | 2711 | ||
2567 | xid = GetXid(); | 2712 | xid = GetXid(); |
2568 | 2713 | ||
@@ -2638,8 +2783,6 @@ try_mount_again: | |||
2638 | goto remote_path_check; | 2783 | goto remote_path_check; |
2639 | } | 2784 | } |
2640 | 2785 | ||
2641 | cifs_sb->tcon = tcon; | ||
2642 | |||
2643 | /* do not care if following two calls succeed - informational */ | 2786 | /* do not care if following two calls succeed - informational */ |
2644 | if (!tcon->ipc) { | 2787 | if (!tcon->ipc) { |
2645 | CIFSSMBQFSDeviceInfo(xid, tcon); | 2788 | CIFSSMBQFSDeviceInfo(xid, tcon); |
@@ -2748,6 +2891,30 @@ remote_path_check: | |||
2748 | #endif | 2891 | #endif |
2749 | } | 2892 | } |
2750 | 2893 | ||
2894 | if (rc) | ||
2895 | goto mount_fail_check; | ||
2896 | |||
2897 | /* now, hang the tcon off of the superblock */ | ||
2898 | tlink = kzalloc(sizeof *tlink, GFP_KERNEL); | ||
2899 | if (tlink == NULL) { | ||
2900 | rc = -ENOMEM; | ||
2901 | goto mount_fail_check; | ||
2902 | } | ||
2903 | |||
2904 | tlink->tl_uid = pSesInfo->linux_uid; | ||
2905 | tlink->tl_tcon = tcon; | ||
2906 | tlink->tl_time = jiffies; | ||
2907 | set_bit(TCON_LINK_MASTER, &tlink->tl_flags); | ||
2908 | set_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | ||
2909 | |||
2910 | cifs_sb->master_tlink = tlink; | ||
2911 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
2912 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
2913 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
2914 | |||
2915 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | ||
2916 | TLINK_IDLE_EXPIRE); | ||
2917 | |||
2751 | mount_fail_check: | 2918 | mount_fail_check: |
2752 | /* on error free sesinfo and tcon struct if needed */ | 2919 | /* on error free sesinfo and tcon struct if needed */ |
2753 | if (rc) { | 2920 | if (rc) { |
@@ -2825,14 +2992,13 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2825 | #ifdef CONFIG_CIFS_WEAK_PW_HASH | 2992 | #ifdef CONFIG_CIFS_WEAK_PW_HASH |
2826 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && | 2993 | if ((global_secflags & CIFSSEC_MAY_LANMAN) && |
2827 | (ses->server->secType == LANMAN)) | 2994 | (ses->server->secType == LANMAN)) |
2828 | calc_lanman_hash(tcon->password, ses->server->cryptKey, | 2995 | calc_lanman_hash(tcon->password, ses->server->cryptkey, |
2829 | ses->server->secMode & | 2996 | ses->server->secMode & |
2830 | SECMODE_PW_ENCRYPT ? true : false, | 2997 | SECMODE_PW_ENCRYPT ? true : false, |
2831 | bcc_ptr); | 2998 | bcc_ptr); |
2832 | else | 2999 | else |
2833 | #endif /* CIFS_WEAK_PW_HASH */ | 3000 | #endif /* CIFS_WEAK_PW_HASH */ |
2834 | SMBNTencrypt(tcon->password, ses->server->cryptKey, | 3001 | SMBNTencrypt(tcon->password, ses->server->cryptkey, bcc_ptr); |
2835 | bcc_ptr); | ||
2836 | 3002 | ||
2837 | bcc_ptr += CIFS_SESS_KEY_SIZE; | 3003 | bcc_ptr += CIFS_SESS_KEY_SIZE; |
2838 | if (ses->capabilities & CAP_UNICODE) { | 3004 | if (ses->capabilities & CAP_UNICODE) { |
@@ -2934,19 +3100,32 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
2934 | int | 3100 | int |
2935 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3101 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) |
2936 | { | 3102 | { |
2937 | int rc = 0; | 3103 | struct rb_root *root = &cifs_sb->tlink_tree; |
3104 | struct rb_node *node; | ||
3105 | struct tcon_link *tlink; | ||
2938 | char *tmp; | 3106 | char *tmp; |
2939 | 3107 | ||
2940 | if (cifs_sb->tcon) | 3108 | cancel_delayed_work_sync(&cifs_sb->prune_tlinks); |
2941 | cifs_put_tcon(cifs_sb->tcon); | 3109 | |
3110 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3111 | while ((node = rb_first(root))) { | ||
3112 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | ||
3113 | cifs_get_tlink(tlink); | ||
3114 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | ||
3115 | rb_erase(node, root); | ||
3116 | |||
3117 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3118 | cifs_put_tlink(tlink); | ||
3119 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3120 | } | ||
3121 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
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 | ||
2952 | int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) | 3131 | int cifs_negotiate_protocol(unsigned int xid, struct cifsSesInfo *ses) |
@@ -2997,6 +3176,16 @@ 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 | server->session_key.response = ses->auth_key.response; | ||
3182 | server->session_key.len = ses->auth_key.len; | ||
3183 | server->sequence_number = 0x2; | ||
3184 | server->session_estab = true; | ||
3185 | ses->auth_key.response = NULL; | ||
3186 | } | ||
3187 | mutex_unlock(&server->srv_mutex); | ||
3188 | |||
3000 | cFYI(1, "CIFS Session Established successfully"); | 3189 | cFYI(1, "CIFS Session Established successfully"); |
3001 | spin_lock(&GlobalMid_Lock); | 3190 | spin_lock(&GlobalMid_Lock); |
3002 | ses->status = CifsGood; | 3191 | ses->status = CifsGood; |
@@ -3004,6 +3193,263 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *ses, | |||
3004 | spin_unlock(&GlobalMid_Lock); | 3193 | spin_unlock(&GlobalMid_Lock); |
3005 | } | 3194 | } |
3006 | 3195 | ||
3196 | kfree(ses->auth_key.response); | ||
3197 | ses->auth_key.response = NULL; | ||
3198 | ses->auth_key.len = 0; | ||
3199 | kfree(ses->ntlmssp); | ||
3200 | ses->ntlmssp = NULL; | ||
3201 | |||
3007 | return rc; | 3202 | return rc; |
3008 | } | 3203 | } |
3009 | 3204 | ||
3205 | static struct cifsTconInfo * | ||
3206 | cifs_construct_tcon(struct cifs_sb_info *cifs_sb, uid_t fsuid) | ||
3207 | { | ||
3208 | struct cifsTconInfo *master_tcon = cifs_sb_master_tcon(cifs_sb); | ||
3209 | struct cifsSesInfo *ses; | ||
3210 | struct cifsTconInfo *tcon = NULL; | ||
3211 | struct smb_vol *vol_info; | ||
3212 | char username[MAX_USERNAME_SIZE + 1]; | ||
3213 | |||
3214 | vol_info = kzalloc(sizeof(*vol_info), GFP_KERNEL); | ||
3215 | if (vol_info == NULL) { | ||
3216 | tcon = ERR_PTR(-ENOMEM); | ||
3217 | goto out; | ||
3218 | } | ||
3219 | |||
3220 | snprintf(username, MAX_USERNAME_SIZE, "krb50x%x", fsuid); | ||
3221 | vol_info->username = username; | ||
3222 | vol_info->local_nls = cifs_sb->local_nls; | ||
3223 | vol_info->linux_uid = fsuid; | ||
3224 | vol_info->cred_uid = fsuid; | ||
3225 | vol_info->UNC = master_tcon->treeName; | ||
3226 | vol_info->retry = master_tcon->retry; | ||
3227 | vol_info->nocase = master_tcon->nocase; | ||
3228 | vol_info->local_lease = master_tcon->local_lease; | ||
3229 | vol_info->no_linux_ext = !master_tcon->unix_ext; | ||
3230 | |||
3231 | /* FIXME: allow for other secFlg settings */ | ||
3232 | vol_info->secFlg = CIFSSEC_MUST_KRB5; | ||
3233 | |||
3234 | /* get a reference for the same TCP session */ | ||
3235 | spin_lock(&cifs_tcp_ses_lock); | ||
3236 | ++master_tcon->ses->server->srv_count; | ||
3237 | spin_unlock(&cifs_tcp_ses_lock); | ||
3238 | |||
3239 | ses = cifs_get_smb_ses(master_tcon->ses->server, vol_info); | ||
3240 | if (IS_ERR(ses)) { | ||
3241 | tcon = (struct cifsTconInfo *)ses; | ||
3242 | cifs_put_tcp_session(master_tcon->ses->server); | ||
3243 | goto out; | ||
3244 | } | ||
3245 | |||
3246 | tcon = cifs_get_tcon(ses, vol_info); | ||
3247 | if (IS_ERR(tcon)) { | ||
3248 | cifs_put_smb_ses(ses); | ||
3249 | goto out; | ||
3250 | } | ||
3251 | |||
3252 | if (ses->capabilities & CAP_UNIX) | ||
3253 | reset_cifs_unix_caps(0, tcon, NULL, vol_info); | ||
3254 | out: | ||
3255 | kfree(vol_info); | ||
3256 | |||
3257 | return tcon; | ||
3258 | } | ||
3259 | |||
3260 | static inline struct tcon_link * | ||
3261 | cifs_sb_master_tlink(struct cifs_sb_info *cifs_sb) | ||
3262 | { | ||
3263 | return cifs_sb->master_tlink; | ||
3264 | } | ||
3265 | |||
3266 | struct cifsTconInfo * | ||
3267 | cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb) | ||
3268 | { | ||
3269 | return tlink_tcon(cifs_sb_master_tlink(cifs_sb)); | ||
3270 | } | ||
3271 | |||
3272 | static int | ||
3273 | cifs_sb_tcon_pending_wait(void *unused) | ||
3274 | { | ||
3275 | schedule(); | ||
3276 | return signal_pending(current) ? -ERESTARTSYS : 0; | ||
3277 | } | ||
3278 | |||
3279 | /* find and return a tlink with given uid */ | ||
3280 | static struct tcon_link * | ||
3281 | tlink_rb_search(struct rb_root *root, uid_t uid) | ||
3282 | { | ||
3283 | struct rb_node *node = root->rb_node; | ||
3284 | struct tcon_link *tlink; | ||
3285 | |||
3286 | while (node) { | ||
3287 | tlink = rb_entry(node, struct tcon_link, tl_rbnode); | ||
3288 | |||
3289 | if (tlink->tl_uid > uid) | ||
3290 | node = node->rb_left; | ||
3291 | else if (tlink->tl_uid < uid) | ||
3292 | node = node->rb_right; | ||
3293 | else | ||
3294 | return tlink; | ||
3295 | } | ||
3296 | return NULL; | ||
3297 | } | ||
3298 | |||
3299 | /* insert a tcon_link into the tree */ | ||
3300 | static void | ||
3301 | tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tlink) | ||
3302 | { | ||
3303 | struct rb_node **new = &(root->rb_node), *parent = NULL; | ||
3304 | struct tcon_link *tlink; | ||
3305 | |||
3306 | while (*new) { | ||
3307 | tlink = rb_entry(*new, struct tcon_link, tl_rbnode); | ||
3308 | parent = *new; | ||
3309 | |||
3310 | if (tlink->tl_uid > new_tlink->tl_uid) | ||
3311 | new = &((*new)->rb_left); | ||
3312 | else | ||
3313 | new = &((*new)->rb_right); | ||
3314 | } | ||
3315 | |||
3316 | rb_link_node(&new_tlink->tl_rbnode, parent, new); | ||
3317 | rb_insert_color(&new_tlink->tl_rbnode, root); | ||
3318 | } | ||
3319 | |||
3320 | /* | ||
3321 | * Find or construct an appropriate tcon given a cifs_sb and the fsuid of the | ||
3322 | * current task. | ||
3323 | * | ||
3324 | * If the superblock doesn't refer to a multiuser mount, then just return | ||
3325 | * the master tcon for the mount. | ||
3326 | * | ||
3327 | * First, search the rbtree for an existing tcon for this fsuid. If one | ||
3328 | * exists, then check to see if it's pending construction. If it is then wait | ||
3329 | * for construction to complete. Once it's no longer pending, check to see if | ||
3330 | * it failed and either return an error or retry construction, depending on | ||
3331 | * the timeout. | ||
3332 | * | ||
3333 | * If one doesn't exist then insert a new tcon_link struct into the tree and | ||
3334 | * try to construct a new one. | ||
3335 | */ | ||
3336 | struct tcon_link * | ||
3337 | cifs_sb_tlink(struct cifs_sb_info *cifs_sb) | ||
3338 | { | ||
3339 | int ret; | ||
3340 | uid_t fsuid = current_fsuid(); | ||
3341 | struct tcon_link *tlink, *newtlink; | ||
3342 | |||
3343 | if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MULTIUSER)) | ||
3344 | return cifs_get_tlink(cifs_sb_master_tlink(cifs_sb)); | ||
3345 | |||
3346 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3347 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); | ||
3348 | if (tlink) | ||
3349 | cifs_get_tlink(tlink); | ||
3350 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3351 | |||
3352 | if (tlink == NULL) { | ||
3353 | newtlink = kzalloc(sizeof(*tlink), GFP_KERNEL); | ||
3354 | if (newtlink == NULL) | ||
3355 | return ERR_PTR(-ENOMEM); | ||
3356 | newtlink->tl_uid = fsuid; | ||
3357 | newtlink->tl_tcon = ERR_PTR(-EACCES); | ||
3358 | set_bit(TCON_LINK_PENDING, &newtlink->tl_flags); | ||
3359 | set_bit(TCON_LINK_IN_TREE, &newtlink->tl_flags); | ||
3360 | cifs_get_tlink(newtlink); | ||
3361 | |||
3362 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3363 | /* was one inserted after previous search? */ | ||
3364 | tlink = tlink_rb_search(&cifs_sb->tlink_tree, fsuid); | ||
3365 | if (tlink) { | ||
3366 | cifs_get_tlink(tlink); | ||
3367 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3368 | kfree(newtlink); | ||
3369 | goto wait_for_construction; | ||
3370 | } | ||
3371 | tlink = newtlink; | ||
3372 | tlink_rb_insert(&cifs_sb->tlink_tree, tlink); | ||
3373 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3374 | } else { | ||
3375 | wait_for_construction: | ||
3376 | ret = wait_on_bit(&tlink->tl_flags, TCON_LINK_PENDING, | ||
3377 | cifs_sb_tcon_pending_wait, | ||
3378 | TASK_INTERRUPTIBLE); | ||
3379 | if (ret) { | ||
3380 | cifs_put_tlink(tlink); | ||
3381 | return ERR_PTR(ret); | ||
3382 | } | ||
3383 | |||
3384 | /* if it's good, return it */ | ||
3385 | if (!IS_ERR(tlink->tl_tcon)) | ||
3386 | return tlink; | ||
3387 | |||
3388 | /* return error if we tried this already recently */ | ||
3389 | if (time_before(jiffies, tlink->tl_time + TLINK_ERROR_EXPIRE)) { | ||
3390 | cifs_put_tlink(tlink); | ||
3391 | return ERR_PTR(-EACCES); | ||
3392 | } | ||
3393 | |||
3394 | if (test_and_set_bit(TCON_LINK_PENDING, &tlink->tl_flags)) | ||
3395 | goto wait_for_construction; | ||
3396 | } | ||
3397 | |||
3398 | tlink->tl_tcon = cifs_construct_tcon(cifs_sb, fsuid); | ||
3399 | clear_bit(TCON_LINK_PENDING, &tlink->tl_flags); | ||
3400 | wake_up_bit(&tlink->tl_flags, TCON_LINK_PENDING); | ||
3401 | |||
3402 | if (IS_ERR(tlink->tl_tcon)) { | ||
3403 | cifs_put_tlink(tlink); | ||
3404 | return ERR_PTR(-EACCES); | ||
3405 | } | ||
3406 | |||
3407 | return tlink; | ||
3408 | } | ||
3409 | |||
3410 | /* | ||
3411 | * periodic workqueue job that scans tcon_tree for a superblock and closes | ||
3412 | * out tcons. | ||
3413 | */ | ||
3414 | static void | ||
3415 | cifs_prune_tlinks(struct work_struct *work) | ||
3416 | { | ||
3417 | struct cifs_sb_info *cifs_sb = container_of(work, struct cifs_sb_info, | ||
3418 | prune_tlinks.work); | ||
3419 | struct rb_root *root = &cifs_sb->tlink_tree; | ||
3420 | struct rb_node *node = rb_first(root); | ||
3421 | struct rb_node *tmp; | ||
3422 | struct tcon_link *tlink; | ||
3423 | |||
3424 | /* | ||
3425 | * Because we drop the spinlock in the loop in order to put the tlink | ||
3426 | * it's not guarded against removal of links from the tree. The only | ||
3427 | * places that remove entries from the tree are this function and | ||
3428 | * umounts. Because this function is non-reentrant and is canceled | ||
3429 | * before umount can proceed, this is safe. | ||
3430 | */ | ||
3431 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3432 | node = rb_first(root); | ||
3433 | while (node != NULL) { | ||
3434 | tmp = node; | ||
3435 | node = rb_next(tmp); | ||
3436 | tlink = rb_entry(tmp, struct tcon_link, tl_rbnode); | ||
3437 | |||
3438 | if (test_bit(TCON_LINK_MASTER, &tlink->tl_flags) || | ||
3439 | atomic_read(&tlink->tl_count) != 0 || | ||
3440 | time_after(tlink->tl_time + TLINK_IDLE_EXPIRE, jiffies)) | ||
3441 | continue; | ||
3442 | |||
3443 | cifs_get_tlink(tlink); | ||
3444 | clear_bit(TCON_LINK_IN_TREE, &tlink->tl_flags); | ||
3445 | rb_erase(tmp, root); | ||
3446 | |||
3447 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3448 | cifs_put_tlink(tlink); | ||
3449 | spin_lock(&cifs_sb->tlink_tree_lock); | ||
3450 | } | ||
3451 | spin_unlock(&cifs_sb->tlink_tree_lock); | ||
3452 | |||
3453 | queue_delayed_work(system_nrt_wq, &cifs_sb->prune_tlinks, | ||
3454 | TLINK_IDLE_EXPIRE); | ||
3455 | } | ||