Merge git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6:
prevent cifs_writepages() from skipping unwritten pages
Fixed parsing of mount options when doing DFS submount
[CIFS] Fix check for tcon seal setting and fix oops on failed mount from earlier patch
[CIFS] Fix build break
cifs: reinstate sharing of tree connections
[CIFS] minor cleanup to cifs_mount
cifs: reinstate sharing of SMB sessions sans races
cifs: disable sharing session and tcon and add new TCP sharing code
[CIFS] clean up server protocol handling
[CIFS] remove unused list, add new cifs sock list to prepare for mount/umount fix
[CIFS] Fix cifs reconnection flags
[CIFS] Can't rely on iov length and base when kernel_recvmsg returns error

+767 -718
+149 -128
fs/cifs/cifs_debug.c
··· 107 107 #ifdef CONFIG_PROC_FS 108 108 static int cifs_debug_data_proc_show(struct seq_file *m, void *v) 109 109 { 110 - struct list_head *tmp; 111 - struct list_head *tmp1; 110 + struct list_head *tmp1, *tmp2, *tmp3; 112 111 struct mid_q_entry *mid_entry; 112 + struct TCP_Server_Info *server; 113 113 struct cifsSesInfo *ses; 114 114 struct cifsTconInfo *tcon; 115 - int i; 115 + int i, j; 116 + __u32 dev_type; 116 117 117 118 seq_puts(m, 118 119 "Display Internal CIFS Data Structures for Debugging\n" ··· 123 122 seq_printf(m, "Servers:"); 124 123 125 124 i = 0; 126 - read_lock(&GlobalSMBSeslock); 127 - list_for_each(tmp, &GlobalSMBSessionList) { 125 + read_lock(&cifs_tcp_ses_lock); 126 + list_for_each(tmp1, &cifs_tcp_ses_list) { 127 + server = list_entry(tmp1, struct TCP_Server_Info, 128 + tcp_ses_list); 128 129 i++; 129 - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 130 - if ((ses->serverDomain == NULL) || (ses->serverOS == NULL) || 131 - (ses->serverNOS == NULL)) { 132 - seq_printf(m, "\nentry for %s not fully " 133 - "displayed\n\t", ses->serverName); 134 - } else { 135 - seq_printf(m, 136 - "\n%d) Name: %s Domain: %s Mounts: %d OS:" 137 - " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" 130 + list_for_each(tmp2, &server->smb_ses_list) { 131 + ses = list_entry(tmp2, struct cifsSesInfo, 132 + smb_ses_list); 133 + if ((ses->serverDomain == NULL) || 134 + (ses->serverOS == NULL) || 135 + (ses->serverNOS == NULL)) { 136 + seq_printf(m, "\n%d) entry for %s not fully " 137 + "displayed\n\t", i, ses->serverName); 138 + } else { 139 + seq_printf(m, 140 + "\n%d) Name: %s Domain: %s Uses: %d OS:" 141 + " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" 138 142 " session status: %d\t", 139 143 i, ses->serverName, ses->serverDomain, 140 - atomic_read(&ses->inUse), 141 - ses->serverOS, ses->serverNOS, 144 + ses->ses_count, ses->serverOS, ses->serverNOS, 142 145 ses->capabilities, ses->status); 143 - } 144 - if (ses->server) { 146 + } 145 147 seq_printf(m, "TCP status: %d\n\tLocal Users To " 146 - "Server: %d SecMode: 0x%x Req On Wire: %d", 147 - ses->server->tcpStatus, 148 - atomic_read(&ses->server->socketUseCount), 149 - ses->server->secMode, 150 - atomic_read(&ses->server->inFlight)); 148 + "Server: %d SecMode: 0x%x Req On Wire: %d", 149 + server->tcpStatus, server->srv_count, 150 + server->secMode, 151 + atomic_read(&server->inFlight)); 151 152 152 153 #ifdef CONFIG_CIFS_STATS2 153 154 seq_printf(m, " In Send: %d In MaxReq Wait: %d", 154 - atomic_read(&ses->server->inSend), 155 - atomic_read(&ses->server->num_waiters)); 155 + atomic_read(&server->inSend), 156 + atomic_read(&server->num_waiters)); 156 157 #endif 157 158 158 - seq_puts(m, "\nMIDs:\n"); 159 + seq_puts(m, "\n\tShares:"); 160 + j = 0; 161 + list_for_each(tmp3, &ses->tcon_list) { 162 + tcon = list_entry(tmp3, struct cifsTconInfo, 163 + tcon_list); 164 + ++j; 165 + dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); 166 + seq_printf(m, "\n\t%d) %s Mounts: %d ", j, 167 + tcon->treeName, tcon->tc_count); 168 + if (tcon->nativeFileSystem) { 169 + seq_printf(m, "Type: %s ", 170 + tcon->nativeFileSystem); 171 + } 172 + seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" 173 + "\nPathComponentMax: %d Status: 0x%d", 174 + le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), 175 + le32_to_cpu(tcon->fsAttrInfo.Attributes), 176 + le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), 177 + tcon->tidStatus); 178 + if (dev_type == FILE_DEVICE_DISK) 179 + seq_puts(m, " type: DISK "); 180 + else if (dev_type == FILE_DEVICE_CD_ROM) 181 + seq_puts(m, " type: CDROM "); 182 + else 183 + seq_printf(m, " type: %d ", dev_type); 184 + 185 + if (tcon->need_reconnect) 186 + seq_puts(m, "\tDISCONNECTED "); 187 + seq_putc(m, '\n'); 188 + } 189 + 190 + seq_puts(m, "\n\tMIDs:\n"); 159 191 160 192 spin_lock(&GlobalMid_Lock); 161 - list_for_each(tmp1, &ses->server->pending_mid_q) { 162 - mid_entry = list_entry(tmp1, struct 163 - mid_q_entry, 193 + list_for_each(tmp3, &server->pending_mid_q) { 194 + mid_entry = list_entry(tmp3, struct mid_q_entry, 164 195 qhead); 165 - seq_printf(m, "State: %d com: %d pid:" 196 + seq_printf(m, "\tState: %d com: %d pid:" 166 197 " %d tsk: %p mid %d\n", 167 198 mid_entry->midState, 168 199 (int)mid_entry->command, ··· 204 171 } 205 172 spin_unlock(&GlobalMid_Lock); 206 173 } 207 - 208 174 } 209 - read_unlock(&GlobalSMBSeslock); 210 - seq_putc(m, '\n'); 211 - 212 - seq_puts(m, "Shares:"); 213 - 214 - i = 0; 215 - read_lock(&GlobalSMBSeslock); 216 - list_for_each(tmp, &GlobalTreeConnectionList) { 217 - __u32 dev_type; 218 - i++; 219 - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 220 - dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); 221 - seq_printf(m, "\n%d) %s Uses: %d ", i, 222 - tcon->treeName, atomic_read(&tcon->useCount)); 223 - if (tcon->nativeFileSystem) { 224 - seq_printf(m, "Type: %s ", 225 - tcon->nativeFileSystem); 226 - } 227 - seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" 228 - "\nPathComponentMax: %d Status: %d", 229 - le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), 230 - le32_to_cpu(tcon->fsAttrInfo.Attributes), 231 - le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), 232 - tcon->tidStatus); 233 - if (dev_type == FILE_DEVICE_DISK) 234 - seq_puts(m, " type: DISK "); 235 - else if (dev_type == FILE_DEVICE_CD_ROM) 236 - seq_puts(m, " type: CDROM "); 237 - else 238 - seq_printf(m, " type: %d ", dev_type); 239 - 240 - if (tcon->tidStatus == CifsNeedReconnect) 241 - seq_puts(m, "\tDISCONNECTED "); 242 - } 243 - read_unlock(&GlobalSMBSeslock); 244 - 175 + read_unlock(&cifs_tcp_ses_lock); 245 176 seq_putc(m, '\n'); 246 177 247 178 /* BB add code to dump additional info such as TCP session info now */ ··· 231 234 { 232 235 char c; 233 236 int rc; 234 - struct list_head *tmp; 237 + struct list_head *tmp1, *tmp2, *tmp3; 238 + struct TCP_Server_Info *server; 239 + struct cifsSesInfo *ses; 235 240 struct cifsTconInfo *tcon; 236 241 237 242 rc = get_user(c, buffer); ··· 241 242 return rc; 242 243 243 244 if (c == '1' || c == 'y' || c == 'Y' || c == '0') { 244 - read_lock(&GlobalSMBSeslock); 245 245 #ifdef CONFIG_CIFS_STATS2 246 246 atomic_set(&totBufAllocCount, 0); 247 247 atomic_set(&totSmBufAllocCount, 0); 248 248 #endif /* CONFIG_CIFS_STATS2 */ 249 - list_for_each(tmp, &GlobalTreeConnectionList) { 250 - tcon = list_entry(tmp, struct cifsTconInfo, 251 - cifsConnectionList); 252 - atomic_set(&tcon->num_smbs_sent, 0); 253 - atomic_set(&tcon->num_writes, 0); 254 - atomic_set(&tcon->num_reads, 0); 255 - atomic_set(&tcon->num_oplock_brks, 0); 256 - atomic_set(&tcon->num_opens, 0); 257 - atomic_set(&tcon->num_closes, 0); 258 - atomic_set(&tcon->num_deletes, 0); 259 - atomic_set(&tcon->num_mkdirs, 0); 260 - atomic_set(&tcon->num_rmdirs, 0); 261 - atomic_set(&tcon->num_renames, 0); 262 - atomic_set(&tcon->num_t2renames, 0); 263 - atomic_set(&tcon->num_ffirst, 0); 264 - atomic_set(&tcon->num_fnext, 0); 265 - atomic_set(&tcon->num_fclose, 0); 266 - atomic_set(&tcon->num_hardlinks, 0); 267 - atomic_set(&tcon->num_symlinks, 0); 268 - atomic_set(&tcon->num_locks, 0); 249 + read_lock(&cifs_tcp_ses_lock); 250 + list_for_each(tmp1, &cifs_tcp_ses_list) { 251 + server = list_entry(tmp1, struct TCP_Server_Info, 252 + tcp_ses_list); 253 + list_for_each(tmp2, &server->smb_ses_list) { 254 + ses = list_entry(tmp2, struct cifsSesInfo, 255 + smb_ses_list); 256 + list_for_each(tmp3, &ses->tcon_list) { 257 + tcon = list_entry(tmp3, 258 + struct cifsTconInfo, 259 + tcon_list); 260 + atomic_set(&tcon->num_smbs_sent, 0); 261 + atomic_set(&tcon->num_writes, 0); 262 + atomic_set(&tcon->num_reads, 0); 263 + atomic_set(&tcon->num_oplock_brks, 0); 264 + atomic_set(&tcon->num_opens, 0); 265 + atomic_set(&tcon->num_closes, 0); 266 + atomic_set(&tcon->num_deletes, 0); 267 + atomic_set(&tcon->num_mkdirs, 0); 268 + atomic_set(&tcon->num_rmdirs, 0); 269 + atomic_set(&tcon->num_renames, 0); 270 + atomic_set(&tcon->num_t2renames, 0); 271 + atomic_set(&tcon->num_ffirst, 0); 272 + atomic_set(&tcon->num_fnext, 0); 273 + atomic_set(&tcon->num_fclose, 0); 274 + atomic_set(&tcon->num_hardlinks, 0); 275 + atomic_set(&tcon->num_symlinks, 0); 276 + atomic_set(&tcon->num_locks, 0); 277 + } 278 + } 269 279 } 270 - read_unlock(&GlobalSMBSeslock); 280 + read_unlock(&cifs_tcp_ses_lock); 271 281 } 272 282 273 283 return count; ··· 285 277 static int cifs_stats_proc_show(struct seq_file *m, void *v) 286 278 { 287 279 int i; 288 - struct list_head *tmp; 280 + struct list_head *tmp1, *tmp2, *tmp3; 281 + struct TCP_Server_Info *server; 282 + struct cifsSesInfo *ses; 289 283 struct cifsTconInfo *tcon; 290 284 291 285 seq_printf(m, ··· 316 306 GlobalCurrentXid, GlobalMaxActiveXid); 317 307 318 308 i = 0; 319 - read_lock(&GlobalSMBSeslock); 320 - list_for_each(tmp, &GlobalTreeConnectionList) { 321 - i++; 322 - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 323 - seq_printf(m, "\n%d) %s", i, tcon->treeName); 324 - if (tcon->tidStatus == CifsNeedReconnect) 325 - seq_puts(m, "\tDISCONNECTED "); 326 - seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", 327 - atomic_read(&tcon->num_smbs_sent), 328 - atomic_read(&tcon->num_oplock_brks)); 329 - seq_printf(m, "\nReads: %d Bytes: %lld", 330 - atomic_read(&tcon->num_reads), 331 - (long long)(tcon->bytes_read)); 332 - seq_printf(m, "\nWrites: %d Bytes: %lld", 333 - atomic_read(&tcon->num_writes), 334 - (long long)(tcon->bytes_written)); 335 - seq_printf(m, 336 - "\nLocks: %d HardLinks: %d Symlinks: %d", 337 - atomic_read(&tcon->num_locks), 338 - atomic_read(&tcon->num_hardlinks), 339 - atomic_read(&tcon->num_symlinks)); 340 - 341 - seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d", 342 - atomic_read(&tcon->num_opens), 343 - atomic_read(&tcon->num_closes), 344 - atomic_read(&tcon->num_deletes)); 345 - seq_printf(m, "\nMkdirs: %d Rmdirs: %d", 346 - atomic_read(&tcon->num_mkdirs), 347 - atomic_read(&tcon->num_rmdirs)); 348 - seq_printf(m, "\nRenames: %d T2 Renames %d", 349 - atomic_read(&tcon->num_renames), 350 - atomic_read(&tcon->num_t2renames)); 351 - seq_printf(m, "\nFindFirst: %d FNext %d FClose %d", 352 - atomic_read(&tcon->num_ffirst), 353 - atomic_read(&tcon->num_fnext), 354 - atomic_read(&tcon->num_fclose)); 309 + read_lock(&cifs_tcp_ses_lock); 310 + list_for_each(tmp1, &cifs_tcp_ses_list) { 311 + server = list_entry(tmp1, struct TCP_Server_Info, 312 + tcp_ses_list); 313 + list_for_each(tmp2, &server->smb_ses_list) { 314 + ses = list_entry(tmp2, struct cifsSesInfo, 315 + smb_ses_list); 316 + list_for_each(tmp3, &ses->tcon_list) { 317 + tcon = list_entry(tmp3, 318 + struct cifsTconInfo, 319 + tcon_list); 320 + i++; 321 + seq_printf(m, "\n%d) %s", i, tcon->treeName); 322 + if (tcon->need_reconnect) 323 + seq_puts(m, "\tDISCONNECTED "); 324 + seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", 325 + atomic_read(&tcon->num_smbs_sent), 326 + atomic_read(&tcon->num_oplock_brks)); 327 + seq_printf(m, "\nReads: %d Bytes: %lld", 328 + atomic_read(&tcon->num_reads), 329 + (long long)(tcon->bytes_read)); 330 + seq_printf(m, "\nWrites: %d Bytes: %lld", 331 + atomic_read(&tcon->num_writes), 332 + (long long)(tcon->bytes_written)); 333 + seq_printf(m, "\nLocks: %d HardLinks: %d " 334 + "Symlinks: %d", 335 + atomic_read(&tcon->num_locks), 336 + atomic_read(&tcon->num_hardlinks), 337 + atomic_read(&tcon->num_symlinks)); 338 + seq_printf(m, "\nOpens: %d Closes: %d" 339 + "Deletes: %d", 340 + atomic_read(&tcon->num_opens), 341 + atomic_read(&tcon->num_closes), 342 + atomic_read(&tcon->num_deletes)); 343 + seq_printf(m, "\nMkdirs: %d Rmdirs: %d", 344 + atomic_read(&tcon->num_mkdirs), 345 + atomic_read(&tcon->num_rmdirs)); 346 + seq_printf(m, "\nRenames: %d T2 Renames %d", 347 + atomic_read(&tcon->num_renames), 348 + atomic_read(&tcon->num_t2renames)); 349 + seq_printf(m, "\nFindFirst: %d FNext %d " 350 + "FClose %d", 351 + atomic_read(&tcon->num_ffirst), 352 + atomic_read(&tcon->num_fnext), 353 + atomic_read(&tcon->num_fclose)); 354 + } 355 + } 355 356 } 356 - read_unlock(&GlobalSMBSeslock); 357 + read_unlock(&cifs_tcp_ses_lock); 357 358 358 359 seq_putc(m, '\n'); 359 360 return 0;
+47 -24
fs/cifs/cifs_dfs_ref.c
··· 106 106 /** 107 107 * compose_mount_options - creates mount options for refferral 108 108 * @sb_mountdata: parent/root DFS mount options (template) 109 - * @ref_unc: refferral server UNC 109 + * @dentry: point where we are going to mount 110 + * @ref: server's referral 110 111 * @devname: pointer for saving device name 111 112 * 112 113 * creates mount options for submount based on template options sb_mountdata ··· 117 116 * Caller is responcible for freeing retunrned value if it is not error. 118 117 */ 119 118 static char *compose_mount_options(const char *sb_mountdata, 120 - const char *ref_unc, 119 + struct dentry *dentry, 120 + const struct dfs_info3_param *ref, 121 121 char **devname) 122 122 { 123 123 int rc; ··· 128 126 char *srvIP = NULL; 129 127 char sep = ','; 130 128 int off, noff; 129 + char *fullpath; 131 130 132 131 if (sb_mountdata == NULL) 133 132 return ERR_PTR(-EINVAL); 134 133 135 - *devname = cifs_get_share_name(ref_unc); 134 + *devname = cifs_get_share_name(ref->node_name); 136 135 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 137 136 if (rc != 0) { 138 137 cERROR(1, ("%s: Failed to resolve server part of %s to IP", ··· 141 138 mountdata = ERR_PTR(rc); 142 139 goto compose_mount_options_out; 143 140 } 144 - md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3; 141 + /* md_len = strlen(...) + 12 for 'sep+prefixpath=' 142 + * assuming that we have 'unc=' and 'ip=' in 143 + * the original sb_mountdata 144 + */ 145 + md_len = strlen(sb_mountdata) + strlen(srvIP) + 146 + strlen(ref->node_name) + 12; 145 147 mountdata = kzalloc(md_len+1, GFP_KERNEL); 146 148 if (mountdata == NULL) { 147 149 mountdata = ERR_PTR(-ENOMEM); ··· 160 152 strncpy(mountdata, sb_mountdata, 5); 161 153 off += 5; 162 154 } 163 - while ((tkn_e = strchr(sb_mountdata+off, sep))) { 164 - noff = (tkn_e - (sb_mountdata+off)) + 1; 165 - if (strnicmp(sb_mountdata+off, "unc=", 4) == 0) { 155 + 156 + do { 157 + tkn_e = strchr(sb_mountdata + off, sep); 158 + if (tkn_e == NULL) 159 + noff = strlen(sb_mountdata + off); 160 + else 161 + noff = tkn_e - (sb_mountdata + off) + 1; 162 + 163 + if (strnicmp(sb_mountdata + off, "unc=", 4) == 0) { 166 164 off += noff; 167 165 continue; 168 166 } 169 - if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) { 167 + if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) { 170 168 off += noff; 171 169 continue; 172 170 } 173 - if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) { 171 + if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) { 174 172 off += noff; 175 173 continue; 176 174 } 177 - strncat(mountdata, sb_mountdata+off, noff); 175 + strncat(mountdata, sb_mountdata + off, noff); 178 176 off += noff; 179 - } 180 - strcat(mountdata, sb_mountdata+off); 177 + } while (tkn_e); 178 + strcat(mountdata, sb_mountdata + off); 181 179 mountdata[md_len] = '\0'; 182 180 183 181 /* copy new IP and ref share name */ 184 - strcat(mountdata, ",ip="); 182 + if (mountdata[strlen(mountdata) - 1] != sep) 183 + strncat(mountdata, &sep, 1); 184 + strcat(mountdata, "ip="); 185 185 strcat(mountdata, srvIP); 186 - strcat(mountdata, ",unc="); 186 + strncat(mountdata, &sep, 1); 187 + strcat(mountdata, "unc="); 187 188 strcat(mountdata, *devname); 188 189 189 190 /* find & copy prefixpath */ 190 - tkn_e = strchr(ref_unc+2, '\\'); 191 - if (tkn_e) { 192 - tkn_e = strchr(tkn_e+1, '\\'); 193 - if (tkn_e) { 194 - strcat(mountdata, ",prefixpath="); 195 - strcat(mountdata, tkn_e+1); 196 - } 191 + tkn_e = strchr(ref->node_name + 2, '\\'); 192 + if (tkn_e == NULL) /* invalid unc, missing share name*/ 193 + goto compose_mount_options_out; 194 + 195 + fullpath = build_path_from_dentry(dentry); 196 + tkn_e = strchr(tkn_e + 1, '\\'); 197 + if (tkn_e || strlen(fullpath) - (ref->path_consumed)) { 198 + strncat(mountdata, &sep, 1); 199 + strcat(mountdata, "prefixpath="); 200 + if (tkn_e) 201 + strcat(mountdata, tkn_e + 1); 202 + strcat(mountdata, fullpath + (ref->path_consumed)); 197 203 } 204 + kfree(fullpath); 198 205 199 206 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ 200 207 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ ··· 221 198 222 199 223 200 static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, 224 - struct dentry *dentry, char *ref_unc) 201 + struct dentry *dentry, const struct dfs_info3_param *ref) 225 202 { 226 203 struct cifs_sb_info *cifs_sb; 227 204 struct vfsmount *mnt; ··· 230 207 231 208 cifs_sb = CIFS_SB(dentry->d_inode->i_sb); 232 209 mountdata = compose_mount_options(cifs_sb->mountdata, 233 - ref_unc, &devname); 210 + dentry, ref, &devname); 234 211 235 212 if (IS_ERR(mountdata)) 236 213 return (struct vfsmount *)mountdata; ··· 333 310 } 334 311 mnt = cifs_dfs_do_refmount(nd->path.mnt, 335 312 nd->path.dentry, 336 - referrals[i].node_name); 313 + referrals + i); 337 314 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", 338 315 __func__, 339 316 referrals[i].node_name, mnt));
+2 -2
fs/cifs/cifs_spnego.c
··· 73 73 * strlen(";sec=ntlmsspi") */ 74 74 #define MAX_MECH_STR_LEN 13 75 75 76 - /* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ 77 - #define MAX_IPV6_ADDR_LEN 42 76 + /* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */ 77 + #define MAX_IPV6_ADDR_LEN 43 78 78 79 79 /* strlen of "host=" */ 80 80 #define HOST_KEY_LEN 5
+15 -15
fs/cifs/cifsfs.c
··· 514 514 tcon = cifs_sb->tcon; 515 515 if (tcon == NULL) 516 516 return; 517 - down(&tcon->tconSem); 518 - if (atomic_read(&tcon->useCount) == 1) 517 + 518 + read_lock(&cifs_tcp_ses_lock); 519 + if (tcon->tc_count == 1) 519 520 tcon->tidStatus = CifsExiting; 520 - up(&tcon->tconSem); 521 + read_unlock(&cifs_tcp_ses_lock); 521 522 522 523 /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ 523 524 /* cancel_notify_requests(tcon); */ ··· 1014 1013 not bother sending an oplock release if session 1015 1014 to server still is disconnected since oplock 1016 1015 already released by the server in that case */ 1017 - if (pTcon->tidStatus != CifsNeedReconnect) { 1016 + if (!pTcon->need_reconnect) { 1018 1017 rc = CIFSSMBLock(0, pTcon, netfid, 1019 1018 0 /* len */ , 0 /* offset */, 0, 1020 1019 0, LOCKING_ANDX_OPLOCK_RELEASE, ··· 1032 1031 static int cifs_dnotify_thread(void *dummyarg) 1033 1032 { 1034 1033 struct list_head *tmp; 1035 - struct cifsSesInfo *ses; 1034 + struct TCP_Server_Info *server; 1036 1035 1037 1036 do { 1038 1037 if (try_to_freeze()) 1039 1038 continue; 1040 1039 set_current_state(TASK_INTERRUPTIBLE); 1041 1040 schedule_timeout(15*HZ); 1042 - read_lock(&GlobalSMBSeslock); 1043 1041 /* check if any stuck requests that need 1044 1042 to be woken up and wakeq so the 1045 1043 thread can wake up and error out */ 1046 - list_for_each(tmp, &GlobalSMBSessionList) { 1047 - ses = list_entry(tmp, struct cifsSesInfo, 1048 - cifsSessionList); 1049 - if (ses->server && atomic_read(&ses->server->inFlight)) 1050 - wake_up_all(&ses->server->response_q); 1044 + read_lock(&cifs_tcp_ses_lock); 1045 + list_for_each(tmp, &cifs_tcp_ses_list) { 1046 + server = list_entry(tmp, struct TCP_Server_Info, 1047 + tcp_ses_list); 1048 + if (atomic_read(&server->inFlight)) 1049 + wake_up_all(&server->response_q); 1051 1050 } 1052 - read_unlock(&GlobalSMBSeslock); 1051 + read_unlock(&cifs_tcp_ses_lock); 1053 1052 } while (!kthread_should_stop()); 1054 1053 1055 1054 return 0; ··· 1060 1059 { 1061 1060 int rc = 0; 1062 1061 cifs_proc_init(); 1063 - /* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ 1064 - INIT_LIST_HEAD(&GlobalSMBSessionList); 1065 - INIT_LIST_HEAD(&GlobalTreeConnectionList); 1062 + INIT_LIST_HEAD(&cifs_tcp_ses_list); 1066 1063 INIT_LIST_HEAD(&GlobalOplock_Q); 1067 1064 #ifdef CONFIG_CIFS_EXPERIMENTAL 1068 1065 INIT_LIST_HEAD(&GlobalDnotifyReqList); ··· 1088 1089 GlobalMaxActiveXid = 0; 1089 1090 memset(Local_System_Name, 0, 15); 1090 1091 rwlock_init(&GlobalSMBSeslock); 1092 + rwlock_init(&cifs_tcp_ses_lock); 1091 1093 spin_lock_init(&GlobalMid_Lock); 1092 1094 1093 1095 if (cifs_max_pending < 2) {
+22 -19
fs/cifs/cifsglob.h
··· 85 85 }; 86 86 87 87 enum protocolEnum { 88 - IPV4 = 0, 89 - IPV6, 88 + TCP = 0, 90 89 SCTP 91 90 /* Netbios frames protocol not supported at this time */ 92 91 }; ··· 121 122 */ 122 123 123 124 struct TCP_Server_Info { 125 + struct list_head tcp_ses_list; 126 + struct list_head smb_ses_list; 127 + int srv_count; /* reference counter */ 124 128 /* 15 character server name + 0x20 16th byte indicating type = srv */ 125 129 char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; 126 130 char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; ··· 145 143 bool svlocal:1; /* local server or remote */ 146 144 bool noblocksnd; /* use blocking sendmsg */ 147 145 bool noautotune; /* do not autotune send buf sizes */ 148 - atomic_t socketUseCount; /* number of open cifs sessions on socket */ 149 146 atomic_t inFlight; /* number of requests on the wire to server */ 150 147 #ifdef CONFIG_CIFS_STATS2 151 148 atomic_t inSend; /* requests trying to send */ ··· 195 194 * Session structure. One of these for each uid session with a particular host 196 195 */ 197 196 struct cifsSesInfo { 198 - struct list_head cifsSessionList; 197 + struct list_head smb_ses_list; 198 + struct list_head tcon_list; 199 199 struct semaphore sesSem; 200 200 #if 0 201 201 struct cifsUidInfo *uidInfo; /* pointer to user info */ 202 202 #endif 203 203 struct TCP_Server_Info *server; /* pointer to server info */ 204 - atomic_t inUse; /* # of mounts (tree connections) on this ses */ 204 + int ses_count; /* reference counter */ 205 205 enum statusEnum status; 206 206 unsigned overrideSecFlg; /* if non-zero override global sec flags */ 207 207 __u16 ipc_tid; /* special tid for connection to IPC share */ ··· 218 216 char userName[MAX_USERNAME_SIZE + 1]; 219 217 char *domainName; 220 218 char *password; 219 + bool need_reconnect:1; /* connection reset, uid now invalid */ 221 220 }; 222 221 /* no more than one of the following three session flags may be set */ 223 222 #define CIFS_SES_NT4 1 ··· 233 230 * session 234 231 */ 235 232 struct cifsTconInfo { 236 - struct list_head cifsConnectionList; 233 + struct list_head tcon_list; 234 + int tc_count; 237 235 struct list_head openFileList; 238 - struct semaphore tconSem; 239 236 struct cifsSesInfo *ses; /* pointer to session associated with */ 240 237 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ 241 238 char *nativeFileSystem; 242 239 __u16 tid; /* The 2 byte tree id */ 243 240 __u16 Flags; /* optional support bits */ 244 241 enum statusEnum tidStatus; 245 - atomic_t useCount; /* how many explicit/implicit mounts to share */ 246 242 #ifdef CONFIG_CIFS_STATS 247 243 atomic_t num_smbs_sent; 248 244 atomic_t num_writes; ··· 290 288 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol 291 289 for this mount even if server would support */ 292 290 bool local_lease:1; /* check leases (only) on local system not remote */ 291 + bool need_reconnect:1; /* connection reset, tid now invalid */ 293 292 /* BB add field for back pointer to sb struct(s)? */ 294 293 }; 295 294 ··· 591 588 #endif 592 589 593 590 /* 594 - * The list of servers that did not respond with NT LM 0.12. 595 - * This list helps improve performance and eliminate the messages indicating 596 - * that we had a communications error talking to the server in this list. 591 + * the list of TCP_Server_Info structures, ie each of the sockets 592 + * connecting our client to a distinct server (ip address), is 593 + * chained together by cifs_tcp_ses_list. The list of all our SMB 594 + * sessions (and from that the tree connections) can be found 595 + * by iterating over cifs_tcp_ses_list 597 596 */ 598 - /* Feature not supported */ 599 - /* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */ 597 + GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; 600 598 601 599 /* 602 - * The following is a hash table of all the users we know about. 600 + * This lock protects the cifs_tcp_ses_list, the list of smb sessions per 601 + * tcp session, and the list of tcon's per smb session. It also protects 602 + * the reference counters for the server, smb session, and tcon. Finally, 603 + * changes to the tcon->tidStatus should be done while holding this lock. 603 604 */ 604 - GLOBAL_EXTERN struct smbUidInfo *GlobalUidList[UID_HASH]; 605 - 606 - /* GLOBAL_EXTERN struct list_head GlobalServerList; BB not implemented yet */ 607 - GLOBAL_EXTERN struct list_head GlobalSMBSessionList; 608 - GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; 605 + GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 609 606 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 610 607 611 608 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
+73 -63
fs/cifs/cifssmb.c
··· 190 190 /* need to prevent multiple threads trying to 191 191 simultaneously reconnect the same SMB session */ 192 192 down(&tcon->ses->sesSem); 193 - if (tcon->ses->status == CifsNeedReconnect) 193 + if (tcon->ses->need_reconnect) 194 194 rc = cifs_setup_session(0, tcon->ses, 195 195 nls_codepage); 196 - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { 196 + if (!rc && (tcon->need_reconnect)) { 197 197 mark_open_files_invalid(tcon); 198 198 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 199 199 tcon, nls_codepage); ··· 295 295 check for tcp and smb session status done differently 296 296 for those three - in the calling routine */ 297 297 if (tcon) { 298 - if (tcon->tidStatus == CifsExiting) { 298 + if (tcon->need_reconnect) { 299 299 /* only tree disconnect, open, and write, 300 300 (and ulogoff which does not have tcon) 301 301 are allowed as we start force umount */ ··· 337 337 /* need to prevent multiple threads trying to 338 338 simultaneously reconnect the same SMB session */ 339 339 down(&tcon->ses->sesSem); 340 - if (tcon->ses->status == CifsNeedReconnect) 340 + if (tcon->ses->need_reconnect) 341 341 rc = cifs_setup_session(0, tcon->ses, 342 342 nls_codepage); 343 - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { 343 + if (!rc && (tcon->need_reconnect)) { 344 344 mark_open_files_invalid(tcon); 345 345 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 346 346 tcon, nls_codepage); ··· 664 664 rc = -EIO; 665 665 goto neg_err_exit; 666 666 } 667 - 668 - if (server->socketUseCount.counter > 1) { 667 + read_lock(&cifs_tcp_ses_lock); 668 + if (server->srv_count > 1) { 669 + read_unlock(&cifs_tcp_ses_lock); 669 670 if (memcmp(server->server_GUID, 670 671 pSMBr->u.extended_response. 671 672 GUID, 16) != 0) { ··· 675 674 pSMBr->u.extended_response.GUID, 676 675 16); 677 676 } 678 - } else 677 + } else { 678 + read_unlock(&cifs_tcp_ses_lock); 679 679 memcpy(server->server_GUID, 680 680 pSMBr->u.extended_response.GUID, 16); 681 + } 681 682 682 683 if (count == 16) { 683 684 server->secType = RawNTLMSSP; ··· 742 739 int rc = 0; 743 740 744 741 cFYI(1, ("In tree disconnect")); 742 + 743 + /* BB: do we need to check this? These should never be NULL. */ 744 + if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) 745 + return -EIO; 746 + 745 747 /* 746 - * If last user of the connection and 747 - * connection alive - disconnect it 748 - * If this is the last connection on the server session disconnect it 749 - * (and inside session disconnect we should check if tcp socket needs 750 - * to be freed and kernel thread woken up). 748 + * No need to return error on this operation if tid invalidated and 749 + * closed on server already e.g. due to tcp session crashing. Also, 750 + * the tcon is no longer on the list, so no need to take lock before 751 + * checking this. 751 752 */ 752 - if (tcon) 753 - down(&tcon->tconSem); 754 - else 755 - return -EIO; 756 - 757 - atomic_dec(&tcon->useCount); 758 - if (atomic_read(&tcon->useCount) > 0) { 759 - up(&tcon->tconSem); 760 - return -EBUSY; 761 - } 762 - 763 - /* No need to return error on this operation if tid invalidated and 764 - closed on server already e.g. due to tcp session crashing */ 765 - if (tcon->tidStatus == CifsNeedReconnect) { 766 - up(&tcon->tconSem); 753 + if (tcon->need_reconnect) 767 754 return 0; 768 - } 769 755 770 - if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) { 771 - up(&tcon->tconSem); 772 - return -EIO; 773 - } 774 756 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 775 757 (void **)&smb_buffer); 776 - if (rc) { 777 - up(&tcon->tconSem); 758 + if (rc) 778 759 return rc; 779 - } 780 760 781 761 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); 782 762 if (rc) 783 763 cFYI(1, ("Tree disconnect failed %d", rc)); 784 764 785 - up(&tcon->tconSem); 786 - 787 765 /* No need to return error on this operation if tid invalidated and 788 - closed on server already e.g. due to tcp session crashing */ 766 + closed on server already e.g. due to tcp session crashing */ 789 767 if (rc == -EAGAIN) 790 768 rc = 0; 791 769 ··· 780 796 int rc = 0; 781 797 782 798 cFYI(1, ("In SMBLogoff for session disconnect")); 783 - if (ses) 784 - down(&ses->sesSem); 785 - else 799 + 800 + /* 801 + * BB: do we need to check validity of ses and server? They should 802 + * always be valid since we have an active reference. If not, that 803 + * should probably be a BUG() 804 + */ 805 + if (!ses || !ses->server) 786 806 return -EIO; 787 807 788 - atomic_dec(&ses->inUse); 789 - if (atomic_read(&ses->inUse) > 0) { 790 - up(&ses->sesSem); 791 - return -EBUSY; 792 - } 808 + down(&ses->sesSem); 809 + if (ses->need_reconnect) 810 + goto session_already_dead; /* no need to send SMBlogoff if uid 811 + already closed due to reconnect */ 793 812 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); 794 813 if (rc) { 795 814 up(&ses->sesSem); 796 815 return rc; 797 816 } 798 817 799 - if (ses->server) { 800 - pSMB->hdr.Mid = GetNextMid(ses->server); 818 + pSMB->hdr.Mid = GetNextMid(ses->server); 801 819 802 - if (ses->server->secMode & 820 + if (ses->server->secMode & 803 821 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 804 822 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; 805 - } 806 823 807 824 pSMB->hdr.Uid = ses->Suid; 808 825 809 826 pSMB->AndXCommand = 0xFF; 810 827 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); 811 - if (ses->server) { 812 - atomic_dec(&ses->server->socketUseCount); 813 - if (atomic_read(&ses->server->socketUseCount) == 0) { 814 - spin_lock(&GlobalMid_Lock); 815 - ses->server->tcpStatus = CifsExiting; 816 - spin_unlock(&GlobalMid_Lock); 817 - rc = -ESHUTDOWN; 818 - } 819 - } 828 + session_already_dead: 820 829 up(&ses->sesSem); 821 830 822 831 /* if session dead then we do not need to do ulogoff, ··· 3899 3922 return rc; 3900 3923 } 3901 3924 3925 + /* computes length of UCS string converted to host codepage 3926 + * @src: UCS string 3927 + * @maxlen: length of the input string in UCS characters 3928 + * (not in bytes) 3929 + * 3930 + * return: size of input string in host codepage 3931 + */ 3932 + static int hostlen_fromUCS(const __le16 *src, const int maxlen, 3933 + const struct nls_table *nls_codepage) { 3934 + int i; 3935 + int hostlen = 0; 3936 + char to[4]; 3937 + int charlen; 3938 + for (i = 0; (i < maxlen) && src[i]; ++i) { 3939 + charlen = nls_codepage->uni2char(le16_to_cpu(src[i]), 3940 + to, NLS_MAX_CHARSET_SIZE); 3941 + hostlen += charlen > 0 ? charlen : 1; 3942 + } 3943 + return hostlen; 3944 + } 3945 + 3902 3946 /* parses DFS refferal V3 structure 3903 3947 * caller is responsible for freeing target_nodes 3904 3948 * returns: ··· 3930 3932 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, 3931 3933 unsigned int *num_of_nodes, 3932 3934 struct dfs_info3_param **target_nodes, 3933 - const struct nls_table *nls_codepage) 3935 + const struct nls_table *nls_codepage, int remap, 3936 + const char *searchName) 3934 3937 { 3935 3938 int i, rc = 0; 3936 3939 char *data_end; ··· 3982 3983 struct dfs_info3_param *node = (*target_nodes)+i; 3983 3984 3984 3985 node->flags = le16_to_cpu(pSMBr->DFSFlags); 3985 - node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); 3986 + if (is_unicode) { 3987 + __le16 *tmp = kmalloc(strlen(searchName)*2, GFP_KERNEL); 3988 + cifsConvertToUCS((__le16 *) tmp, searchName, 3989 + PATH_MAX, nls_codepage, remap); 3990 + node->path_consumed = hostlen_fromUCS(tmp, 3991 + le16_to_cpu(pSMBr->PathConsumed)/2, 3992 + nls_codepage); 3993 + kfree(tmp); 3994 + } else 3995 + node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); 3996 + 3986 3997 node->server_type = le16_to_cpu(ref->ServerType); 3987 3998 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); 3988 3999 ··· 4125 4116 4126 4117 /* parse returned result into more usable form */ 4127 4118 rc = parse_DFS_referrals(pSMBr, num_of_nodes, 4128 - target_nodes, nls_codepage); 4119 + target_nodes, nls_codepage, remap, 4120 + searchName); 4129 4121 4130 4122 GetDFSRefExit: 4131 4123 cifs_buf_release(pSMB);
+413 -416
fs/cifs/connect.c
··· 124 124 cifs_reconnect(struct TCP_Server_Info *server) 125 125 { 126 126 int rc = 0; 127 - struct list_head *tmp; 127 + struct list_head *tmp, *tmp2; 128 128 struct cifsSesInfo *ses; 129 129 struct cifsTconInfo *tcon; 130 130 struct mid_q_entry *mid_entry; ··· 144 144 145 145 /* before reconnecting the tcp session, mark the smb session (uid) 146 146 and the tid bad so they are not used until reconnected */ 147 - read_lock(&GlobalSMBSeslock); 148 - list_for_each(tmp, &GlobalSMBSessionList) { 149 - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 150 - if (ses->server) { 151 - if (ses->server == server) { 152 - ses->status = CifsNeedReconnect; 153 - ses->ipc_tid = 0; 154 - } 147 + read_lock(&cifs_tcp_ses_lock); 148 + list_for_each(tmp, &server->smb_ses_list) { 149 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 150 + ses->need_reconnect = true; 151 + ses->ipc_tid = 0; 152 + list_for_each(tmp2, &ses->tcon_list) { 153 + tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list); 154 + tcon->need_reconnect = true; 155 155 } 156 - /* else tcp and smb sessions need reconnection */ 157 156 } 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 - } 163 - read_unlock(&GlobalSMBSeslock); 157 + read_unlock(&cifs_tcp_ses_lock); 164 158 /* do not want to be sending data on a socket we are freeing */ 165 159 down(&server->tcpSem); 166 160 if (server->ssocket) { ··· 187 193 while ((server->tcpStatus != CifsExiting) && 188 194 (server->tcpStatus != CifsGood)) { 189 195 try_to_freeze(); 190 - if (server->protocolType == IPV6) { 196 + if (server->addr.sockAddr6.sin6_family == AF_INET6) { 191 197 rc = ipv6_connect(&server->addr.sockAddr6, 192 198 &server->ssocket, server->noautotune); 193 199 } else { ··· 411 417 msleep(1); /* minimum sleep to prevent looping 412 418 allowing socket to clear and app threads to set 413 419 tcpStatus CifsNeedReconnect if server hung */ 414 - if (pdu_length < 4) 420 + if (pdu_length < 4) { 421 + iov.iov_base = (4 - pdu_length) + 422 + (char *)smb_buffer; 423 + iov.iov_len = pdu_length; 424 + smb_msg.msg_control = NULL; 425 + smb_msg.msg_controllen = 0; 415 426 goto incomplete_rcv; 416 - else 427 + } else 417 428 continue; 418 429 } else if (length <= 0) { 419 430 if (server->tcpStatus == CifsNew) { ··· 653 654 } 654 655 } /* end while !EXITING */ 655 656 657 + /* take it off the list, if it's not already */ 658 + write_lock(&cifs_tcp_ses_lock); 659 + list_del_init(&server->tcp_ses_list); 660 + write_unlock(&cifs_tcp_ses_lock); 661 + 656 662 spin_lock(&GlobalMid_Lock); 657 663 server->tcpStatus = CifsExiting; 658 664 spin_unlock(&GlobalMid_Lock); ··· 690 686 if (smallbuf) /* no sense logging a debug message if NULL */ 691 687 cifs_small_buf_release(smallbuf); 692 688 693 - read_lock(&GlobalSMBSeslock); 689 + /* 690 + * BB: we shouldn't have to do any of this. It shouldn't be 691 + * possible to exit from the thread with active SMB sessions 692 + */ 693 + read_lock(&cifs_tcp_ses_lock); 694 694 if (list_empty(&server->pending_mid_q)) { 695 695 /* loop through server session structures attached to this and 696 696 mark them dead */ 697 - list_for_each(tmp, &GlobalSMBSessionList) { 698 - ses = 699 - list_entry(tmp, struct cifsSesInfo, 700 - cifsSessionList); 701 - if (ses->server == server) { 702 - ses->status = CifsExiting; 703 - ses->server = NULL; 704 - } 697 + list_for_each(tmp, &server->smb_ses_list) { 698 + ses = list_entry(tmp, struct cifsSesInfo, 699 + smb_ses_list); 700 + ses->status = CifsExiting; 701 + ses->server = NULL; 705 702 } 706 - read_unlock(&GlobalSMBSeslock); 703 + read_unlock(&cifs_tcp_ses_lock); 707 704 } else { 708 705 /* although we can not zero the server struct pointer yet, 709 706 since there are active requests which may depnd on them, 710 707 mark the corresponding SMB sessions as exiting too */ 711 - list_for_each(tmp, &GlobalSMBSessionList) { 708 + list_for_each(tmp, &server->smb_ses_list) { 712 709 ses = list_entry(tmp, struct cifsSesInfo, 713 - cifsSessionList); 714 - if (ses->server == server) 715 - ses->status = CifsExiting; 710 + smb_ses_list); 711 + ses->status = CifsExiting; 716 712 } 717 713 718 714 spin_lock(&GlobalMid_Lock); ··· 727 723 } 728 724 } 729 725 spin_unlock(&GlobalMid_Lock); 730 - read_unlock(&GlobalSMBSeslock); 726 + read_unlock(&cifs_tcp_ses_lock); 731 727 /* 1/8th of sec is more than enough time for them to exit */ 732 728 msleep(125); 733 729 } ··· 749 745 if there are any pointing to this (e.g 750 746 if a crazy root user tried to kill cifsd 751 747 kernel thread explicitly this might happen) */ 752 - write_lock(&GlobalSMBSeslock); 753 - list_for_each(tmp, &GlobalSMBSessionList) { 754 - ses = list_entry(tmp, struct cifsSesInfo, 755 - cifsSessionList); 756 - if (ses->server == server) 757 - ses->server = NULL; 748 + /* BB: This shouldn't be necessary, see above */ 749 + read_lock(&cifs_tcp_ses_lock); 750 + list_for_each(tmp, &server->smb_ses_list) { 751 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 752 + ses->server = NULL; 758 753 } 759 - write_unlock(&GlobalSMBSeslock); 754 + read_unlock(&cifs_tcp_ses_lock); 760 755 761 756 kfree(server->hostname); 762 757 task_to_wake = xchg(&server->tsk, NULL); ··· 1355 1352 return 0; 1356 1353 } 1357 1354 1355 + static struct TCP_Server_Info * 1356 + cifs_find_tcp_session(struct sockaddr *addr) 1357 + { 1358 + struct list_head *tmp; 1359 + struct TCP_Server_Info *server; 1360 + struct sockaddr_in *addr4 = (struct sockaddr_in *) addr; 1361 + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) addr; 1362 + 1363 + write_lock(&cifs_tcp_ses_lock); 1364 + list_for_each(tmp, &cifs_tcp_ses_list) { 1365 + server = list_entry(tmp, struct TCP_Server_Info, 1366 + tcp_ses_list); 1367 + /* 1368 + * the demux thread can exit on its own while still in CifsNew 1369 + * so don't accept any sockets in that state. Since the 1370 + * tcpStatus never changes back to CifsNew it's safe to check 1371 + * for this without a lock. 1372 + */ 1373 + if (server->tcpStatus == CifsNew) 1374 + continue; 1375 + 1376 + if (addr->sa_family == AF_INET && 1377 + (addr4->sin_addr.s_addr != 1378 + server->addr.sockAddr.sin_addr.s_addr)) 1379 + continue; 1380 + else if (addr->sa_family == AF_INET6 && 1381 + memcmp(&server->addr.sockAddr6.sin6_addr, 1382 + &addr6->sin6_addr, sizeof(addr6->sin6_addr))) 1383 + continue; 1384 + 1385 + ++server->srv_count; 1386 + write_unlock(&cifs_tcp_ses_lock); 1387 + cFYI(1, ("Existing tcp session with server found")); 1388 + return server; 1389 + } 1390 + write_unlock(&cifs_tcp_ses_lock); 1391 + return NULL; 1392 + } 1393 + 1394 + static void 1395 + cifs_put_tcp_session(struct TCP_Server_Info *server) 1396 + { 1397 + struct task_struct *task; 1398 + 1399 + write_lock(&cifs_tcp_ses_lock); 1400 + if (--server->srv_count > 0) { 1401 + write_unlock(&cifs_tcp_ses_lock); 1402 + return; 1403 + } 1404 + 1405 + list_del_init(&server->tcp_ses_list); 1406 + write_unlock(&cifs_tcp_ses_lock); 1407 + 1408 + spin_lock(&GlobalMid_Lock); 1409 + server->tcpStatus = CifsExiting; 1410 + spin_unlock(&GlobalMid_Lock); 1411 + 1412 + task = xchg(&server->tsk, NULL); 1413 + if (task) 1414 + force_sig(SIGKILL, task); 1415 + } 1416 + 1358 1417 static struct cifsSesInfo * 1359 - cifs_find_tcp_session(struct in_addr *target_ip_addr, 1360 - struct in6_addr *target_ip6_addr, 1361 - char *userName, struct TCP_Server_Info **psrvTcp) 1418 + cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) 1362 1419 { 1363 1420 struct list_head *tmp; 1364 1421 struct cifsSesInfo *ses; 1365 1422 1366 - *psrvTcp = NULL; 1367 - 1368 - read_lock(&GlobalSMBSeslock); 1369 - list_for_each(tmp, &GlobalSMBSessionList) { 1370 - ses = list_entry(tmp, struct cifsSesInfo, cifsSessionList); 1371 - if (!ses->server) 1423 + write_lock(&cifs_tcp_ses_lock); 1424 + list_for_each(tmp, &server->smb_ses_list) { 1425 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 1426 + if (strncmp(ses->userName, username, MAX_USERNAME_SIZE)) 1372 1427 continue; 1373 1428 1374 - if (target_ip_addr && 1375 - ses->server->addr.sockAddr.sin_addr.s_addr != target_ip_addr->s_addr) 1376 - continue; 1377 - else if (target_ip6_addr && 1378 - memcmp(&ses->server->addr.sockAddr6.sin6_addr, 1379 - target_ip6_addr, sizeof(*target_ip6_addr))) 1380 - continue; 1381 - /* BB lock server and tcp session; increment use count here?? */ 1382 - 1383 - /* found a match on the TCP session */ 1384 - *psrvTcp = ses->server; 1385 - 1386 - /* BB check if reconnection needed */ 1387 - if (strncmp(ses->userName, userName, MAX_USERNAME_SIZE) == 0) { 1388 - read_unlock(&GlobalSMBSeslock); 1389 - /* Found exact match on both TCP and 1390 - SMB sessions */ 1391 - return ses; 1392 - } 1393 - /* else tcp and smb sessions need reconnection */ 1429 + ++ses->ses_count; 1430 + write_unlock(&cifs_tcp_ses_lock); 1431 + return ses; 1394 1432 } 1395 - read_unlock(&GlobalSMBSeslock); 1396 - 1433 + write_unlock(&cifs_tcp_ses_lock); 1397 1434 return NULL; 1398 1435 } 1399 1436 1437 + static void 1438 + cifs_put_smb_ses(struct cifsSesInfo *ses) 1439 + { 1440 + int xid; 1441 + struct TCP_Server_Info *server = ses->server; 1442 + 1443 + write_lock(&cifs_tcp_ses_lock); 1444 + if (--ses->ses_count > 0) { 1445 + write_unlock(&cifs_tcp_ses_lock); 1446 + return; 1447 + } 1448 + 1449 + list_del_init(&ses->smb_ses_list); 1450 + write_unlock(&cifs_tcp_ses_lock); 1451 + 1452 + if (ses->status == CifsGood) { 1453 + xid = GetXid(); 1454 + CIFSSMBLogoff(xid, ses); 1455 + _FreeXid(xid); 1456 + } 1457 + sesInfoFree(ses); 1458 + cifs_put_tcp_session(server); 1459 + } 1460 + 1400 1461 static struct cifsTconInfo * 1401 - find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) 1462 + cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) 1402 1463 { 1403 1464 struct list_head *tmp; 1404 1465 struct cifsTconInfo *tcon; 1405 - __be32 old_ip; 1406 1466 1407 - read_lock(&GlobalSMBSeslock); 1408 - 1409 - list_for_each(tmp, &GlobalTreeConnectionList) { 1410 - cFYI(1, ("Next tcon")); 1411 - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 1412 - if (!tcon->ses || !tcon->ses->server) 1467 + write_lock(&cifs_tcp_ses_lock); 1468 + list_for_each(tmp, &ses->tcon_list) { 1469 + tcon = list_entry(tmp, struct cifsTconInfo, tcon_list); 1470 + if (tcon->tidStatus == CifsExiting) 1471 + continue; 1472 + if (strncmp(tcon->treeName, unc, MAX_TREE_SIZE)) 1413 1473 continue; 1414 1474 1415 - old_ip = tcon->ses->server->addr.sockAddr.sin_addr.s_addr; 1416 - cFYI(1, ("old ip addr: %x == new ip %x ?", 1417 - old_ip, new_target_ip_addr)); 1418 - 1419 - if (old_ip != new_target_ip_addr) 1420 - continue; 1421 - 1422 - /* BB lock tcon, server, tcp session and increment use count? */ 1423 - /* found a match on the TCP session */ 1424 - /* BB check if reconnection needed */ 1425 - cFYI(1, ("IP match, old UNC: %s new: %s", 1426 - tcon->treeName, uncName)); 1427 - 1428 - if (strncmp(tcon->treeName, uncName, MAX_TREE_SIZE)) 1429 - continue; 1430 - 1431 - cFYI(1, ("and old usr: %s new: %s", 1432 - tcon->treeName, uncName)); 1433 - 1434 - if (strncmp(tcon->ses->userName, userName, MAX_USERNAME_SIZE)) 1435 - continue; 1436 - 1437 - /* matched smb session (user name) */ 1438 - read_unlock(&GlobalSMBSeslock); 1475 + ++tcon->tc_count; 1476 + write_unlock(&cifs_tcp_ses_lock); 1439 1477 return tcon; 1440 1478 } 1441 - 1442 - read_unlock(&GlobalSMBSeslock); 1479 + write_unlock(&cifs_tcp_ses_lock); 1443 1480 return NULL; 1481 + } 1482 + 1483 + static void 1484 + cifs_put_tcon(struct cifsTconInfo *tcon) 1485 + { 1486 + int xid; 1487 + struct cifsSesInfo *ses = tcon->ses; 1488 + 1489 + write_lock(&cifs_tcp_ses_lock); 1490 + if (--tcon->tc_count > 0) { 1491 + write_unlock(&cifs_tcp_ses_lock); 1492 + return; 1493 + } 1494 + 1495 + list_del_init(&tcon->tcon_list); 1496 + write_unlock(&cifs_tcp_ses_lock); 1497 + 1498 + xid = GetXid(); 1499 + CIFSSMBTDis(xid, tcon); 1500 + _FreeXid(xid); 1501 + 1502 + DeleteTconOplockQEntries(tcon); 1503 + tconInfoFree(tcon); 1504 + cifs_put_smb_ses(ses); 1444 1505 } 1445 1506 1446 1507 int ··· 1943 1876 } 1944 1877 } 1945 1878 1946 - static void 1947 - kill_cifsd(struct TCP_Server_Info *server) 1879 + static void setup_cifs_sb(struct smb_vol *pvolume_info, 1880 + struct cifs_sb_info *cifs_sb) 1948 1881 { 1949 - struct task_struct *task; 1882 + if (pvolume_info->rsize > CIFSMaxBufSize) { 1883 + cERROR(1, ("rsize %d too large, using MaxBufSize", 1884 + pvolume_info->rsize)); 1885 + cifs_sb->rsize = CIFSMaxBufSize; 1886 + } else if ((pvolume_info->rsize) && 1887 + (pvolume_info->rsize <= CIFSMaxBufSize)) 1888 + cifs_sb->rsize = pvolume_info->rsize; 1889 + else /* default */ 1890 + cifs_sb->rsize = CIFSMaxBufSize; 1950 1891 1951 - task = xchg(&server->tsk, NULL); 1952 - if (task) 1953 - force_sig(SIGKILL, task); 1892 + if (pvolume_info->wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { 1893 + cERROR(1, ("wsize %d too large, using 4096 instead", 1894 + pvolume_info->wsize)); 1895 + cifs_sb->wsize = 4096; 1896 + } else if (pvolume_info->wsize) 1897 + cifs_sb->wsize = pvolume_info->wsize; 1898 + else 1899 + cifs_sb->wsize = min_t(const int, 1900 + PAGEVEC_SIZE * PAGE_CACHE_SIZE, 1901 + 127*1024); 1902 + /* old default of CIFSMaxBufSize was too small now 1903 + that SMB Write2 can send multiple pages in kvec. 1904 + RFC1001 does not describe what happens when frame 1905 + bigger than 128K is sent so use that as max in 1906 + conjunction with 52K kvec constraint on arch with 4K 1907 + page size */ 1908 + 1909 + if (cifs_sb->rsize < 2048) { 1910 + cifs_sb->rsize = 2048; 1911 + /* Windows ME may prefer this */ 1912 + cFYI(1, ("readsize set to minimum: 2048")); 1913 + } 1914 + /* calculate prepath */ 1915 + cifs_sb->prepath = pvolume_info->prepath; 1916 + if (cifs_sb->prepath) { 1917 + cifs_sb->prepathlen = strlen(cifs_sb->prepath); 1918 + /* we can not convert the / to \ in the path 1919 + separators in the prefixpath yet because we do not 1920 + know (until reset_cifs_unix_caps is called later) 1921 + whether POSIX PATH CAP is available. We normalize 1922 + the / to \ after reset_cifs_unix_caps is called */ 1923 + pvolume_info->prepath = NULL; 1924 + } else 1925 + cifs_sb->prepathlen = 0; 1926 + cifs_sb->mnt_uid = pvolume_info->linux_uid; 1927 + cifs_sb->mnt_gid = pvolume_info->linux_gid; 1928 + cifs_sb->mnt_file_mode = pvolume_info->file_mode; 1929 + cifs_sb->mnt_dir_mode = pvolume_info->dir_mode; 1930 + cFYI(1, ("file mode: 0x%x dir mode: 0x%x", 1931 + cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); 1932 + 1933 + if (pvolume_info->noperm) 1934 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; 1935 + if (pvolume_info->setuids) 1936 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; 1937 + if (pvolume_info->server_ino) 1938 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; 1939 + if (pvolume_info->remap) 1940 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; 1941 + if (pvolume_info->no_xattr) 1942 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; 1943 + if (pvolume_info->sfu_emul) 1944 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; 1945 + if (pvolume_info->nobrl) 1946 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; 1947 + if (pvolume_info->cifs_acl) 1948 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; 1949 + if (pvolume_info->override_uid) 1950 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; 1951 + if (pvolume_info->override_gid) 1952 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; 1953 + if (pvolume_info->dynperm) 1954 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; 1955 + if (pvolume_info->direct_io) { 1956 + cFYI(1, ("mounting share using direct i/o")); 1957 + cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; 1958 + } 1959 + 1960 + if ((pvolume_info->cifs_acl) && (pvolume_info->dynperm)) 1961 + cERROR(1, ("mount option dynperm ignored if cifsacl " 1962 + "mount option supported")); 1954 1963 } 1955 1964 1956 1965 int ··· 2035 1892 { 2036 1893 int rc = 0; 2037 1894 int xid; 2038 - int address_type = AF_INET; 2039 1895 struct socket *csocket = NULL; 2040 - struct sockaddr_in sin_server; 2041 - struct sockaddr_in6 sin_server6; 1896 + struct sockaddr addr; 1897 + struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; 1898 + struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; 2042 1899 struct smb_vol volume_info; 2043 1900 struct cifsSesInfo *pSesInfo = NULL; 2044 - struct cifsSesInfo *existingCifsSes = NULL; 2045 1901 struct cifsTconInfo *tcon = NULL; 2046 1902 struct TCP_Server_Info *srvTcp = NULL; 2047 1903 ··· 2048 1906 2049 1907 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ 2050 1908 1909 + memset(&addr, 0, sizeof(struct sockaddr)); 2051 1910 memset(&volume_info, 0, sizeof(struct smb_vol)); 2052 1911 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { 2053 1912 rc = -EINVAL; ··· 2071 1928 2072 1929 if (volume_info.UNCip && volume_info.UNC) { 2073 1930 rc = cifs_inet_pton(AF_INET, volume_info.UNCip, 2074 - &sin_server.sin_addr.s_addr); 1931 + &sin_server->sin_addr.s_addr); 2075 1932 2076 1933 if (rc <= 0) { 2077 1934 /* not ipv4 address, try ipv6 */ 2078 1935 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, 2079 - &sin_server6.sin6_addr.in6_u); 1936 + &sin_server6->sin6_addr.in6_u); 2080 1937 if (rc > 0) 2081 - address_type = AF_INET6; 1938 + addr.sa_family = AF_INET6; 2082 1939 } else { 2083 - address_type = AF_INET; 1940 + addr.sa_family = AF_INET; 2084 1941 } 2085 1942 2086 1943 if (rc <= 0) { ··· 2120 1977 } 2121 1978 } 2122 1979 2123 - if (address_type == AF_INET) 2124 - existingCifsSes = cifs_find_tcp_session(&sin_server.sin_addr, 2125 - NULL /* no ipv6 addr */, 2126 - volume_info.username, &srvTcp); 2127 - else if (address_type == AF_INET6) { 2128 - cFYI(1, ("looking for ipv6 address")); 2129 - existingCifsSes = cifs_find_tcp_session(NULL /* no ipv4 addr */, 2130 - &sin_server6.sin6_addr, 2131 - volume_info.username, &srvTcp); 2132 - } else { 2133 - rc = -EINVAL; 2134 - goto out; 2135 - } 2136 - 2137 - if (srvTcp) { 2138 - cFYI(1, ("Existing tcp session with server found")); 2139 - } else { /* create socket */ 2140 - if (volume_info.port) 2141 - sin_server.sin_port = htons(volume_info.port); 2142 - else 2143 - sin_server.sin_port = 0; 2144 - if (address_type == AF_INET6) { 1980 + srvTcp = cifs_find_tcp_session(&addr); 1981 + if (!srvTcp) { /* create socket */ 1982 + if (addr.sa_family == AF_INET6) { 2145 1983 cFYI(1, ("attempting ipv6 connect")); 2146 1984 /* BB should we allow ipv6 on port 139? */ 2147 1985 /* other OS never observed in Wild doing 139 with v6 */ 2148 - rc = ipv6_connect(&sin_server6, &csocket, 1986 + sin_server6->sin6_port = htons(volume_info.port); 1987 + rc = ipv6_connect(sin_server6, &csocket, 2149 1988 volume_info.noblocksnd); 2150 - } else 2151 - rc = ipv4_connect(&sin_server, &csocket, 1989 + } else { 1990 + sin_server->sin_port = htons(volume_info.port); 1991 + rc = ipv4_connect(sin_server, &csocket, 2152 1992 volume_info.source_rfc1001_name, 2153 1993 volume_info.target_rfc1001_name, 2154 1994 volume_info.noblocksnd, 2155 1995 volume_info.noautotune); 1996 + } 2156 1997 if (rc < 0) { 2157 - cERROR(1, ("Error connecting to IPv4 socket. " 1998 + cERROR(1, ("Error connecting to socket. " 2158 1999 "Aborting operation")); 2159 2000 if (csocket != NULL) 2160 2001 sock_release(csocket); ··· 2153 2026 } else { 2154 2027 srvTcp->noblocksnd = volume_info.noblocksnd; 2155 2028 srvTcp->noautotune = volume_info.noautotune; 2156 - memcpy(&srvTcp->addr.sockAddr, &sin_server, 2157 - sizeof(struct sockaddr_in)); 2029 + if (addr.sa_family == AF_INET6) 2030 + memcpy(&srvTcp->addr.sockAddr6, sin_server6, 2031 + sizeof(struct sockaddr_in6)); 2032 + else 2033 + memcpy(&srvTcp->addr.sockAddr, sin_server, 2034 + sizeof(struct sockaddr_in)); 2158 2035 atomic_set(&srvTcp->inFlight, 0); 2159 2036 /* BB Add code for ipv6 case too */ 2160 2037 srvTcp->ssocket = csocket; 2161 - srvTcp->protocolType = IPV4; 2162 2038 srvTcp->hostname = extract_hostname(volume_info.UNC); 2163 2039 if (IS_ERR(srvTcp->hostname)) { 2164 2040 rc = PTR_ERR(srvTcp->hostname); ··· 2191 2061 memcpy(srvTcp->server_RFC1001_name, 2192 2062 volume_info.target_rfc1001_name, 16); 2193 2063 srvTcp->sequence_number = 0; 2064 + INIT_LIST_HEAD(&srvTcp->tcp_ses_list); 2065 + INIT_LIST_HEAD(&srvTcp->smb_ses_list); 2066 + ++srvTcp->srv_count; 2067 + write_lock(&cifs_tcp_ses_lock); 2068 + list_add(&srvTcp->tcp_ses_list, 2069 + &cifs_tcp_ses_list); 2070 + write_unlock(&cifs_tcp_ses_lock); 2194 2071 } 2195 2072 } 2196 2073 2197 - if (existingCifsSes) { 2198 - pSesInfo = existingCifsSes; 2074 + pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); 2075 + if (pSesInfo) { 2199 2076 cFYI(1, ("Existing smb sess found (status=%d)", 2200 2077 pSesInfo->status)); 2078 + /* 2079 + * The existing SMB session already has a reference to srvTcp, 2080 + * so we can put back the extra one we got before 2081 + */ 2082 + cifs_put_tcp_session(srvTcp); 2083 + 2201 2084 down(&pSesInfo->sesSem); 2202 - if (pSesInfo->status == CifsNeedReconnect) { 2085 + if (pSesInfo->need_reconnect) { 2203 2086 cFYI(1, ("Session needs reconnect")); 2204 2087 rc = cifs_setup_session(xid, pSesInfo, 2205 2088 cifs_sb->local_nls); ··· 2221 2078 } else if (!rc) { 2222 2079 cFYI(1, ("Existing smb sess not found")); 2223 2080 pSesInfo = sesInfoAlloc(); 2224 - if (pSesInfo == NULL) 2081 + if (pSesInfo == NULL) { 2225 2082 rc = -ENOMEM; 2226 - else { 2227 - pSesInfo->server = srvTcp; 2228 - sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2229 - NIPQUAD(sin_server.sin_addr.s_addr)); 2083 + goto mount_fail_check; 2230 2084 } 2231 2085 2232 - if (!rc) { 2233 - /* volume_info.password freed at unmount */ 2234 - if (volume_info.password) { 2235 - pSesInfo->password = volume_info.password; 2236 - /* set to NULL to prevent freeing on exit */ 2237 - volume_info.password = NULL; 2238 - } 2239 - if (volume_info.username) 2240 - strncpy(pSesInfo->userName, 2241 - volume_info.username, 2242 - MAX_USERNAME_SIZE); 2243 - if (volume_info.domainname) { 2244 - int len = strlen(volume_info.domainname); 2245 - pSesInfo->domainName = 2246 - kmalloc(len + 1, GFP_KERNEL); 2247 - if (pSesInfo->domainName) 2248 - strcpy(pSesInfo->domainName, 2249 - volume_info.domainname); 2250 - } 2251 - pSesInfo->linux_uid = volume_info.linux_uid; 2252 - pSesInfo->overrideSecFlg = volume_info.secFlg; 2253 - down(&pSesInfo->sesSem); 2254 - /* BB FIXME need to pass vol->secFlgs BB */ 2255 - rc = cifs_setup_session(xid, pSesInfo, 2256 - cifs_sb->local_nls); 2257 - up(&pSesInfo->sesSem); 2258 - if (!rc) 2259 - atomic_inc(&srvTcp->socketUseCount); 2086 + /* new SMB session uses our srvTcp ref */ 2087 + pSesInfo->server = srvTcp; 2088 + sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2089 + NIPQUAD(sin_server->sin_addr.s_addr)); 2090 + 2091 + write_lock(&cifs_tcp_ses_lock); 2092 + list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); 2093 + write_unlock(&cifs_tcp_ses_lock); 2094 + 2095 + /* volume_info.password freed at unmount */ 2096 + if (volume_info.password) { 2097 + pSesInfo->password = volume_info.password; 2098 + /* set to NULL to prevent freeing on exit */ 2099 + volume_info.password = NULL; 2260 2100 } 2101 + if (volume_info.username) 2102 + strncpy(pSesInfo->userName, volume_info.username, 2103 + MAX_USERNAME_SIZE); 2104 + if (volume_info.domainname) { 2105 + int len = strlen(volume_info.domainname); 2106 + pSesInfo->domainName = kmalloc(len + 1, GFP_KERNEL); 2107 + if (pSesInfo->domainName) 2108 + strcpy(pSesInfo->domainName, 2109 + volume_info.domainname); 2110 + } 2111 + pSesInfo->linux_uid = volume_info.linux_uid; 2112 + pSesInfo->overrideSecFlg = volume_info.secFlg; 2113 + down(&pSesInfo->sesSem); 2114 + 2115 + /* BB FIXME need to pass vol->secFlgs BB */ 2116 + rc = cifs_setup_session(xid, pSesInfo, 2117 + cifs_sb->local_nls); 2118 + up(&pSesInfo->sesSem); 2261 2119 } 2262 2120 2263 2121 /* search for existing tcon to this server share */ 2264 2122 if (!rc) { 2265 - if (volume_info.rsize > CIFSMaxBufSize) { 2266 - cERROR(1, ("rsize %d too large, using MaxBufSize", 2267 - volume_info.rsize)); 2268 - cifs_sb->rsize = CIFSMaxBufSize; 2269 - } else if ((volume_info.rsize) && 2270 - (volume_info.rsize <= CIFSMaxBufSize)) 2271 - cifs_sb->rsize = volume_info.rsize; 2272 - else /* default */ 2273 - cifs_sb->rsize = CIFSMaxBufSize; 2123 + setup_cifs_sb(&volume_info, cifs_sb); 2274 2124 2275 - if (volume_info.wsize > PAGEVEC_SIZE * PAGE_CACHE_SIZE) { 2276 - cERROR(1, ("wsize %d too large, using 4096 instead", 2277 - volume_info.wsize)); 2278 - cifs_sb->wsize = 4096; 2279 - } else if (volume_info.wsize) 2280 - cifs_sb->wsize = volume_info.wsize; 2281 - else 2282 - cifs_sb->wsize = 2283 - min_t(const int, PAGEVEC_SIZE * PAGE_CACHE_SIZE, 2284 - 127*1024); 2285 - /* old default of CIFSMaxBufSize was too small now 2286 - that SMB Write2 can send multiple pages in kvec. 2287 - RFC1001 does not describe what happens when frame 2288 - bigger than 128K is sent so use that as max in 2289 - conjunction with 52K kvec constraint on arch with 4K 2290 - page size */ 2291 - 2292 - if (cifs_sb->rsize < 2048) { 2293 - cifs_sb->rsize = 2048; 2294 - /* Windows ME may prefer this */ 2295 - cFYI(1, ("readsize set to minimum: 2048")); 2296 - } 2297 - /* calculate prepath */ 2298 - cifs_sb->prepath = volume_info.prepath; 2299 - if (cifs_sb->prepath) { 2300 - cifs_sb->prepathlen = strlen(cifs_sb->prepath); 2301 - /* we can not convert the / to \ in the path 2302 - separators in the prefixpath yet because we do not 2303 - know (until reset_cifs_unix_caps is called later) 2304 - whether POSIX PATH CAP is available. We normalize 2305 - the / to \ after reset_cifs_unix_caps is called */ 2306 - volume_info.prepath = NULL; 2307 - } else 2308 - cifs_sb->prepathlen = 0; 2309 - cifs_sb->mnt_uid = volume_info.linux_uid; 2310 - cifs_sb->mnt_gid = volume_info.linux_gid; 2311 - cifs_sb->mnt_file_mode = volume_info.file_mode; 2312 - cifs_sb->mnt_dir_mode = volume_info.dir_mode; 2313 - cFYI(1, ("file mode: 0x%x dir mode: 0x%x", 2314 - cifs_sb->mnt_file_mode, cifs_sb->mnt_dir_mode)); 2315 - 2316 - if (volume_info.noperm) 2317 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_PERM; 2318 - if (volume_info.setuids) 2319 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SET_UID; 2320 - if (volume_info.server_ino) 2321 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_SERVER_INUM; 2322 - if (volume_info.remap) 2323 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_MAP_SPECIAL_CHR; 2324 - if (volume_info.no_xattr) 2325 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_XATTR; 2326 - if (volume_info.sfu_emul) 2327 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_UNX_EMUL; 2328 - if (volume_info.nobrl) 2329 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_NO_BRL; 2330 - if (volume_info.cifs_acl) 2331 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_CIFS_ACL; 2332 - if (volume_info.override_uid) 2333 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_UID; 2334 - if (volume_info.override_gid) 2335 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_OVERR_GID; 2336 - if (volume_info.dynperm) 2337 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DYNPERM; 2338 - if (volume_info.direct_io) { 2339 - cFYI(1, ("mounting share using direct i/o")); 2340 - cifs_sb->mnt_cifs_flags |= CIFS_MOUNT_DIRECT_IO; 2341 - } 2342 - 2343 - if ((volume_info.cifs_acl) && (volume_info.dynperm)) 2344 - cERROR(1, ("mount option dynperm ignored if cifsacl " 2345 - "mount option supported")); 2346 - 2347 - tcon = 2348 - find_unc(sin_server.sin_addr.s_addr, volume_info.UNC, 2349 - volume_info.username); 2125 + tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); 2350 2126 if (tcon) { 2351 2127 cFYI(1, ("Found match on UNC path")); 2352 - /* we can have only one retry value for a connection 2353 - to a share so for resources mounted more than once 2354 - to the same server share the last value passed in 2355 - for the retry flag is used */ 2356 - tcon->retry = volume_info.retry; 2357 - tcon->nocase = volume_info.nocase; 2358 - tcon->local_lease = volume_info.local_lease; 2128 + /* existing tcon already has a reference */ 2129 + cifs_put_smb_ses(pSesInfo); 2359 2130 if (tcon->seal != volume_info.seal) 2360 2131 cERROR(1, ("transport encryption setting " 2361 2132 "conflicts with existing tid")); 2362 2133 } else { 2363 2134 tcon = tconInfoAlloc(); 2364 - if (tcon == NULL) 2135 + if (tcon == NULL) { 2365 2136 rc = -ENOMEM; 2366 - else { 2367 - /* check for null share name ie connecting to 2368 - * dfs root */ 2137 + goto mount_fail_check; 2138 + } 2139 + tcon->ses = pSesInfo; 2369 2140 2370 - /* BB check if this works for exactly length 2371 - * three strings */ 2372 - if ((strchr(volume_info.UNC + 3, '\\') == NULL) 2373 - && (strchr(volume_info.UNC + 3, '/') == 2374 - NULL)) { 2375 - /* rc = connect_to_dfs_path(xid, pSesInfo, 2376 - "", cifs_sb->local_nls, 2377 - cifs_sb->mnt_cifs_flags & 2378 - CIFS_MOUNT_MAP_SPECIAL_CHR);*/ 2379 - cFYI(1, ("DFS root not supported")); 2380 - rc = -ENODEV; 2381 - goto out; 2382 - } else { 2383 - /* BB Do we need to wrap sesSem around 2384 - * this TCon call and Unix SetFS as 2385 - * we do on SessSetup and reconnect? */ 2386 - rc = CIFSTCon(xid, pSesInfo, 2387 - volume_info.UNC, 2388 - tcon, cifs_sb->local_nls); 2389 - cFYI(1, ("CIFS Tcon rc = %d", rc)); 2390 - if (volume_info.nodfs) { 2391 - tcon->Flags &= 2392 - ~SMB_SHARE_IS_IN_DFS; 2393 - cFYI(1, ("DFS disabled (%d)", 2394 - tcon->Flags)); 2395 - } 2396 - } 2397 - if (!rc) { 2398 - atomic_inc(&pSesInfo->inUse); 2399 - tcon->retry = volume_info.retry; 2400 - tcon->nocase = volume_info.nocase; 2401 - tcon->seal = volume_info.seal; 2141 + /* check for null share name ie connect to dfs root */ 2142 + if ((strchr(volume_info.UNC + 3, '\\') == NULL) 2143 + && (strchr(volume_info.UNC + 3, '/') == NULL)) { 2144 + /* rc = connect_to_dfs_path(...) */ 2145 + cFYI(1, ("DFS root not supported")); 2146 + rc = -ENODEV; 2147 + goto mount_fail_check; 2148 + } else { 2149 + /* BB Do we need to wrap sesSem around 2150 + * this TCon call and Unix SetFS as 2151 + * we do on SessSetup and reconnect? */ 2152 + rc = CIFSTCon(xid, pSesInfo, volume_info.UNC, 2153 + tcon, cifs_sb->local_nls); 2154 + cFYI(1, ("CIFS Tcon rc = %d", rc)); 2155 + if (volume_info.nodfs) { 2156 + tcon->Flags &= ~SMB_SHARE_IS_IN_DFS; 2157 + cFYI(1, ("DFS disabled (%d)", 2158 + tcon->Flags)); 2402 2159 } 2403 2160 } 2161 + if (rc) 2162 + goto mount_fail_check; 2163 + tcon->seal = volume_info.seal; 2164 + write_lock(&cifs_tcp_ses_lock); 2165 + list_add(&tcon->tcon_list, &pSesInfo->tcon_list); 2166 + write_unlock(&cifs_tcp_ses_lock); 2404 2167 } 2168 + 2169 + /* we can have only one retry value for a connection 2170 + to a share so for resources mounted more than once 2171 + to the same server share the last value passed in 2172 + for the retry flag is used */ 2173 + tcon->retry = volume_info.retry; 2174 + tcon->nocase = volume_info.nocase; 2175 + tcon->local_lease = volume_info.local_lease; 2405 2176 } 2406 2177 if (pSesInfo) { 2407 2178 if (pSesInfo->capabilities & CAP_LARGE_FILES) { ··· 2327 2270 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2328 2271 sb->s_time_gran = 100; 2329 2272 2330 - /* on error free sesinfo and tcon struct if needed */ 2273 + mount_fail_check: 2274 + /* on error free sesinfo and tcon struct if needed */ 2331 2275 if (rc) { 2332 - /* if session setup failed, use count is zero but 2333 - we still need to free cifsd thread */ 2334 - if (atomic_read(&srvTcp->socketUseCount) == 0) { 2335 - spin_lock(&GlobalMid_Lock); 2336 - srvTcp->tcpStatus = CifsExiting; 2337 - spin_unlock(&GlobalMid_Lock); 2338 - kill_cifsd(srvTcp); 2339 - } 2340 - /* If find_unc succeeded then rc == 0 so we can not end */ 2341 - if (tcon) /* up accidently freeing someone elses tcon struct */ 2342 - tconInfoFree(tcon); 2343 - if (existingCifsSes == NULL) { 2344 - if (pSesInfo) { 2345 - if ((pSesInfo->server) && 2346 - (pSesInfo->status == CifsGood)) { 2347 - int temp_rc; 2348 - temp_rc = CIFSSMBLogoff(xid, pSesInfo); 2349 - /* if the socketUseCount is now zero */ 2350 - if ((temp_rc == -ESHUTDOWN) && 2351 - (pSesInfo->server)) 2352 - kill_cifsd(pSesInfo->server); 2353 - } else { 2354 - cFYI(1, ("No session or bad tcon")); 2355 - if (pSesInfo->server) { 2356 - spin_lock(&GlobalMid_Lock); 2357 - srvTcp->tcpStatus = CifsExiting; 2358 - spin_unlock(&GlobalMid_Lock); 2359 - kill_cifsd(pSesInfo->server); 2360 - } 2361 - } 2362 - sesInfoFree(pSesInfo); 2363 - /* pSesInfo = NULL; */ 2364 - } 2365 - } 2366 - } else { 2367 - atomic_inc(&tcon->useCount); 2368 - cifs_sb->tcon = tcon; 2369 - tcon->ses = pSesInfo; 2370 - 2371 - /* do not care if following two calls succeed - informational */ 2372 - if (!tcon->ipc) { 2373 - CIFSSMBQFSDeviceInfo(xid, tcon); 2374 - CIFSSMBQFSAttributeInfo(xid, tcon); 2375 - } 2376 - 2377 - /* tell server which Unix caps we support */ 2378 - if (tcon->ses->capabilities & CAP_UNIX) 2379 - /* reset of caps checks mount to see if unix extensions 2380 - disabled for just this mount */ 2381 - reset_cifs_unix_caps(xid, tcon, sb, &volume_info); 2276 + /* If find_unc succeeded then rc == 0 so we can not end */ 2277 + /* up accidently freeing someone elses tcon struct */ 2278 + if (tcon) 2279 + cifs_put_tcon(tcon); 2280 + else if (pSesInfo) 2281 + cifs_put_smb_ses(pSesInfo); 2382 2282 else 2383 - tcon->unix_ext = 0; /* server does not support them */ 2384 - 2385 - /* convert forward to back slashes in prepath here if needed */ 2386 - if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) 2387 - convert_delimiter(cifs_sb->prepath, 2388 - CIFS_DIR_SEP(cifs_sb)); 2389 - 2390 - if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { 2391 - cifs_sb->rsize = 1024 * 127; 2392 - cFYI(DBG2, 2393 - ("no very large read support, rsize now 127K")); 2394 - } 2395 - if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) 2396 - cifs_sb->wsize = min(cifs_sb->wsize, 2397 - (tcon->ses->server->maxBuf - 2398 - MAX_CIFS_HDR_SIZE)); 2399 - if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) 2400 - cifs_sb->rsize = min(cifs_sb->rsize, 2401 - (tcon->ses->server->maxBuf - 2402 - MAX_CIFS_HDR_SIZE)); 2283 + cifs_put_tcp_session(srvTcp); 2284 + goto out; 2403 2285 } 2286 + cifs_sb->tcon = tcon; 2287 + 2288 + /* do not care if following two calls succeed - informational */ 2289 + if (!tcon->ipc) { 2290 + CIFSSMBQFSDeviceInfo(xid, tcon); 2291 + CIFSSMBQFSAttributeInfo(xid, tcon); 2292 + } 2293 + 2294 + /* tell server which Unix caps we support */ 2295 + if (tcon->ses->capabilities & CAP_UNIX) 2296 + /* reset of caps checks mount to see if unix extensions 2297 + disabled for just this mount */ 2298 + reset_cifs_unix_caps(xid, tcon, sb, &volume_info); 2299 + else 2300 + tcon->unix_ext = 0; /* server does not support them */ 2301 + 2302 + /* convert forward to back slashes in prepath here if needed */ 2303 + if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS) == 0) 2304 + convert_delimiter(cifs_sb->prepath, CIFS_DIR_SEP(cifs_sb)); 2305 + 2306 + if ((tcon->unix_ext == 0) && (cifs_sb->rsize > (1024 * 127))) { 2307 + cifs_sb->rsize = 1024 * 127; 2308 + cFYI(DBG2, ("no very large read support, rsize now 127K")); 2309 + } 2310 + if (!(tcon->ses->capabilities & CAP_LARGE_WRITE_X)) 2311 + cifs_sb->wsize = min(cifs_sb->wsize, 2312 + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); 2313 + if (!(tcon->ses->capabilities & CAP_LARGE_READ_X)) 2314 + cifs_sb->rsize = min(cifs_sb->rsize, 2315 + (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE)); 2404 2316 2405 2317 /* volume_info.password is freed above when existing session found 2406 2318 (in which case it is not needed anymore) but when new sesion is created ··· 3539 3513 /* above now done in SendReceive */ 3540 3514 if ((rc == 0) && (tcon != NULL)) { 3541 3515 tcon->tidStatus = CifsGood; 3516 + tcon->need_reconnect = false; 3542 3517 tcon->tid = smb_buffer_response->Tid; 3543 3518 bcc_ptr = pByteArea(smb_buffer_response); 3544 3519 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); ··· 3611 3584 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3612 3585 { 3613 3586 int rc = 0; 3614 - int xid; 3615 - struct cifsSesInfo *ses = NULL; 3616 3587 char *tmp; 3617 3588 3618 - xid = GetXid(); 3619 - 3620 - if (cifs_sb->tcon) { 3621 - ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ 3622 - rc = CIFSSMBTDis(xid, cifs_sb->tcon); 3623 - if (rc == -EBUSY) { 3624 - FreeXid(xid); 3625 - return 0; 3626 - } 3627 - DeleteTconOplockQEntries(cifs_sb->tcon); 3628 - tconInfoFree(cifs_sb->tcon); 3629 - if ((ses) && (ses->server)) { 3630 - /* save off task so we do not refer to ses later */ 3631 - cFYI(1, ("About to do SMBLogoff ")); 3632 - rc = CIFSSMBLogoff(xid, ses); 3633 - if (rc == -EBUSY) { 3634 - FreeXid(xid); 3635 - return 0; 3636 - } else if (rc == -ESHUTDOWN) { 3637 - cFYI(1, ("Waking up socket by sending signal")); 3638 - if (ses->server) 3639 - kill_cifsd(ses->server); 3640 - rc = 0; 3641 - } /* else - we have an smb session 3642 - left on this socket do not kill cifsd */ 3643 - } else 3644 - cFYI(1, ("No session or bad tcon")); 3645 - } 3589 + if (cifs_sb->tcon) 3590 + cifs_put_tcon(cifs_sb->tcon); 3646 3591 3647 3592 cifs_sb->tcon = NULL; 3648 3593 tmp = cifs_sb->prepath; 3649 3594 cifs_sb->prepathlen = 0; 3650 3595 cifs_sb->prepath = NULL; 3651 3596 kfree(tmp); 3652 - if (ses) 3653 - sesInfoFree(ses); 3654 3597 3655 - FreeXid(xid); 3656 3598 return rc; 3657 3599 } 3658 3600 ··· 3737 3741 cFYI(1, ("CIFS Session Established successfully")); 3738 3742 spin_lock(&GlobalMid_Lock); 3739 3743 pSesInfo->status = CifsGood; 3744 + pSesInfo->need_reconnect = false; 3740 3745 spin_unlock(&GlobalMid_Lock); 3741 3746 } 3742 3747
+5 -2
fs/cifs/file.c
··· 493 493 if (pTcon) { 494 494 /* no sense reconnecting to close a file that is 495 495 already closed */ 496 - if (pTcon->tidStatus != CifsNeedReconnect) { 496 + if (!pTcon->need_reconnect) { 497 497 timeout = 2; 498 498 while ((atomic_read(&pSMBFile->wrtPending) != 0) 499 499 && (timeout <= 2048)) { ··· 1404 1404 if ((wbc->nr_to_write -= n_iov) <= 0) 1405 1405 done = 1; 1406 1406 index = next; 1407 - } 1407 + } else 1408 + /* Need to re-find the pages we skipped */ 1409 + index = pvec.pages[0]->index + 1; 1410 + 1408 1411 pagevec_release(&pvec); 1409 1412 } 1410 1413 if (!scanned && !done) {
+41 -49
fs/cifs/misc.c
··· 75 75 76 76 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); 77 77 if (ret_buf) { 78 - write_lock(&GlobalSMBSeslock); 79 78 atomic_inc(&sesInfoAllocCount); 80 79 ret_buf->status = CifsNew; 81 - list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); 80 + ++ret_buf->ses_count; 81 + INIT_LIST_HEAD(&ret_buf->smb_ses_list); 82 + INIT_LIST_HEAD(&ret_buf->tcon_list); 82 83 init_MUTEX(&ret_buf->sesSem); 83 - write_unlock(&GlobalSMBSeslock); 84 84 } 85 85 return ret_buf; 86 86 } ··· 93 93 return; 94 94 } 95 95 96 - write_lock(&GlobalSMBSeslock); 97 96 atomic_dec(&sesInfoAllocCount); 98 - list_del(&buf_to_free->cifsSessionList); 99 - write_unlock(&GlobalSMBSeslock); 100 97 kfree(buf_to_free->serverOS); 101 98 kfree(buf_to_free->serverDomain); 102 99 kfree(buf_to_free->serverNOS); ··· 108 111 struct cifsTconInfo *ret_buf; 109 112 ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); 110 113 if (ret_buf) { 111 - write_lock(&GlobalSMBSeslock); 112 114 atomic_inc(&tconInfoAllocCount); 113 - list_add(&ret_buf->cifsConnectionList, 114 - &GlobalTreeConnectionList); 115 115 ret_buf->tidStatus = CifsNew; 116 + ++ret_buf->tc_count; 116 117 INIT_LIST_HEAD(&ret_buf->openFileList); 117 - init_MUTEX(&ret_buf->tconSem); 118 + INIT_LIST_HEAD(&ret_buf->tcon_list); 118 119 #ifdef CONFIG_CIFS_STATS 119 120 spin_lock_init(&ret_buf->stat_lock); 120 121 #endif 121 - write_unlock(&GlobalSMBSeslock); 122 122 } 123 123 return ret_buf; 124 124 } ··· 127 133 cFYI(1, ("Null buffer passed to tconInfoFree")); 128 134 return; 129 135 } 130 - write_lock(&GlobalSMBSeslock); 131 136 atomic_dec(&tconInfoAllocCount); 132 - list_del(&buf_to_free->cifsConnectionList); 133 - write_unlock(&GlobalSMBSeslock); 134 137 kfree(buf_to_free->nativeFileSystem); 135 138 kfree(buf_to_free); 136 139 } ··· 341 350 if (current->fsuid != treeCon->ses->linux_uid) { 342 351 cFYI(1, ("Multiuser mode and UID " 343 352 "did not match tcon uid")); 344 - read_lock(&GlobalSMBSeslock); 345 - list_for_each(temp_item, &GlobalSMBSessionList) { 346 - ses = list_entry(temp_item, struct cifsSesInfo, cifsSessionList); 353 + read_lock(&cifs_tcp_ses_lock); 354 + list_for_each(temp_item, &treeCon->ses->server->smb_ses_list) { 355 + ses = list_entry(temp_item, struct cifsSesInfo, smb_ses_list); 347 356 if (ses->linux_uid == current->fsuid) { 348 357 if (ses->server == treeCon->ses->server) { 349 358 cFYI(1, ("found matching uid substitute right smb_uid")); ··· 355 364 } 356 365 } 357 366 } 358 - read_unlock(&GlobalSMBSeslock); 367 + read_unlock(&cifs_tcp_ses_lock); 359 368 } 360 369 } 361 370 } ··· 488 497 is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) 489 498 { 490 499 struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; 491 - struct list_head *tmp; 492 - struct list_head *tmp1; 500 + struct list_head *tmp, *tmp1, *tmp2; 501 + struct cifsSesInfo *ses; 493 502 struct cifsTconInfo *tcon; 503 + struct cifsInodeInfo *pCifsInode; 494 504 struct cifsFileInfo *netfile; 495 505 496 506 cFYI(1, ("Checking for oplock break or dnotify response")); ··· 546 554 return false; 547 555 548 556 /* look up tcon based on tid & uid */ 549 - read_lock(&GlobalSMBSeslock); 550 - list_for_each(tmp, &GlobalTreeConnectionList) { 551 - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 552 - if ((tcon->tid == buf->Tid) && (srv == tcon->ses->server)) { 557 + read_lock(&cifs_tcp_ses_lock); 558 + list_for_each(tmp, &srv->smb_ses_list) { 559 + ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); 560 + list_for_each(tmp1, &ses->tcon_list) { 561 + tcon = list_entry(tmp1, struct cifsTconInfo, tcon_list); 562 + if (tcon->tid != buf->Tid) 563 + continue; 564 + 553 565 cifs_stats_inc(&tcon->num_oplock_brks); 554 - list_for_each(tmp1, &tcon->openFileList) { 555 - netfile = list_entry(tmp1, struct cifsFileInfo, 566 + list_for_each(tmp2, &tcon->openFileList) { 567 + netfile = list_entry(tmp2, struct cifsFileInfo, 556 568 tlist); 557 - if (pSMB->Fid == netfile->netfid) { 558 - struct cifsInodeInfo *pCifsInode; 559 - read_unlock(&GlobalSMBSeslock); 560 - cFYI(1, 561 - ("file id match, oplock break")); 562 - pCifsInode = 563 - CIFS_I(netfile->pInode); 564 - pCifsInode->clientCanCacheAll = false; 565 - if (pSMB->OplockLevel == 0) 566 - pCifsInode->clientCanCacheRead 567 - = false; 568 - pCifsInode->oplockPending = true; 569 - AllocOplockQEntry(netfile->pInode, 570 - netfile->netfid, 571 - tcon); 572 - cFYI(1, 573 - ("about to wake up oplock thread")); 574 - if (oplockThread) 575 - wake_up_process(oplockThread); 576 - return true; 577 - } 569 + if (pSMB->Fid != netfile->netfid) 570 + continue; 571 + 572 + read_unlock(&cifs_tcp_ses_lock); 573 + cFYI(1, ("file id match, oplock break")); 574 + pCifsInode = CIFS_I(netfile->pInode); 575 + pCifsInode->clientCanCacheAll = false; 576 + if (pSMB->OplockLevel == 0) 577 + pCifsInode->clientCanCacheRead = false; 578 + pCifsInode->oplockPending = true; 579 + AllocOplockQEntry(netfile->pInode, 580 + netfile->netfid, tcon); 581 + cFYI(1, ("about to wake up oplock thread")); 582 + if (oplockThread) 583 + wake_up_process(oplockThread); 584 + 585 + return true; 578 586 } 579 - read_unlock(&GlobalSMBSeslock); 587 + read_unlock(&cifs_tcp_ses_lock); 580 588 cFYI(1, ("No matching file for oplock break")); 581 589 return true; 582 590 } 583 591 } 584 - read_unlock(&GlobalSMBSeslock); 592 + read_unlock(&cifs_tcp_ses_lock); 585 593 cFYI(1, ("Can not process oplock break for non-existent connection")); 586 594 return true; 587 595 }