diff options
Diffstat (limited to 'fs/cifs/connect.c')
| -rw-r--r-- | fs/cifs/connect.c | 825 |
1 files changed, 411 insertions, 414 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index e9f9248cb3fe..c7d341714586 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
| @@ -124,7 +124,7 @@ static int | |||
| 124 | cifs_reconnect(struct TCP_Server_Info *server) | 124 | cifs_reconnect(struct TCP_Server_Info *server) |
| 125 | { | 125 | { |
| 126 | int rc = 0; | 126 | int rc = 0; |
| 127 | struct list_head *tmp; | 127 | struct list_head *tmp, *tmp2; |
| 128 | struct cifsSesInfo *ses; | 128 | struct cifsSesInfo *ses; |
| 129 | struct cifsTconInfo *tcon; | 129 | struct cifsTconInfo *tcon; |
| 130 | struct mid_q_entry *mid_entry; | 130 | struct mid_q_entry *mid_entry; |
| @@ -144,23 +144,17 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 144 | 144 | ||
| 145 | /* before reconnecting the tcp session, mark the smb session (uid) | 145 | /* before reconnecting the tcp session, mark the smb session (uid) |
| 146 | and the tid bad so they are not used until reconnected */ | 146 | and the tid bad so they are not used until reconnected */ |
| 147 | read_lock(&GlobalSMBSeslock); | 147 | read_lock(&cifs_tcp_ses_lock); |
| 148 | list_for_each(tmp, &GlobalSMBSessionList) { | 148 | list_for_each(tmp, &server->smb_ses_list) { |
| 149 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | 149 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| 150 | if (ses->server) { | 150 | ses->need_reconnect = true; |
| 151 | if (ses->server == server) { | 151 | ses->ipc_tid = 0; |
| 152 | ses->status = CifsNeedReconnect; | 152 | list_for_each(tmp2, &ses->tcon_list) { |
| 153 | ses->ipc_tid = 0; | 153 | tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list); |
| 154 | } | 154 | tcon->need_reconnect = true; |
| 155 | } | 155 | } |
| 156 | /* else tcp and smb sessions need reconnection */ | ||
| 157 | } | ||
| 158 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
| 159 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
| 160 | if ((tcon->ses) && (tcon->ses->server == server)) | ||
| 161 | tcon->tidStatus = CifsNeedReconnect; | ||
| 162 | } | 156 | } |
| 163 | read_unlock(&GlobalSMBSeslock); | 157 | read_unlock(&cifs_tcp_ses_lock); |
| 164 | /* 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 */ |
| 165 | down(&server->tcpSem); | 159 | down(&server->tcpSem); |
| 166 | if (server->ssocket) { | 160 | if (server->ssocket) { |
| @@ -193,7 +187,7 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 193 | while ((server->tcpStatus != CifsExiting) && | 187 | while ((server->tcpStatus != CifsExiting) && |
| 194 | (server->tcpStatus != CifsGood)) { | 188 | (server->tcpStatus != CifsGood)) { |
| 195 | try_to_freeze(); | 189 | try_to_freeze(); |
| 196 | if (server->protocolType == IPV6) { | 190 | if (server->addr.sockAddr6.sin6_family == AF_INET6) { |
| 197 | rc = ipv6_connect(&server->addr.sockAddr6, | 191 | rc = ipv6_connect(&server->addr.sockAddr6, |
| 198 | &server->ssocket, server->noautotune); | 192 | &server->ssocket, server->noautotune); |
| 199 | } else { | 193 | } else { |
| @@ -417,9 +411,14 @@ incomplete_rcv: | |||
| 417 | msleep(1); /* minimum sleep to prevent looping | 411 | msleep(1); /* minimum sleep to prevent looping |
| 418 | allowing socket to clear and app threads to set | 412 | allowing socket to clear and app threads to set |
| 419 | tcpStatus CifsNeedReconnect if server hung */ | 413 | tcpStatus CifsNeedReconnect if server hung */ |
| 420 | 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; | ||
| 421 | goto incomplete_rcv; | 420 | goto incomplete_rcv; |
| 422 | else | 421 | } else |
| 423 | continue; | 422 | continue; |
| 424 | } else if (length <= 0) { | 423 | } else if (length <= 0) { |
| 425 | if (server->tcpStatus == CifsNew) { | 424 | if (server->tcpStatus == CifsNew) { |
| @@ -654,6 +653,11 @@ multi_t2_fnd: | |||
| 654 | } | 653 | } |
| 655 | } /* end while !EXITING */ | 654 | } /* end while !EXITING */ |
| 656 | 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 | |||
| 657 | spin_lock(&GlobalMid_Lock); | 661 | spin_lock(&GlobalMid_Lock); |
| 658 | server->tcpStatus = CifsExiting; | 662 | server->tcpStatus = CifsExiting; |
| 659 | spin_unlock(&GlobalMid_Lock); | 663 | spin_unlock(&GlobalMid_Lock); |
| @@ -686,29 +690,29 @@ multi_t2_fnd: | |||
| 686 | if (smallbuf) /* no sense logging a debug message if NULL */ | 690 | if (smallbuf) /* no sense logging a debug message if NULL */ |
| 687 | cifs_small_buf_release(smallbuf); | 691 | cifs_small_buf_release(smallbuf); |
| 688 | 692 | ||
| 689 | 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); | ||
| 690 | if (list_empty(&server->pending_mid_q)) { | 698 | if (list_empty(&server->pending_mid_q)) { |
| 691 | /* loop through server session structures attached to this and | 699 | /* loop through server session structures attached to this and |
| 692 | mark them dead */ | 700 | mark them dead */ |
| 693 | list_for_each(tmp, &GlobalSMBSessionList) { | 701 | list_for_each(tmp, &server->smb_ses_list) { |
| 694 | ses = | 702 | ses = list_entry(tmp, struct cifsSesInfo, |
| 695 | list_entry(tmp, struct cifsSesInfo, | 703 | smb_ses_list); |
| 696 | cifsSessionList); | 704 | ses->status = CifsExiting; |
| 697 | if (ses->server == server) { | 705 | ses->server = NULL; |
| 698 | ses->status = CifsExiting; | ||
| 699 | ses->server = NULL; | ||
| 700 | } | ||
| 701 | } | 706 | } |
| 702 | read_unlock(&GlobalSMBSeslock); | 707 | read_unlock(&cifs_tcp_ses_lock); |
| 703 | } else { | 708 | } else { |
| 704 | /* although we can not zero the server struct pointer yet, | 709 | /* although we can not zero the server struct pointer yet, |
| 705 | since there are active requests which may depnd on them, | 710 | since there are active requests which may depnd on them, |
| 706 | mark the corresponding SMB sessions as exiting too */ | 711 | mark the corresponding SMB sessions as exiting too */ |
| 707 | list_for_each(tmp, &GlobalSMBSessionList) { | 712 | list_for_each(tmp, &server->smb_ses_list) { |
| 708 | ses = list_entry(tmp, struct cifsSesInfo, | 713 | ses = list_entry(tmp, struct cifsSesInfo, |
| 709 | cifsSessionList); | 714 | smb_ses_list); |
| 710 | if (ses->server == server) | 715 | ses->status = CifsExiting; |
| 711 | ses->status = CifsExiting; | ||
| 712 | } | 716 | } |
| 713 | 717 | ||
| 714 | spin_lock(&GlobalMid_Lock); | 718 | spin_lock(&GlobalMid_Lock); |
| @@ -723,7 +727,7 @@ multi_t2_fnd: | |||
| 723 | } | 727 | } |
| 724 | } | 728 | } |
| 725 | spin_unlock(&GlobalMid_Lock); | 729 | spin_unlock(&GlobalMid_Lock); |
| 726 | read_unlock(&GlobalSMBSeslock); | 730 | read_unlock(&cifs_tcp_ses_lock); |
| 727 | /* 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 */ |
| 728 | msleep(125); | 732 | msleep(125); |
| 729 | } | 733 | } |
| @@ -745,14 +749,13 @@ multi_t2_fnd: | |||
| 745 | if there are any pointing to this (e.g | 749 | if there are any pointing to this (e.g |
| 746 | if a crazy root user tried to kill cifsd | 750 | if a crazy root user tried to kill cifsd |
| 747 | kernel thread explicitly this might happen) */ | 751 | kernel thread explicitly this might happen) */ |
| 748 | write_lock(&GlobalSMBSeslock); | 752 | /* BB: This shouldn't be necessary, see above */ |
| 749 | list_for_each(tmp, &GlobalSMBSessionList) { | 753 | read_lock(&cifs_tcp_ses_lock); |
| 750 | ses = list_entry(tmp, struct cifsSesInfo, | 754 | list_for_each(tmp, &server->smb_ses_list) { |
| 751 | cifsSessionList); | 755 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| 752 | if (ses->server == server) | 756 | ses->server = NULL; |
| 753 | ses->server = NULL; | ||
| 754 | } | 757 | } |
| 755 | write_unlock(&GlobalSMBSeslock); | 758 | read_unlock(&cifs_tcp_ses_lock); |
| 756 | 759 | ||
| 757 | kfree(server->hostname); | 760 | kfree(server->hostname); |
| 758 | task_to_wake = xchg(&server->tsk, NULL); | 761 | task_to_wake = xchg(&server->tsk, NULL); |
| @@ -1352,94 +1355,158 @@ cifs_parse_mount_options(char *options, const char *devname, | |||
| 1352 | return 0; | 1355 | return 0; |
| 1353 | } | 1356 | } |
| 1354 | 1357 | ||
| 1355 | static struct cifsSesInfo * | 1358 | static struct TCP_Server_Info * |
| 1356 | cifs_find_tcp_session(struct in_addr *target_ip_addr, | 1359 | cifs_find_tcp_session(struct sockaddr *addr) |
| 1357 | struct in6_addr *target_ip6_addr, | ||
| 1358 | char *userName, struct TCP_Server_Info **psrvTcp) | ||
| 1359 | { | 1360 | { |
| 1360 | struct list_head *tmp; | 1361 | struct list_head *tmp; |
| 1361 | struct cifsSesInfo *ses; | 1362 | struct TCP_Server_Info *server; |
| 1362 | 1363 | struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; | |
| 1363 | *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; | ||
| 1364 | 1378 | ||
| 1365 | read_lock(&GlobalSMBSeslock); | 1379 | if (addr->sa_family == AF_INET && |
| 1366 | list_for_each(tmp, &GlobalSMBSessionList) { | 1380 | (addr4->sin_addr.s_addr != |
| 1367 | ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); | 1381 | server->addr.sockAddr.sin_addr.s_addr)) |
| 1368 | 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))) | ||
| 1369 | continue; | 1386 | continue; |
| 1370 | 1387 | ||
| 1371 | if (target_ip_addr && | 1388 | ++server->srv_count; |
| 1372 | ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) | 1389 | write_unlock(&cifs_tcp_ses_lock); |
| 1373 | continue; | 1390 | cFYI(1, ("Existing tcp session with server found")); |
| 1374 | else if (target_ip6_addr && | 1391 | return server; |
| 1375 | memcmp(&ses->server->addr.sockAddr6.sin6_addr, | 1392 | } |
| 1376 | target_ip6_addr, sizeof(*target_ip6_addr))) | 1393 | write_unlock(&cifs_tcp_ses_lock); |
| 1377 | continue; | 1394 | return NULL; |
| 1378 | /* BB lock server and tcp session; increment use count here?? */ | 1395 | } |
| 1379 | 1396 | ||
| 1380 | /* found a match on the TCP session */ | 1397 | static void |
| 1381 | *psrvTcp = ses->server; | 1398 | cifs_put_tcp_session(struct TCP_Server_Info *server) |
| 1399 | { | ||
| 1400 | struct task_struct *task; | ||
| 1382 | 1401 | ||
| 1383 | /* BB check if reconnection needed */ | 1402 | write_lock(&cifs_tcp_ses_lock); |
| 1384 | if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { | 1403 | if (--server->srv_count > 0) { |
| 1385 | read_unlock(&GlobalSMBSeslock); | 1404 | write_unlock(&cifs_tcp_ses_lock); |
| 1386 | /* Found exact match on both TCP and | 1405 | return; |
| 1387 | SMB sessions */ | ||
| 1388 | return ses; | ||
| 1389 | } | ||
| 1390 | /* else tcp and smb sessions need reconnection */ | ||
| 1391 | } | 1406 | } |
| 1392 | read_unlock(&GlobalSMBSeslock); | ||
| 1393 | 1407 | ||
| 1394 | 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); | ||
| 1395 | } | 1418 | } |
| 1396 | 1419 | ||
| 1397 | static struct cifsTconInfo * | 1420 | static struct cifsSesInfo * |
| 1398 | find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) | 1421 | cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) |
| 1399 | { | 1422 | { |
| 1400 | struct list_head *tmp; | 1423 | struct list_head *tmp; |
| 1401 | struct cifsTconInfo *tcon; | 1424 | struct cifsSesInfo *ses; |
| 1402 | __be32 old_ip; | ||
| 1403 | |||
| 1404 | read_lock(&GlobalSMBSeslock); | ||
| 1405 | 1425 | ||
| 1406 | list_for_each(tmp, &GlobalTreeConnectionList) { | 1426 | write_lock(&cifs_tcp_ses_lock); |
| 1407 | cFYI(1, ("Next tcon")); | 1427 | list_for_each(tmp, &server->smb_ses_list) { |
| 1408 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 1428 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| 1409 | if (!tcon->ses || !tcon->ses->server) | 1429 | if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) |
| 1410 | continue; | 1430 | continue; |
| 1411 | 1431 | ||
| 1412 | old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr; | 1432 | ++ses->ses_count; |
| 1413 | cFYI(1, ("old ip addr: %x == new ip %x ?", | 1433 | write_unlock(&cifs_tcp_ses_lock); |
| 1414 | old_ip, new_target_ip_addr)); | 1434 | return ses; |
| 1435 | } | ||
| 1436 | write_unlock(&cifs_tcp_ses_lock); | ||
| 1437 | return NULL; | ||
| 1438 | } | ||
| 1415 | 1439 | ||
| 1416 | if (old_ip != new_target_ip_addr) | 1440 | static void |
| 1417 | continue; | 1441 | cifs_put_smb_ses(struct cifsSesInfo *ses) |
| 1442 | { | ||
| 1443 | int xid; | ||
| 1444 | struct TCP_Server_Info *server = ses->server; | ||
| 1418 | 1445 | ||
| 1419 | /* BB lock tcon, server, tcp session and increment use count? */ | 1446 | write_lock(&cifs_tcp_ses_lock); |
| 1420 | /* found a match on the TCP session */ | 1447 | if (--ses->ses_count > 0) { |
| 1421 | /* BB check if reconnection needed */ | 1448 | write_unlock(&cifs_tcp_ses_lock); |
| 1422 | cFYI(1, ("IP match, old UNC: %s new: %s", | 1449 | return; |
| 1423 | tcon->treeName, uncName)); | 1450 | } |
| 1424 | 1451 | ||
| 1425 | if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE)) | 1452 | list_del_init(&ses->smb_ses_list); |
| 1426 | continue; | 1453 | write_unlock(&cifs_tcp_ses_lock); |
| 1427 | 1454 | ||
| 1428 | cFYI(1, ("and old usr: %s new: %s", | 1455 | if (ses->status == CifsGood) { |
| 1429 | tcon->treeName, uncName)); | 1456 | xid = GetXid(); |
| 1457 | CIFSSMBLogoff(xid, ses); | ||
| 1458 | _FreeXid(xid); | ||
| 1459 | } | ||
| 1460 | sesInfoFree(ses); | ||
| 1461 | cifs_put_tcp_session(server); | ||
| 1462 | } | ||
| 1430 | 1463 | ||
| 1431 | if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE)) | 1464 | static struct cifsTconInfo * |
| 1465 | cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) | ||
| 1466 | { | ||
| 1467 | struct list_head *tmp; | ||
| 1468 | struct cifsTconInfo *tcon; | ||
| 1469 | |||
| 1470 | write_lock(&cifs_tcp_ses_lock); | ||
| 1471 | list_for_each(tmp, &ses->tcon_list) { | ||
| 1472 | tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); | ||
| 1473 | if (tcon->tidStatus == CifsExiting) | ||
| 1474 | continue; | ||
| 1475 | if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) | ||
| 1432 | continue; | 1476 | continue; |
| 1433 | 1477 | ||
| 1434 | /* matched smb session (user name) */ | 1478 | ++tcon->tc_count; |
| 1435 | read_unlock(&GlobalSMBSeslock); | 1479 | write_unlock(&cifs_tcp_ses_lock); |
| 1436 | return tcon; | 1480 | return tcon; |
| 1437 | } | 1481 | } |
| 1438 | 1482 | write_unlock(&cifs_tcp_ses_lock); | |
| 1439 | read_unlock(&GlobalSMBSeslock); | ||
| 1440 | return NULL; | 1483 | return NULL; |
| 1441 | } | 1484 | } |
| 1442 | 1485 | ||
| 1486 | static void | ||
| 1487 | cifs_put_tcon(struct cifsTconInfo *tcon) | ||
| 1488 | { | ||
| 1489 | int xid; | ||
| 1490 | struct cifsSesInfo *ses = tcon->ses; | ||
| 1491 | |||
| 1492 | write_lock(&cifs_tcp_ses_lock); | ||
| 1493 | if (--tcon->tc_count > 0) { | ||
| 1494 | write_unlock(&cifs_tcp_ses_lock); | ||
| 1495 | return; | ||
| 1496 | } | ||
| 1497 | |||
| 1498 | list_del_init(&tcon->tcon_list); | ||
| 1499 | write_unlock(&cifs_tcp_ses_lock); | ||
| 1500 | |||
| 1501 | xid = GetXid(); | ||
| 1502 | CIFSSMBTDis(xid, tcon); | ||
| 1503 | _FreeXid(xid); | ||
| 1504 | |||
| 1505 | DeleteTconOplockQEntries(tcon); | ||
| 1506 | tconInfoFree(tcon); | ||
| 1507 | cifs_put_smb_ses(ses); | ||
| 1508 | } | ||
| 1509 | |||
| 1443 | int | 1510 | int |
| 1444 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1511 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, |
| 1445 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 1512 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
| @@ -1876,14 +1943,90 @@ convert_delimiter(char *path, char delim) | |||
| 1876 | } | 1943 | } |
| 1877 | } | 1944 | } |
| 1878 | 1945 | ||
| 1879 | static void | 1946 | static void setup_cifs_sb(struct smb_vol *pvolume_info, |
| 1880 | kill_cifsd(struct TCP_Server_Info *server) | 1947 | struct cifs_sb_info *cifs_sb) |
| 1881 | { | 1948 | { |
| 1882 | struct task_struct *task; | 1949 | if (pvolume_info->rsize > CIFSMaxBufSize) { |
| 1883 | 1950 | cERROR(1, ("rsize %d too large, using MaxBufSize", | |
| 1884 | task = xchg(&server->tsk, NULL); | 1951 | pvolume_info->rsize)); |
| 1885 | if (task) | 1952 | cifs_sb->rsize = CIFSMaxBufSize; |
| 1886 | 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")); | ||
| 1887 | } | 2030 | } |
| 1888 | 2031 | ||
| 1889 | int | 2032 | int |
| @@ -1892,13 +2035,12 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1892 | { | 2035 | { |
| 1893 | int rc = 0; | 2036 | int rc = 0; |
| 1894 | int xid; | 2037 | int xid; |
| 1895 | int address_type = AF_INET; | ||
| 1896 | struct socket *csocket = NULL; | 2038 | struct socket *csocket = NULL; |
| 1897 | struct sockaddr_in sin_server; | 2039 | struct sockaddr addr; |
| 1898 | 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; | ||
| 1899 | struct smb_vol volume_info; | 2042 | struct smb_vol volume_info; |
| 1900 | struct cifsSesInfo *pSesInfo = NULL; | 2043 | struct cifsSesInfo *pSesInfo = NULL; |
| 1901 | struct cifsSesInfo *existingCifsSes = NULL; | ||
| 1902 | struct cifsTconInfo *tcon = NULL; | 2044 | struct cifsTconInfo *tcon = NULL; |
| 1903 | struct TCP_Server_Info *srvTcp = NULL; | 2045 | struct TCP_Server_Info *srvTcp = NULL; |
| 1904 | 2046 | ||
| @@ -1906,6 +2048,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1906 | 2048 | ||
| 1907 | /* 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)); */ |
| 1908 | 2050 | ||
| 2051 | memset(&addr, 0, sizeof(struct sockaddr)); | ||
| 1909 | memset(&volume_info, 0, sizeof(struct smb_vol)); | 2052 | memset(&volume_info, 0, sizeof(struct smb_vol)); |
| 1910 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { | 2053 | if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { |
| 1911 | rc = -EINVAL; | 2054 | rc = -EINVAL; |
| @@ -1928,16 +2071,16 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1928 | 2071 | ||
| 1929 | if (volume_info.UNCip && volume_info.UNC) { | 2072 | if (volume_info.UNCip && volume_info.UNC) { |
| 1930 | rc = cifs_inet_pton(AF_INET, volume_info.UNCip, | 2073 | rc = cifs_inet_pton(AF_INET, volume_info.UNCip, |
| 1931 | &sin_server.sin_addr.s_addr); | 2074 | &sin_server->sin_addr.s_addr); |
| 1932 | 2075 | ||
| 1933 | if (rc <= 0) { | 2076 | if (rc <= 0) { |
| 1934 | /* not ipv4 address, try ipv6 */ | 2077 | /* not ipv4 address, try ipv6 */ |
| 1935 | rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, | 2078 | rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, |
| 1936 | &sin_server6.sin6_addr.in6_u); | 2079 | &sin_server6->sin6_addr.in6_u); |
| 1937 | if (rc > 0) | 2080 | if (rc > 0) |
| 1938 | address_type = AF_INET6; | 2081 | addr.sa_family = AF_INET6; |
| 1939 | } else { | 2082 | } else { |
| 1940 | address_type = AF_INET; | 2083 | addr.sa_family = AF_INET; |
| 1941 | } | 2084 | } |
| 1942 | 2085 | ||
| 1943 | if (rc <= 0) { | 2086 | if (rc <= 0) { |
| @@ -1977,41 +2120,25 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 1977 | } | 2120 | } |
| 1978 | } | 2121 | } |
| 1979 | 2122 | ||
| 1980 | if (address_type == AF_INET) | 2123 | srvTcp = cifs_find_tcp_session(&addr); |
| 1981 | existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, | 2124 | if (!srvTcp) { /* create socket */ |
| 1982 | NULL /* no ipv6 addr */, | 2125 | if (addr.sa_family == AF_INET6) { |
| 1983 | volume_info.username, &srvTcp); | ||
| 1984 | else if (address_type == AF_INET6) { | ||
| 1985 | cFYI(1, ("looking for ipv6 address")); | ||
| 1986 | existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, | ||
| 1987 | &sin_server6.sin6_addr, | ||
| 1988 | volume_info.username, &srvTcp); | ||
| 1989 | } else { | ||
| 1990 | rc = -EINVAL; | ||
| 1991 | goto out; | ||
| 1992 | } | ||
| 1993 | |||
| 1994 | if (srvTcp) { | ||
| 1995 | cFYI(1, ("Existing tcp session with server found")); | ||
| 1996 | } else { /* create socket */ | ||
| 1997 | if (volume_info.port) | ||
| 1998 | sin_server.sin_port = htons(volume_info.port); | ||
| 1999 | else | ||
| 2000 | sin_server.sin_port = 0; | ||
| 2001 | if (address_type == AF_INET6) { | ||
| 2002 | cFYI(1, ("attempting ipv6 connect")); | 2126 | cFYI(1, ("attempting ipv6 connect")); |
| 2003 | /* BB should we allow ipv6 on port 139? */ | 2127 | /* BB should we allow ipv6 on port 139? */ |
| 2004 | /* other OS never observed in Wild doing 139 with v6 */ | 2128 | /* other OS never observed in Wild doing 139 with v6 */ |
| 2005 | rc = ipv6_connect(&sin_server6, &csocket, | 2129 | sin_server6->sin6_port = htons(volume_info.port); |
| 2130 | rc = ipv6_connect(sin_server6, &csocket, | ||
| 2006 | volume_info.noblocksnd); | 2131 | volume_info.noblocksnd); |
| 2007 | } else | 2132 | } else { |
| 2008 | rc = ipv4_connect(&sin_server, &csocket, | 2133 | sin_server->sin_port = htons(volume_info.port); |
| 2134 | rc = ipv4_connect(sin_server, &csocket, | ||
| 2009 | volume_info.source_rfc1001_name, | 2135 | volume_info.source_rfc1001_name, |
| 2010 | volume_info.target_rfc1001_name, | 2136 | volume_info.target_rfc1001_name, |
| 2011 | volume_info.noblocksnd, | 2137 | volume_info.noblocksnd, |
| 2012 | volume_info.noautotune); | 2138 | volume_info.noautotune); |
| 2139 | } | ||
| 2013 | if (rc < 0) { | 2140 | if (rc < 0) { |
| 2014 | cERROR(1, ("Error connecting to IPv4 socket. " | 2141 | cERROR(1, ("Error connecting to socket. " |
| 2015 | "Aborting operation")); | 2142 | "Aborting operation")); |
| 2016 | if (csocket != NULL) | 2143 | if (csocket != NULL) |
| 2017 | sock_release(csocket); | 2144 | sock_release(csocket); |
| @@ -2026,12 +2153,15 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2026 | } else { | 2153 | } else { |
| 2027 | srvTcp->noblocksnd = volume_info.noblocksnd; | 2154 | srvTcp->noblocksnd = volume_info.noblocksnd; |
| 2028 | srvTcp->noautotune = volume_info.noautotune; | 2155 | srvTcp->noautotune = volume_info.noautotune; |
| 2029 | memcpy(&srvTcp->addr.sockAddr, &sin_server, | 2156 | if (addr.sa_family == AF_INET6) |
| 2030 | sizeof(struct sockaddr_in)); | 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)); | ||
| 2031 | atomic_set(&srvTcp->inFlight, 0); | 2162 | atomic_set(&srvTcp->inFlight, 0); |
| 2032 | /* BB Add code for ipv6 case too */ | 2163 | /* BB Add code for ipv6 case too */ |
| 2033 | srvTcp->ssocket = csocket; | 2164 | srvTcp->ssocket = csocket; |
| 2034 | srvTcp->protocolType = IPV4; | ||
| 2035 | srvTcp->hostname = extract_hostname(volume_info.UNC); | 2165 | srvTcp->hostname = extract_hostname(volume_info.UNC); |
| 2036 | if (IS_ERR(srvTcp->hostname)) { | 2166 | if (IS_ERR(srvTcp->hostname)) { |
| 2037 | rc = PTR_ERR(srvTcp->hostname); | 2167 | rc = PTR_ERR(srvTcp->hostname); |
| @@ -2061,15 +2191,28 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2061 | memcpy(srvTcp->server_RFC1001_name, | 2191 | memcpy(srvTcp->server_RFC1001_name, |
| 2062 | volume_info.target_rfc1001_name, 16); | 2192 | volume_info.target_rfc1001_name, 16); |
| 2063 | 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); | ||
| 2064 | } | 2201 | } |
| 2065 | } | 2202 | } |
| 2066 | 2203 | ||
| 2067 | if (existingCifsSes) { | 2204 | pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); |
| 2068 | pSesInfo = existingCifsSes; | 2205 | if (pSesInfo) { |
| 2069 | cFYI(1, ("Existing smb sess found (status=%d)", | 2206 | cFYI(1, ("Existing smb sess found (status=%d)", |
| 2070 | 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 | |||
| 2071 | down(&pSesInfo->sesSem); | 2214 | down(&pSesInfo->sesSem); |
| 2072 | if (pSesInfo->status == CifsNeedReconnect) { | 2215 | if (pSesInfo->need_reconnect) { |
| 2073 | cFYI(1, ("Session needs reconnect")); | 2216 | cFYI(1, ("Session needs reconnect")); |
| 2074 | rc = cifs_setup_session(xid, pSesInfo, | 2217 | rc = cifs_setup_session(xid, pSesInfo, |
| 2075 | cifs_sb->local_nls); | 2218 | cifs_sb->local_nls); |
| @@ -2078,187 +2221,101 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2078 | } else if (!rc) { | 2221 | } else if (!rc) { |
| 2079 | cFYI(1, ("Existing smb sess not found")); | 2222 | cFYI(1, ("Existing smb sess not found")); |
| 2080 | pSesInfo = sesInfoAlloc(); | 2223 | pSesInfo = sesInfoAlloc(); |
| 2081 | if (pSesInfo == NULL) | 2224 | if (pSesInfo == NULL) { |
| 2082 | rc = -ENOMEM; | 2225 | rc = -ENOMEM; |
| 2083 | else { | 2226 | goto mount_fail_check; |
| 2084 | pSesInfo->server = srvTcp; | 2227 | } |
| 2085 | sprintf(pSesInfo->serverName, "%u.%u.%u.%u", | 2228 | |
| 2086 | NIPQUAD(sin_server.sin_addr.s_addr)); | 2229 | /* new SMB session uses our srvTcp ref */ |
| 2087 | } | 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); | ||
| 2088 | 2257 | ||
| 2089 | if (!rc) { | 2258 | /* BB FIXME need to pass vol->secFlgs BB */ |
| 2090 | /* volume_info.password freed at unmount */ | 2259 | rc = cifs_setup_session(xid, pSesInfo, |
| 2091 | if (volume_info.password) { | 2260 | cifs_sb->local_nls); |
| 2092 | pSesInfo->password = volume_info.password; | 2261 | up(&pSesInfo->sesSem); |
| 2093 | /* set to NULL to prevent freeing on exit */ | ||
| 2094 | volume_info.password = NULL; | ||
| 2095 | } | ||
| 2096 | if (volume_info.username) | ||
| 2097 | strncpy(pSesInfo->userName, | ||
| 2098 | volume_info.username, | ||
| 2099 | MAX_USERNAME_SIZE); | ||
| 2100 | if (volume_info.domainname) { | ||
| 2101 | int len = strlen(volume_info.domainname); | ||
| 2102 | pSesInfo->domainName = | ||
| 2103 | kmalloc(len + 1, GFP_KERNEL); | ||
| 2104 | if (pSesInfo->domainName) | ||
| 2105 | strcpy(pSesInfo->domainName, | ||
| 2106 | volume_info.domainname); | ||
| 2107 | } | ||
| 2108 | pSesInfo->linux_uid = volume_info.linux_uid; | ||
| 2109 | pSesInfo->overrideSecFlg = volume_info.secFlg; | ||
| 2110 | down(&pSesInfo->sesSem); | ||
| 2111 | /* BB FIXME need to pass vol->secFlgs BB */ | ||
| 2112 | rc = cifs_setup_session(xid, pSesInfo, | ||
| 2113 | cifs_sb->local_nls); | ||
| 2114 | up(&pSesInfo->sesSem); | ||
| 2115 | if (!rc) | ||
| 2116 | atomic_inc(&srvTcp->socketUseCount); | ||
| 2117 | } | ||
| 2118 | } | 2262 | } |
| 2119 | 2263 | ||
| 2120 | /* search for existing tcon to this server share */ | 2264 | /* search for existing tcon to this server share */ |
| 2121 | if (!rc) { | 2265 | if (!rc) { |
| 2122 | if (volume_info.rsize > CIFSMaxBufSize) { | 2266 | setup_cifs_sb(&volume_info, cifs_sb); |
| 2123 | cERROR(1, ("rsize %d too large, using MaxBufSize", | ||
| 2124 | volume_info.rsize)); | ||
| 2125 | cifs_sb->rsize = CIFSMaxBufSize; | ||
| 2126 | } else if ((volume_info.rsize) && | ||
| 2127 | (volume_info.rsize <= CIFSMaxBufSize)) | ||
| 2128 | cifs_sb->rsize = volume_info.rsize; | ||
| 2129 | else /* default */ | ||
| 2130 | cifs_sb->rsize = CIFSMaxBufSize; | ||
| 2131 | |||
| 2132 | if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { | ||
| 2133 | cERROR(1, ("wsize %d too large, using 4096 instead", | ||
| 2134 | volume_info.wsize)); | ||
| 2135 | cifs_sb->wsize = 4096; | ||
| 2136 | } else if (volume_info.wsize) | ||
| 2137 | cifs_sb->wsize = volume_info.wsize; | ||
| 2138 | else | ||
| 2139 | cifs_sb->wsize = | ||
| 2140 | min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE, | ||
| 2141 | 127*1024); | ||
| 2142 | /* old default of CIFSMaxBufSize was too small now | ||
| 2143 | that SMB Write2 can send multiple pages in kvec. | ||
| 2144 | RFC1001 does not describe what happens when frame | ||
| 2145 | bigger than 128K is sent so use that as max in | ||
| 2146 | conjunction with 52K kvec constraint on arch with 4K | ||
| 2147 | page size */ | ||
| 2148 | |||
| 2149 | if (cifs_sb->rsize < 2048) { | ||
| 2150 | cifs_sb->rsize = 2048; | ||
| 2151 | /* Windows ME may prefer this */ | ||
| 2152 | cFYI(1, ("readsize set to minimum: 2048")); | ||
| 2153 | } | ||
| 2154 | /* calculate prepath */ | ||
| 2155 | cifs_sb->prepath = volume_info.prepath; | ||
| 2156 | if (cifs_sb->prepath) { | ||
| 2157 | cifs_sb->prepathlen = strlen(cifs_sb->prepath); | ||
| 2158 | /* we can not convert the / to \ in the path | ||
| 2159 | separators in the prefixpath yet because we do not | ||
| 2160 | know (until reset_cifs_unix_caps is called later) | ||
| 2161 | whether POSIX PATH CAP is available. We normalize | ||
| 2162 | the / to \ after reset_cifs_unix_caps is called */ | ||
| 2163 | volume_info.prepath = NULL; | ||
| 2164 | } else | ||
| 2165 | cifs_sb->prepathlen = 0; | ||
| 2166 | cifs_sb->mnt_uid = volume_info.linux_uid; | ||
| 2167 | cifs_sb->mnt_gid = volume_info.linux_gid; | ||
| 2168 | cifs_sb->mnt_file_mode = volume_info.file_mode; | ||
| 2169 | cifs_sb->mnt_dir_mode = volume_info.dir_mode; | ||
| 2170 | cFYI(1, ("file mode: 0x%x dir mode: 0x%x", | ||
| 2171 | cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); | ||
| 2172 | |||
| 2173 | if (volume_info.noperm) | ||
| 2174 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; | ||
| 2175 | if (volume_info.setuids) | ||
| 2176 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; | ||
| 2177 | if (volume_info.server_ino) | ||
| 2178 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; | ||
| 2179 | if (volume_info.remap) | ||
| 2180 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; | ||
| 2181 | if (volume_info.no_xattr) | ||
| 2182 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; | ||
| 2183 | if (volume_info.sfu_emul) | ||
| 2184 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; | ||
| 2185 | if (volume_info.nobrl) | ||
| 2186 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; | ||
| 2187 | if (volume_info.cifs_acl) | ||
| 2188 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; | ||
| 2189 | if (volume_info.override_uid) | ||
| 2190 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; | ||
| 2191 | if (volume_info.override_gid) | ||
| 2192 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; | ||
| 2193 | if (volume_info.dynperm) | ||
| 2194 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; | ||
| 2195 | if (volume_info.direct_io) { | ||
| 2196 | cFYI(1, ("mounting share using direct i/o")); | ||
| 2197 | cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; | ||
| 2198 | } | ||
| 2199 | 2267 | ||
| 2200 | if ((volume_info.cifs_acl) && (volume_info.dynperm)) | 2268 | tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); |
| 2201 | cERROR(1, ("mount option dynperm ignored if cifsacl " | ||
| 2202 | "mount option supported")); | ||
| 2203 | |||
| 2204 | tcon = | ||
| 2205 | find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, | ||
| 2206 | volume_info.username); | ||
| 2207 | if (tcon) { | 2269 | if (tcon) { |
| 2208 | cFYI(1, ("Found match on UNC path")); | 2270 | cFYI(1, ("Found match on UNC path")); |
| 2209 | /* we can have only one retry value for a connection | 2271 | /* existing tcon already has a reference */ |
| 2210 | to a share so for resources mounted more than once | 2272 | cifs_put_smb_ses(pSesInfo); |
| 2211 | to the same server share the last value passed in | ||
| 2212 | for the retry flag is used */ | ||
| 2213 | tcon->retry = volume_info.retry; | ||
| 2214 | tcon->nocase = volume_info.nocase; | ||
| 2215 | tcon->local_lease = volume_info.local_lease; | ||
| 2216 | if (tcon->seal != volume_info.seal) | 2273 | if (tcon->seal != volume_info.seal) |
| 2217 | cERROR(1, ("transport encryption setting " | 2274 | cERROR(1, ("transport encryption setting " |
| 2218 | "conflicts with existing tid")); | 2275 | "conflicts with existing tid")); |
| 2219 | } else { | 2276 | } else { |
| 2220 | tcon = tconInfoAlloc(); | 2277 | tcon = tconInfoAlloc(); |
| 2221 | if (tcon == NULL) | 2278 | if (tcon == NULL) { |
| 2222 | rc = -ENOMEM; | 2279 | rc = -ENOMEM; |
| 2223 | else { | 2280 | goto mount_fail_check; |
| 2224 | /* check for null share name ie connecting to | 2281 | } |
| 2225 | * dfs root */ | 2282 | tcon->ses = pSesInfo; |
| 2226 | 2283 | ||
| 2227 | /* BB check if this works for exactly length | 2284 | /* check for null share name ie connect to dfs root */ |
| 2228 | * three strings */ | 2285 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) |
| 2229 | if ((strchr(volume_info.UNC + 3, '\\') == NULL) | 2286 | && (strchr(volume_info.UNC + 3, '/') == NULL)) { |
| 2230 | && (strchr(volume_info.UNC + 3, '/') == | 2287 | /* rc = connect_to_dfs_path(...) */ |
| 2231 | NULL)) { | 2288 | cFYI(1, ("DFS root not supported")); |
| 2232 | /* rc = connect_to_dfs_path(xid, pSesInfo, | 2289 | rc = -ENODEV; |
| 2233 | "", cifs_sb->local_nls, | 2290 | goto mount_fail_check; |
| 2234 | cifs_sb->mnt_cifs_flags & | 2291 | } else { |
| 2235 | CIFS_MOUNT_MAP_SPECIAL_CHR);*/ | 2292 | /* BB Do we need to wrap sesSem around |
| 2236 | cFYI(1, ("DFS root not supported")); | 2293 | * this TCon call and Unix SetFS as |
| 2237 | rc = -ENODEV; | 2294 | * we do on SessSetup and reconnect? */ |
| 2238 | goto out; | 2295 | rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, |
| 2239 | } else { | 2296 | tcon, cifs_sb->local_nls); |
| 2240 | /* BB Do we need to wrap sesSem around | 2297 | cFYI(1, ("CIFS Tcon rc = %d", rc)); |
| 2241 | * this TCon call and Unix SetFS as | 2298 | if (volume_info.nodfs) { |
| 2242 | * we do on SessSetup and reconnect? */ | 2299 | tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; |
| 2243 | rc = CIFSTCon(xid, pSesInfo, | 2300 | cFYI(1, ("DFS disabled (%d)", |
| 2244 | volume_info.UNC, | 2301 | tcon->Flags)); |
| 2245 | tcon, cifs_sb->local_nls); | ||
| 2246 | cFYI(1, ("CIFS Tcon rc = %d", rc)); | ||
| 2247 | if (volume_info.nodfs) { | ||
| 2248 | tcon->Flags &= | ||
| 2249 | ~SMB_SHARE_IS_IN_DFS; | ||
| 2250 | cFYI(1, ("DFS disabled (%d)", | ||
| 2251 | tcon->Flags)); | ||
| 2252 | } | ||
| 2253 | } | ||
| 2254 | if (!rc) { | ||
| 2255 | atomic_inc(&pSesInfo->inUse); | ||
| 2256 | tcon->retry = volume_info.retry; | ||
| 2257 | tcon->nocase = volume_info.nocase; | ||
| 2258 | tcon->seal = volume_info.seal; | ||
| 2259 | } | 2302 | } |
| 2260 | } | 2303 | } |
| 2261 | } | 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; | ||
| 2262 | } | 2319 | } |
| 2263 | if (pSesInfo) { | 2320 | if (pSesInfo) { |
| 2264 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { | 2321 | if (pSesInfo->capabilities & CAP_LARGE_FILES) { |
| @@ -2270,80 +2327,49 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2270 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2327 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
| 2271 | sb->s_time_gran = 100; | 2328 | sb->s_time_gran = 100; |
| 2272 | 2329 | ||
| 2273 | /* on error free sesinfo and tcon struct if needed */ | 2330 | mount_fail_check: |
| 2331 | /* on error free sesinfo and tcon struct if needed */ | ||
| 2274 | if (rc) { | 2332 | if (rc) { |
| 2275 | /* if session setup failed, use count is zero but | 2333 | /* If find_unc succeeded then rc == 0 so we can not end */ |
| 2276 | we still need to free cifsd thread */ | 2334 | /* up accidently freeing someone elses tcon struct */ |
| 2277 | if (atomic_read(&srvTcp->socketUseCount) == 0) { | 2335 | if (tcon) |
| 2278 | spin_lock(&GlobalMid_Lock); | 2336 | cifs_put_tcon(tcon); |
| 2279 | srvTcp->tcpStatus = CifsExiting; | 2337 | else if (pSesInfo) |
| 2280 | spin_unlock(&GlobalMid_Lock); | 2338 | cifs_put_smb_ses(pSesInfo); |
| 2281 | kill_cifsd(srvTcp); | ||
| 2282 | } | ||
| 2283 | /* If find_unc succeeded then rc == 0 so we can not end */ | ||
| 2284 | if (tcon) /* up accidently freeing someone elses tcon struct */ | ||
| 2285 | tconInfoFree(tcon); | ||
| 2286 | if (existingCifsSes == NULL) { | ||
| 2287 | if (pSesInfo) { | ||
| 2288 | if ((pSesInfo->server) && | ||
| 2289 | (pSesInfo->status == CifsGood)) { | ||
| 2290 | int temp_rc; | ||
| 2291 | temp_rc = CIFSSMBLogoff(xid, pSesInfo); | ||
| 2292 | /* if the socketUseCount is now zero */ | ||
| 2293 | if ((temp_rc == -ESHUTDOWN) && | ||
| 2294 | (pSesInfo->server)) | ||
| 2295 | kill_cifsd(pSesInfo->server); | ||
| 2296 | } else { | ||
| 2297 | cFYI(1, ("No session or bad tcon")); | ||
| 2298 | if (pSesInfo->server) { | ||
| 2299 | spin_lock(&GlobalMid_Lock); | ||
| 2300 | srvTcp->tcpStatus = CifsExiting; | ||
| 2301 | spin_unlock(&GlobalMid_Lock); | ||
| 2302 | kill_cifsd(pSesInfo->server); | ||
| 2303 | } | ||
| 2304 | } | ||
| 2305 | sesInfoFree(pSesInfo); | ||
| 2306 | /* pSesInfo = NULL; */ | ||
| 2307 | } | ||
| 2308 | } | ||
| 2309 | } else { | ||
| 2310 | atomic_inc(&tcon->useCount); | ||
| 2311 | cifs_sb->tcon = tcon; | ||
| 2312 | tcon->ses = pSesInfo; | ||
| 2313 | |||
| 2314 | /* do not care if following two calls succeed - informational */ | ||
| 2315 | if (!tcon->ipc) { | ||
| 2316 | CIFSSMBQFSDeviceInfo(xid, tcon); | ||
| 2317 | CIFSSMBQFSAttributeInfo(xid, tcon); | ||
| 2318 | } | ||
| 2319 | |||
| 2320 | /* tell server which Unix caps we support */ | ||
| 2321 | if (tcon->ses->capabilities & CAP_UNIX) | ||
| 2322 | /* reset of caps checks mount to see if unix extensions | ||
| 2323 | disabled for just this mount */ | ||
| 2324 | reset_cifs_unix_caps(xid, tcon, sb, &volume_info); | ||
| 2325 | else | 2339 | else |
| 2326 | tcon->unix_ext = 0; /* server does not support them */ | 2340 | cifs_put_tcp_session(srvTcp); |
| 2341 | goto out; | ||
| 2342 | } | ||
| 2343 | cifs_sb->tcon = tcon; | ||
| 2327 | 2344 | ||
| 2328 | /* convert forward to back slashes in prepath here if needed */ | 2345 | /* do not care if following two calls succeed - informational */ |
| 2329 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) | 2346 | if (!tcon->ipc) { |
| 2330 | convert_delimiter(cifs_sb->prepath, | 2347 | CIFSSMBQFSDeviceInfo(xid, tcon); |
| 2331 | CIFS_DIR_SEP(cifs_sb)); | 2348 | CIFSSMBQFSAttributeInfo(xid, tcon); |
| 2349 | } | ||
| 2332 | 2350 | ||
| 2333 | if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { | 2351 | /* tell server which Unix caps we support */ |
| 2334 | cifs_sb->rsize = 1024 * 127; | 2352 | if (tcon->ses->capabilities & CAP_UNIX) |
| 2335 | cFYI(DBG2, | 2353 | /* reset of caps checks mount to see if unix extensions |
| 2336 | ("no very large read support, rsize now 127K")); | 2354 | disabled for just this mount */ |
| 2337 | } | 2355 | reset_cifs_unix_caps(xid, tcon, sb, &volume_info); |
| 2338 | if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) | 2356 | else |
| 2339 | cifs_sb->wsize = min(cifs_sb->wsize, | 2357 | tcon->unix_ext = 0; /* server does not support them */ |
| 2340 | (tcon->ses->server->maxBuf - | 2358 | |
| 2341 | MAX_CIFS_HDR_SIZE)); | 2359 | /* convert forward to back slashes in prepath here if needed */ |
| 2342 | if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) | 2360 | if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) |
| 2343 | cifs_sb->rsize = min(cifs_sb->rsize, | 2361 | convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); |
| 2344 | (tcon->ses->server->maxBuf - | 2362 | |
| 2345 | 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")); | ||
| 2346 | } | 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)); | ||
| 2347 | 2373 | ||
| 2348 | /* volume_info.password is freed above when existing session found | 2374 | /* volume_info.password is freed above when existing session found |
| 2349 | (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 |
| @@ -3513,6 +3539,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses, | |||
| 3513 | /* above now done in SendReceive */ | 3539 | /* above now done in SendReceive */ |
| 3514 | if ((rc == 0) && (tcon != NULL)) { | 3540 | if ((rc == 0) && (tcon != NULL)) { |
| 3515 | tcon->tidStatus = CifsGood; | 3541 | tcon->tidStatus = CifsGood; |
| 3542 | tcon->need_reconnect = false; | ||
| 3516 | tcon->tid = smb_buffer_response->Tid; | 3543 | tcon->tid = smb_buffer_response->Tid; |
| 3517 | bcc_ptr = pByteArea(smb_buffer_response); | 3544 | bcc_ptr = pByteArea(smb_buffer_response); |
| 3518 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); | 3545 | length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); |
| @@ -3584,48 +3611,17 @@ int | |||
| 3584 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3611 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) |
| 3585 | { | 3612 | { |
| 3586 | int rc = 0; | 3613 | int rc = 0; |
| 3587 | int xid; | ||
| 3588 | struct cifsSesInfo *ses = NULL; | ||
| 3589 | char *tmp; | 3614 | char *tmp; |
| 3590 | 3615 | ||
| 3591 | xid = GetXid(); | 3616 | if (cifs_sb->tcon) |
| 3592 | 3617 | cifs_put_tcon(cifs_sb->tcon); | |
| 3593 | if (cifs_sb->tcon) { | ||
| 3594 | ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ | ||
| 3595 | rc = CIFSSMBTDis(xid, cifs_sb->tcon); | ||
| 3596 | if (rc == -EBUSY) { | ||
| 3597 | FreeXid(xid); | ||
| 3598 | return 0; | ||
| 3599 | } | ||
| 3600 | DeleteTconOplockQEntries(cifs_sb->tcon); | ||
| 3601 | tconInfoFree(cifs_sb->tcon); | ||
| 3602 | if ((ses) && (ses->server)) { | ||
| 3603 | /* save off task so we do not refer to ses later */ | ||
| 3604 | cFYI(1, ("About to do SMBLogoff ")); | ||
| 3605 | rc = CIFSSMBLogoff(xid, ses); | ||
| 3606 | if (rc == -EBUSY) { | ||
| 3607 | FreeXid(xid); | ||
| 3608 | return 0; | ||
| 3609 | } else if (rc == -ESHUTDOWN) { | ||
| 3610 | cFYI(1, ("Waking up socket by sending signal")); | ||
| 3611 | if (ses->server) | ||
| 3612 | kill_cifsd(ses->server); | ||
| 3613 | rc = 0; | ||
| 3614 | } /* else - we have an smb session | ||
| 3615 | left on this socket do not kill cifsd */ | ||
| 3616 | } else | ||
| 3617 | cFYI(1, ("No session or bad tcon")); | ||
| 3618 | } | ||
| 3619 | 3618 | ||
| 3620 | cifs_sb->tcon = NULL; | 3619 | cifs_sb->tcon = NULL; |
| 3621 | tmp = cifs_sb->prepath; | 3620 | tmp = cifs_sb->prepath; |
| 3622 | cifs_sb->prepathlen = 0; | 3621 | cifs_sb->prepathlen = 0; |
| 3623 | cifs_sb->prepath = NULL; | 3622 | cifs_sb->prepath = NULL; |
| 3624 | kfree(tmp); | 3623 | kfree(tmp); |
| 3625 | if (ses) | ||
| 3626 | sesInfoFree(ses); | ||
| 3627 | 3624 | ||
| 3628 | FreeXid(xid); | ||
| 3629 | return rc; | 3625 | return rc; |
| 3630 | } | 3626 | } |
| 3631 | 3627 | ||
| @@ -3741,6 +3737,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo, | |||
| 3741 | cFYI(1, ("CIFS Session Established successfully")); | 3737 | cFYI(1, ("CIFS Session Established successfully")); |
| 3742 | spin_lock(&GlobalMid_Lock); | 3738 | spin_lock(&GlobalMid_Lock); |
| 3743 | pSesInfo->status = CifsGood; | 3739 | pSesInfo->status = CifsGood; |
| 3740 | pSesInfo->need_reconnect = false; | ||
| 3744 | spin_unlock(&GlobalMid_Lock); | 3741 | spin_unlock(&GlobalMid_Lock); |
| 3745 | } | 3742 | } |
| 3746 | 3743 | ||
