aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/connect.c
diff options
context:
space:
mode:
authorSteve French <sfrench@us.ibm.com>2008-11-13 14:45:32 -0500
committerSteve French <sfrench@us.ibm.com>2008-11-13 14:45:32 -0500
commit3b7952109361c684caf0c50474da8662ecc81019 (patch)
tree402062ed63236ef245d8d65010d8f06520df8453 /fs/cifs/connect.c
parentc527c8a7ffa18400c2c1488f7ab5aff5e83f3c8e (diff)
[CIFS] Fix cifs reconnection flags
In preparation for Jeff's big umount/mount fixes to remove the possibility of various races in cifs mount and linked list handling of sessions, sockets and tree connections, this patch cleans up some repetitive code in cifs_mount, and addresses a problem with ses->status and tcon->tidStatus in which we were overloading the "need_reconnect" state with other status in that field. So the "need_reconnect" flag has been broken out from those two state fields (need reconnect was not mutually exclusive from some of the other possible tid and ses states). In addition, a few exit cases in cifs_mount were cleaned up, and a problem with a tcon flag (for lease support) was not being set consistently for the 2nd mount of the same share CC: Jeff Layton <jlayton@redhat.com> CC: Shirish Pargaonkar <shirishp@us.ibm.com> Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'fs/cifs/connect.c')
-rw-r--r--fs/cifs/connect.c262
1 files changed, 131 insertions, 131 deletions
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index c682be8f2984..c1cd1217c990 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -149,7 +149,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
149 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 149 ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList);
150 if (ses->server) { 150 if (ses->server) {
151 if (ses->server == server) { 151 if (ses->server == server) {
152 ses->status = CifsNeedReconnect; 152 ses->need_reconnect = true;
153 ses->ipc_tid = 0; 153 ses->ipc_tid = 0;
154 } 154 }
155 } 155 }
@@ -158,7 +158,7 @@ cifs_reconnect(struct TCP_Server_Info *server)
158 list_for_each(tmp, &GlobalTreeConnectionList) { 158 list_for_each(tmp, &GlobalTreeConnectionList) {
159 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 159 tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList);
160 if ((tcon->ses) && (tcon->ses->server == server)) 160 if ((tcon->ses) && (tcon->ses->server == server))
161 tcon->tidStatus = CifsNeedReconnect; 161 tcon->need_reconnect = true;
162 } 162 }
163 read_unlock(&GlobalSMBSeslock); 163 read_unlock(&GlobalSMBSeslock);
164 /* do not want to be sending data on a socket we are freeing */ 164 /* do not want to be sending data on a socket we are freeing */
@@ -1891,6 +1891,92 @@ kill_cifsd(struct TCP_Server_Info *server)
1891 force_sig(SIGKILL, task); 1891 force_sig(SIGKILL, task);
1892} 1892}
1893 1893
1894static void setup_cifs_sb(struct smb_vol *pvolume_info,
1895 struct cifs_sb_info *cifs_sb)
1896{
1897 if (pvolume_info->rsize > CIFSMaxBufSize) {
1898 cERROR(1, ("rsize %d too large, using MaxBufSize",
1899 pvolume_info->rsize));
1900 cifs_sb->rsize = CIFSMaxBufSize;
1901 } else if ((pvolume_info->rsize) &&
1902 (pvolume_info->rsize <= CIFSMaxBufSize))
1903 cifs_sb->rsize = pvolume_info->rsize;
1904 else /* default */
1905 cifs_sb->rsize = CIFSMaxBufSize;
1906
1907 if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
1908 cERROR(1, ("wsize %d too large, using 4096 instead",
1909 pvolume_info->wsize));
1910 cifs_sb->wsize = 4096;
1911 } else if (pvolume_info->wsize)
1912 cifs_sb->wsize = pvolume_info->wsize;
1913 else
1914 cifs_sb->wsize = min_t(const int,
1915 PAGEVEC_SIZE * PAGE_CACHE_SIZE,
1916 127*1024);
1917 /* old default of CIFSMaxBufSize was too small now
1918 that SMB Write2 can send multiple pages in kvec.
1919 RFC1001 does not describe what happens when frame
1920 bigger than 128K is sent so use that as max in
1921 conjunction with 52K kvec constraint on arch with 4K
1922 page size */
1923
1924 if (cifs_sb->rsize < 2048) {
1925 cifs_sb->rsize = 2048;
1926 /* Windows ME may prefer this */
1927 cFYI(1, ("readsize set to minimum: 2048"));
1928 }
1929 /* calculate prepath */
1930 cifs_sb->prepath = pvolume_info->prepath;
1931 if (cifs_sb->prepath) {
1932 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
1933 /* we can not convert the / to \ in the path
1934 separators in the prefixpath yet because we do not
1935 know (until reset_cifs_unix_caps is called later)
1936 whether POSIX PATH CAP is available. We normalize
1937 the / to \ after reset_cifs_unix_caps is called */
1938 pvolume_info->prepath = NULL;
1939 } else
1940 cifs_sb->prepathlen = 0;
1941 cifs_sb->mnt_uid = pvolume_info->linux_uid;
1942 cifs_sb->mnt_gid = pvolume_info->linux_gid;
1943 cifs_sb->mnt_file_mode = pvolume_info->file_mode;
1944 cifs_sb->mnt_dir_mode = pvolume_info->dir_mode;
1945 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
1946 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
1947
1948 if (pvolume_info->noperm)
1949 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
1950 if (pvolume_info->setuids)
1951 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
1952 if (pvolume_info->server_ino)
1953 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
1954 if (pvolume_info->remap)
1955 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
1956 if (pvolume_info->no_xattr)
1957 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
1958 if (pvolume_info->sfu_emul)
1959 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
1960 if (pvolume_info->nobrl)
1961 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
1962 if (pvolume_info->cifs_acl)
1963 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
1964 if (pvolume_info->override_uid)
1965 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
1966 if (pvolume_info->override_gid)
1967 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
1968 if (pvolume_info->dynperm)
1969 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
1970 if (pvolume_info->direct_io) {
1971 cFYI(1, ("mounting share using direct i/o"));
1972 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
1973 }
1974
1975 if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm))
1976 cERROR(1, ("mount option dynperm ignored if cifsacl "
1977 "mount option supported"));
1978}
1979
1894int 1980int
1895cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, 1981cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1896 char *mount_data, const char *devname) 1982 char *mount_data, const char *devname)
@@ -1996,9 +2082,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
1996 goto out; 2082 goto out;
1997 } 2083 }
1998 2084
1999 if (srvTcp) { 2085 if (!srvTcp) { /* create socket */
2000 cFYI(1, ("Existing tcp session with server found"));
2001 } else { /* create socket */
2002 if (volume_info.port) 2086 if (volume_info.port)
2003 sin_server.sin_port = htons(volume_info.port); 2087 sin_server.sin_port = htons(volume_info.port);
2004 else 2088 else
@@ -2074,7 +2158,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2074 cFYI(1, ("Existing smb sess found (status=%d)", 2158 cFYI(1, ("Existing smb sess found (status=%d)",
2075 pSesInfo->status)); 2159 pSesInfo->status));
2076 down(&pSesInfo->sesSem); 2160 down(&pSesInfo->sesSem);
2077 if (pSesInfo->status == CifsNeedReconnect) { 2161 if (pSesInfo->need_reconnect) {
2078 cFYI(1, ("Session needs reconnect")); 2162 cFYI(1, ("Session needs reconnect"));
2079 rc = cifs_setup_session(xid, pSesInfo, 2163 rc = cifs_setup_session(xid, pSesInfo,
2080 cifs_sb->local_nls); 2164 cifs_sb->local_nls);
@@ -2124,146 +2208,59 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2124 2208
2125 /* search for existing tcon to this server share */ 2209 /* search for existing tcon to this server share */
2126 if (!rc) { 2210 if (!rc) {
2127 if (volume_info.rsize > CIFSMaxBufSize) { 2211 setup_cifs_sb(&volume_info, cifs_sb);
2128 cERROR(1, ("rsize %d too large, using MaxBufSize",
2129 volume_info.rsize));
2130 cifs_sb->rsize = CIFSMaxBufSize;
2131 } else if ((volume_info.rsize) &&
2132 (volume_info.rsize <= CIFSMaxBufSize))
2133 cifs_sb->rsize = volume_info.rsize;
2134 else /* default */
2135 cifs_sb->rsize = CIFSMaxBufSize;
2136
2137 if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) {
2138 cERROR(1, ("wsize %d too large, using 4096 instead",
2139 volume_info.wsize));
2140 cifs_sb->wsize = 4096;
2141 } else if (volume_info.wsize)
2142 cifs_sb->wsize = volume_info.wsize;
2143 else
2144 cifs_sb->wsize =
2145 min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE,
2146 127*1024);
2147 /* old default of CIFSMaxBufSize was too small now
2148 that SMB Write2 can send multiple pages in kvec.
2149 RFC1001 does not describe what happens when frame
2150 bigger than 128K is sent so use that as max in
2151 conjunction with 52K kvec constraint on arch with 4K
2152 page size */
2153
2154 if (cifs_sb->rsize < 2048) {
2155 cifs_sb->rsize = 2048;
2156 /* Windows ME may prefer this */
2157 cFYI(1, ("readsize set to minimum: 2048"));
2158 }
2159 /* calculate prepath */
2160 cifs_sb->prepath = volume_info.prepath;
2161 if (cifs_sb->prepath) {
2162 cifs_sb->prepathlen = strlen(cifs_sb->prepath);
2163 /* we can not convert the / to \ in the path
2164 separators in the prefixpath yet because we do not
2165 know (until reset_cifs_unix_caps is called later)
2166 whether POSIX PATH CAP is available. We normalize
2167 the / to \ after reset_cifs_unix_caps is called */
2168 volume_info.prepath = NULL;
2169 } else
2170 cifs_sb->prepathlen = 0;
2171 cifs_sb->mnt_uid = volume_info.linux_uid;
2172 cifs_sb->mnt_gid = volume_info.linux_gid;
2173 cifs_sb->mnt_file_mode = volume_info.file_mode;
2174 cifs_sb->mnt_dir_mode = volume_info.dir_mode;
2175 cFYI(1, ("file mode: 0x%x dir mode: 0x%x",
2176 cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode));
2177
2178 if (volume_info.noperm)
2179 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM;
2180 if (volume_info.setuids)
2181 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID;
2182 if (volume_info.server_ino)
2183 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM;
2184 if (volume_info.remap)
2185 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR;
2186 if (volume_info.no_xattr)
2187 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR;
2188 if (volume_info.sfu_emul)
2189 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL;
2190 if (volume_info.nobrl)
2191 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL;
2192 if (volume_info.cifs_acl)
2193 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL;
2194 if (volume_info.override_uid)
2195 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID;
2196 if (volume_info.override_gid)
2197 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID;
2198 if (volume_info.dynperm)
2199 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM;
2200 if (volume_info.direct_io) {
2201 cFYI(1, ("mounting share using direct i/o"));
2202 cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO;
2203 }
2204
2205 if ((volume_info.cifs_acl) && (volume_info.dynperm))
2206 cERROR(1, ("mount option dynperm ignored if cifsacl "
2207 "mount option supported"));
2208 2212
2209 tcon = 2213 tcon =
2210 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, 2214 find_unc(sin_server.sin_addr.s_addr, volume_info.UNC,
2211 volume_info.username); 2215 volume_info.username);
2212 if (tcon) { 2216 if (tcon) {
2213 cFYI(1, ("Found match on UNC path")); 2217 cFYI(1, ("Found match on UNC path"));
2214 /* we can have only one retry value for a connection
2215 to a share so for resources mounted more than once
2216 to the same server share the last value passed in
2217 for the retry flag is used */
2218 tcon->retry = volume_info.retry;
2219 tcon->nocase = volume_info.nocase;
2220 tcon->local_lease = volume_info.local_lease;
2221 if (tcon->seal != volume_info.seal) 2218 if (tcon->seal != volume_info.seal)
2222 cERROR(1, ("transport encryption setting " 2219 cERROR(1, ("transport encryption setting "
2223 "conflicts with existing tid")); 2220 "conflicts with existing tid"));
2224 } else { 2221 } else {
2225 tcon = tconInfoAlloc(); 2222 tcon = tconInfoAlloc();
2226 if (tcon == NULL) 2223 if (tcon == NULL) {
2227 rc = -ENOMEM; 2224 rc = -ENOMEM;
2228 else { 2225 goto mount_fail_check;
2229 /* check for null share name ie connecting to 2226 }
2230 * dfs root */ 2227
2231 2228 /* check for null share name ie connect to dfs root */
2232 /* BB check if this works for exactly length 2229
2233 * three strings */ 2230 /* BB check if works for exactly length 3 strings */
2234 if ((strchr(volume_info.UNC + 3, '\\') == NULL) 2231 if ((strchr(volume_info.UNC + 3, '\\') == NULL)
2235 && (strchr(volume_info.UNC + 3, '/') == 2232 && (strchr(volume_info.UNC + 3, '/') == NULL)) {
2236 NULL)) { 2233 /* rc = connect_to_dfs_path(...) */
2237/* rc = connect_to_dfs_path(xid, pSesInfo, 2234 cFYI(1, ("DFS root not supported"));
2238 "", cifs_sb->local_nls, 2235 rc = -ENODEV;
2239 cifs_sb->mnt_cifs_flags & 2236 goto mount_fail_check;
2240 CIFS_MOUNT_MAP_SPECIAL_CHR);*/ 2237 } else {
2241 cFYI(1, ("DFS root not supported")); 2238 /* BB Do we need to wrap sesSem around
2242 rc = -ENODEV; 2239 * this TCon call and Unix SetFS as
2243 goto out; 2240 * we do on SessSetup and reconnect? */
2244 } else { 2241 rc = CIFSTCon(xid, pSesInfo, volume_info.UNC,
2245 /* BB Do we need to wrap sesSem around 2242 tcon, cifs_sb->local_nls);
2246 * this TCon call and Unix SetFS as 2243 cFYI(1, ("CIFS Tcon rc = %d", rc));
2247 * we do on SessSetup and reconnect? */ 2244 if (volume_info.nodfs) {
2248 rc = CIFSTCon(xid, pSesInfo, 2245 tcon->Flags &= ~SMB_SHARE_IS_IN_DFS;
2249 volume_info.UNC, 2246 cFYI(1, ("DFS disabled (%d)",
2250 tcon, cifs_sb->local_nls); 2247 tcon->Flags));
2251 cFYI(1, ("CIFS Tcon rc = %d", rc));
2252 if (volume_info.nodfs) {
2253 tcon->Flags &=
2254 ~SMB_SHARE_IS_IN_DFS;
2255 cFYI(1, ("DFS disabled (%d)",
2256 tcon->Flags));
2257 }
2258 }
2259 if (!rc) {
2260 atomic_inc(&pSesInfo->inUse);
2261 tcon->retry = volume_info.retry;
2262 tcon->nocase = volume_info.nocase;
2263 tcon->seal = volume_info.seal;
2264 } 2248 }
2265 } 2249 }
2250 if (!rc) {
2251 atomic_inc(&pSesInfo->inUse);
2252 tcon->seal = volume_info.seal;
2253 } else
2254 goto mount_fail_check;
2266 } 2255 }
2256
2257 /* we can have only one retry value for a connection
2258 to a share so for resources mounted more than once
2259 to the same server share the last value passed in
2260 for the retry flag is used */
2261 tcon->retry = volume_info.retry;
2262 tcon->nocase = volume_info.nocase;
2263 tcon->local_lease = volume_info.local_lease;
2267 } 2264 }
2268 if (pSesInfo) { 2265 if (pSesInfo) {
2269 if (pSesInfo->capabilities & CAP_LARGE_FILES) { 2266 if (pSesInfo->capabilities & CAP_LARGE_FILES) {
@@ -2276,6 +2273,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
2276 sb->s_time_gran = 100; 2273 sb->s_time_gran = 100;
2277 2274
2278/* on error free sesinfo and tcon struct if needed */ 2275/* on error free sesinfo and tcon struct if needed */
2276mount_fail_check:
2279 if (rc) { 2277 if (rc) {
2280 /* if session setup failed, use count is zero but 2278 /* if session setup failed, use count is zero but
2281 we still need to free cifsd thread */ 2279 we still need to free cifsd thread */
@@ -3518,6 +3516,7 @@ CIFSTCon(unsigned int xid, struct cifsSesInfo *ses,
3518 /* above now done in SendReceive */ 3516 /* above now done in SendReceive */
3519 if ((rc == 0) && (tcon != NULL)) { 3517 if ((rc == 0) && (tcon != NULL)) {
3520 tcon->tidStatus = CifsGood; 3518 tcon->tidStatus = CifsGood;
3519 tcon->need_reconnect = false;
3521 tcon->tid = smb_buffer_response->Tid; 3520 tcon->tid = smb_buffer_response->Tid;
3522 bcc_ptr = pByteArea(smb_buffer_response); 3521 bcc_ptr = pByteArea(smb_buffer_response);
3523 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); 3522 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2);
@@ -3746,6 +3745,7 @@ int cifs_setup_session(unsigned int xid, struct cifsSesInfo *pSesInfo,
3746 cFYI(1, ("CIFS Session Established successfully")); 3745 cFYI(1, ("CIFS Session Established successfully"));
3747 spin_lock(&GlobalMid_Lock); 3746 spin_lock(&GlobalMid_Lock);
3748 pSesInfo->status = CifsGood; 3747 pSesInfo->status = CifsGood;
3748 pSesInfo->need_reconnect = false;
3749 spin_unlock(&GlobalMid_Lock); 3749 spin_unlock(&GlobalMid_Lock);
3750 } 3750 }
3751 3751