diff options
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r-- | fs/cifs/connect.c | 156 |
1 files changed, 86 insertions, 70 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 74c222ed83dd..c104f54cadfe 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -1749,6 +1749,7 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1749 | int xid; | 1749 | int xid; |
1750 | struct cifsSesInfo *ses = tcon->ses; | 1750 | struct cifsSesInfo *ses = tcon->ses; |
1751 | 1751 | ||
1752 | cFYI(1, "%s: tc_count=%d\n", __func__, tcon->tc_count); | ||
1752 | write_lock(&cifs_tcp_ses_lock); | 1753 | write_lock(&cifs_tcp_ses_lock); |
1753 | if (--tcon->tc_count > 0) { | 1754 | if (--tcon->tc_count > 0) { |
1754 | write_unlock(&cifs_tcp_ses_lock); | 1755 | write_unlock(&cifs_tcp_ses_lock); |
@@ -1766,6 +1767,80 @@ cifs_put_tcon(struct cifsTconInfo *tcon) | |||
1766 | cifs_put_smb_ses(ses); | 1767 | cifs_put_smb_ses(ses); |
1767 | } | 1768 | } |
1768 | 1769 | ||
1770 | static struct cifsTconInfo * | ||
1771 | cifs_get_tcon(struct cifsSesInfo *ses, struct smb_vol *volume_info) | ||
1772 | { | ||
1773 | int rc, xid; | ||
1774 | struct cifsTconInfo *tcon; | ||
1775 | |||
1776 | tcon = cifs_find_tcon(ses, volume_info->UNC); | ||
1777 | if (tcon) { | ||
1778 | cFYI(1, "Found match on UNC path"); | ||
1779 | /* existing tcon already has a reference */ | ||
1780 | cifs_put_smb_ses(ses); | ||
1781 | if (tcon->seal != volume_info->seal) | ||
1782 | cERROR(1, "transport encryption setting " | ||
1783 | "conflicts with existing tid"); | ||
1784 | return tcon; | ||
1785 | } | ||
1786 | |||
1787 | tcon = tconInfoAlloc(); | ||
1788 | if (tcon == NULL) { | ||
1789 | rc = -ENOMEM; | ||
1790 | goto out_fail; | ||
1791 | } | ||
1792 | |||
1793 | tcon->ses = ses; | ||
1794 | if (volume_info->password) { | ||
1795 | tcon->password = kstrdup(volume_info->password, GFP_KERNEL); | ||
1796 | if (!tcon->password) { | ||
1797 | rc = -ENOMEM; | ||
1798 | goto out_fail; | ||
1799 | } | ||
1800 | } | ||
1801 | |||
1802 | if (strchr(volume_info->UNC + 3, '\\') == NULL | ||
1803 | && strchr(volume_info->UNC + 3, '/') == NULL) { | ||
1804 | cERROR(1, "Missing share name"); | ||
1805 | rc = -ENODEV; | ||
1806 | goto out_fail; | ||
1807 | } | ||
1808 | |||
1809 | /* BB Do we need to wrap session_mutex around | ||
1810 | * this TCon call and Unix SetFS as | ||
1811 | * we do on SessSetup and reconnect? */ | ||
1812 | xid = GetXid(); | ||
1813 | rc = CIFSTCon(xid, ses, volume_info->UNC, tcon, volume_info->local_nls); | ||
1814 | FreeXid(xid); | ||
1815 | cFYI(1, "CIFS Tcon rc = %d", rc); | ||
1816 | if (rc) | ||
1817 | goto out_fail; | ||
1818 | |||
1819 | if (volume_info->nodfs) { | ||
1820 | tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; | ||
1821 | cFYI(1, "DFS disabled (%d)", tcon->Flags); | ||
1822 | } | ||
1823 | tcon->seal = volume_info->seal; | ||
1824 | /* we can have only one retry value for a connection | ||
1825 | to a share so for resources mounted more than once | ||
1826 | to the same server share the last value passed in | ||
1827 | for the retry flag is used */ | ||
1828 | tcon->retry = volume_info->retry; | ||
1829 | tcon->nocase = volume_info->nocase; | ||
1830 | tcon->local_lease = volume_info->local_lease; | ||
1831 | |||
1832 | write_lock(&cifs_tcp_ses_lock); | ||
1833 | list_add(&tcon->tcon_list, &ses->tcon_list); | ||
1834 | write_unlock(&cifs_tcp_ses_lock); | ||
1835 | |||
1836 | return tcon; | ||
1837 | |||
1838 | out_fail: | ||
1839 | tconInfoFree(tcon); | ||
1840 | return ERR_PTR(rc); | ||
1841 | } | ||
1842 | |||
1843 | |||
1769 | int | 1844 | int |
1770 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, | 1845 | get_dfs_path(int xid, struct cifsSesInfo *pSesInfo, const char *old_path, |
1771 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 1846 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
@@ -2471,81 +2546,22 @@ try_mount_again: | |||
2471 | goto mount_fail_check; | 2546 | goto mount_fail_check; |
2472 | } | 2547 | } |
2473 | 2548 | ||
2474 | /* search for existing tcon to this server share */ | 2549 | setup_cifs_sb(volume_info, cifs_sb); |
2475 | if (!rc) { | 2550 | if (pSesInfo->capabilities & CAP_LARGE_FILES) |
2476 | setup_cifs_sb(volume_info, cifs_sb); | 2551 | sb->s_maxbytes = MAX_LFS_FILESIZE; |
2477 | 2552 | else | |
2478 | tcon = cifs_find_tcon(pSesInfo, volume_info->UNC); | 2553 | sb->s_maxbytes = MAX_NON_LFS; |
2479 | if (tcon) { | ||
2480 | cFYI(1, "Found match on UNC path"); | ||
2481 | /* existing tcon already has a reference */ | ||
2482 | cifs_put_smb_ses(pSesInfo); | ||
2483 | if (tcon->seal != volume_info->seal) | ||
2484 | cERROR(1, "transport encryption setting " | ||
2485 | "conflicts with existing tid"); | ||
2486 | } else { | ||
2487 | tcon = tconInfoAlloc(); | ||
2488 | if (tcon == NULL) { | ||
2489 | rc = -ENOMEM; | ||
2490 | goto mount_fail_check; | ||
2491 | } | ||
2492 | |||
2493 | tcon->ses = pSesInfo; | ||
2494 | if (volume_info->password) { | ||
2495 | tcon->password = kstrdup(volume_info->password, | ||
2496 | GFP_KERNEL); | ||
2497 | if (!tcon->password) { | ||
2498 | rc = -ENOMEM; | ||
2499 | goto mount_fail_check; | ||
2500 | } | ||
2501 | } | ||
2502 | |||
2503 | if ((strchr(volume_info->UNC + 3, '\\') == NULL) | ||
2504 | && (strchr(volume_info->UNC + 3, '/') == NULL)) { | ||
2505 | cERROR(1, "Missing share name"); | ||
2506 | rc = -ENODEV; | ||
2507 | goto mount_fail_check; | ||
2508 | } else { | ||
2509 | /* BB Do we need to wrap sesSem around | ||
2510 | * this TCon call and Unix SetFS as | ||
2511 | * we do on SessSetup and reconnect? */ | ||
2512 | rc = CIFSTCon(xid, pSesInfo, volume_info->UNC, | ||
2513 | tcon, cifs_sb->local_nls); | ||
2514 | cFYI(1, "CIFS Tcon rc = %d", rc); | ||
2515 | if (volume_info->nodfs) { | ||
2516 | tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; | ||
2517 | cFYI(1, "DFS disabled (%d)", | ||
2518 | tcon->Flags); | ||
2519 | } | ||
2520 | } | ||
2521 | if (rc) | ||
2522 | goto remote_path_check; | ||
2523 | tcon->seal = volume_info->seal; | ||
2524 | write_lock(&cifs_tcp_ses_lock); | ||
2525 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | ||
2526 | write_unlock(&cifs_tcp_ses_lock); | ||
2527 | } | ||
2528 | |||
2529 | /* we can have only one retry value for a connection | ||
2530 | to a share so for resources mounted more than once | ||
2531 | to the same server share the last value passed in | ||
2532 | for the retry flag is used */ | ||
2533 | tcon->retry = volume_info->retry; | ||
2534 | tcon->nocase = volume_info->nocase; | ||
2535 | tcon->local_lease = volume_info->local_lease; | ||
2536 | } | ||
2537 | if (pSesInfo) { | ||
2538 | if (pSesInfo->capabilities & CAP_LARGE_FILES) | ||
2539 | sb->s_maxbytes = MAX_LFS_FILESIZE; | ||
2540 | else | ||
2541 | sb->s_maxbytes = MAX_NON_LFS; | ||
2542 | } | ||
2543 | 2554 | ||
2544 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ | 2555 | /* BB FIXME fix time_gran to be larger for LANMAN sessions */ |
2545 | sb->s_time_gran = 100; | 2556 | sb->s_time_gran = 100; |
2546 | 2557 | ||
2547 | if (rc) | 2558 | /* search for existing tcon to this server share */ |
2559 | tcon = cifs_get_tcon(pSesInfo, volume_info); | ||
2560 | if (IS_ERR(tcon)) { | ||
2561 | rc = PTR_ERR(tcon); | ||
2562 | tcon = NULL; | ||
2548 | goto remote_path_check; | 2563 | goto remote_path_check; |
2564 | } | ||
2549 | 2565 | ||
2550 | cifs_sb->tcon = tcon; | 2566 | cifs_sb->tcon = tcon; |
2551 | 2567 | ||