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 #ifdef CONFIG_PROC_FS 108 static int cifs_debug_data_proc_show(struct seq_file *m, void *v) 109 { 110 - struct list_head *tmp; 111 - struct list_head *tmp1; 112 struct mid_q_entry *mid_entry; 113 struct cifsSesInfo *ses; 114 struct cifsTconInfo *tcon; 115 - int i; 116 117 seq_puts(m, 118 "Display Internal CIFS Data Structures for Debugging\n" ··· 123 seq_printf(m, "Servers:"); 124 125 i = 0; 126 - read_lock(&GlobalSMBSeslock); 127 - list_for_each(tmp, &GlobalSMBSessionList) { 128 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" 138 " session status: %d\t", 139 i, ses->serverName, ses->serverDomain, 140 - atomic_read(&ses->inUse), 141 - ses->serverOS, ses->serverNOS, 142 ses->capabilities, ses->status); 143 - } 144 - if (ses->server) { 145 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)); 151 152 #ifdef CONFIG_CIFS_STATS2 153 seq_printf(m, " In Send: %d In MaxReq Wait: %d", 154 - atomic_read(&ses->server->inSend), 155 - atomic_read(&ses->server->num_waiters)); 156 #endif 157 158 - seq_puts(m, "\nMIDs:\n"); 159 160 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, 164 qhead); 165 - seq_printf(m, "State: %d com: %d pid:" 166 " %d tsk: %p mid %d\n", 167 mid_entry->midState, 168 (int)mid_entry->command, ··· 204 } 205 spin_unlock(&GlobalMid_Lock); 206 } 207 - 208 } 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 - 245 seq_putc(m, '\n'); 246 247 /* BB add code to dump additional info such as TCP session info now */ ··· 231 { 232 char c; 233 int rc; 234 - struct list_head *tmp; 235 struct cifsTconInfo *tcon; 236 237 rc = get_user(c, buffer); ··· 241 return rc; 242 243 if (c == '1' || c == 'y' || c == 'Y' || c == '0') { 244 - read_lock(&GlobalSMBSeslock); 245 #ifdef CONFIG_CIFS_STATS2 246 atomic_set(&totBufAllocCount, 0); 247 atomic_set(&totSmBufAllocCount, 0); 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); 269 } 270 - read_unlock(&GlobalSMBSeslock); 271 } 272 273 return count; ··· 285 static int cifs_stats_proc_show(struct seq_file *m, void *v) 286 { 287 int i; 288 - struct list_head *tmp; 289 struct cifsTconInfo *tcon; 290 291 seq_printf(m, ··· 316 GlobalCurrentXid, GlobalMaxActiveXid); 317 318 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)); 355 } 356 - read_unlock(&GlobalSMBSeslock); 357 358 seq_putc(m, '\n'); 359 return 0;
··· 107 #ifdef CONFIG_PROC_FS 108 static int cifs_debug_data_proc_show(struct seq_file *m, void *v) 109 { 110 + struct list_head *tmp1, *tmp2, *tmp3; 111 struct mid_q_entry *mid_entry; 112 + struct TCP_Server_Info *server; 113 struct cifsSesInfo *ses; 114 struct cifsTconInfo *tcon; 115 + int i, j; 116 + __u32 dev_type; 117 118 seq_puts(m, 119 "Display Internal CIFS Data Structures for Debugging\n" ··· 122 seq_printf(m, "Servers:"); 123 124 i = 0; 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); 129 i++; 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" 142 " session status: %d\t", 143 i, ses->serverName, ses->serverDomain, 144 + ses->ses_count, ses->serverOS, ses->serverNOS, 145 ses->capabilities, ses->status); 146 + } 147 seq_printf(m, "TCP status: %d\n\tLocal Users To " 148 + "Server: %d SecMode: 0x%x Req On Wire: %d", 149 + server->tcpStatus, server->srv_count, 150 + server->secMode, 151 + atomic_read(&server->inFlight)); 152 153 #ifdef CONFIG_CIFS_STATS2 154 seq_printf(m, " In Send: %d In MaxReq Wait: %d", 155 + atomic_read(&server->inSend), 156 + atomic_read(&server->num_waiters)); 157 #endif 158 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"); 191 192 spin_lock(&GlobalMid_Lock); 193 + list_for_each(tmp3, &server->pending_mid_q) { 194 + mid_entry = list_entry(tmp3, struct mid_q_entry, 195 qhead); 196 + seq_printf(m, "\tState: %d com: %d pid:" 197 " %d tsk: %p mid %d\n", 198 mid_entry->midState, 199 (int)mid_entry->command, ··· 171 } 172 spin_unlock(&GlobalMid_Lock); 173 } 174 } 175 + read_unlock(&cifs_tcp_ses_lock); 176 seq_putc(m, '\n'); 177 178 /* BB add code to dump additional info such as TCP session info now */ ··· 234 { 235 char c; 236 int rc; 237 + struct list_head *tmp1, *tmp2, *tmp3; 238 + struct TCP_Server_Info *server; 239 + struct cifsSesInfo *ses; 240 struct cifsTconInfo *tcon; 241 242 rc = get_user(c, buffer); ··· 242 return rc; 243 244 if (c == '1' || c == 'y' || c == 'Y' || c == '0') { 245 #ifdef CONFIG_CIFS_STATS2 246 atomic_set(&totBufAllocCount, 0); 247 atomic_set(&totSmBufAllocCount, 0); 248 #endif /* CONFIG_CIFS_STATS2 */ 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 + } 279 } 280 + read_unlock(&cifs_tcp_ses_lock); 281 } 282 283 return count; ··· 277 static int cifs_stats_proc_show(struct seq_file *m, void *v) 278 { 279 int i; 280 + struct list_head *tmp1, *tmp2, *tmp3; 281 + struct TCP_Server_Info *server; 282 + struct cifsSesInfo *ses; 283 struct cifsTconInfo *tcon; 284 285 seq_printf(m, ··· 306 GlobalCurrentXid, GlobalMaxActiveXid); 307 308 i = 0; 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 + } 356 } 357 + read_unlock(&cifs_tcp_ses_lock); 358 359 seq_putc(m, '\n'); 360 return 0;
+47 -24
fs/cifs/cifs_dfs_ref.c
··· 106 /** 107 * compose_mount_options - creates mount options for refferral 108 * @sb_mountdata: parent/root DFS mount options (template) 109 - * @ref_unc: refferral server UNC 110 * @devname: pointer for saving device name 111 * 112 * creates mount options for submount based on template options sb_mountdata ··· 117 * Caller is responcible for freeing retunrned value if it is not error. 118 */ 119 static char *compose_mount_options(const char *sb_mountdata, 120 - const char *ref_unc, 121 char **devname) 122 { 123 int rc; ··· 128 char *srvIP = NULL; 129 char sep = ','; 130 int off, noff; 131 132 if (sb_mountdata == NULL) 133 return ERR_PTR(-EINVAL); 134 135 - *devname = cifs_get_share_name(ref_unc); 136 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 137 if (rc != 0) { 138 cERROR(1, ("%s: Failed to resolve server part of %s to IP", ··· 141 mountdata = ERR_PTR(rc); 142 goto compose_mount_options_out; 143 } 144 - md_len = strlen(sb_mountdata) + strlen(srvIP) + strlen(ref_unc) + 3; 145 mountdata = kzalloc(md_len+1, GFP_KERNEL); 146 if (mountdata == NULL) { 147 mountdata = ERR_PTR(-ENOMEM); ··· 160 strncpy(mountdata, sb_mountdata, 5); 161 off += 5; 162 } 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) { 166 off += noff; 167 continue; 168 } 169 - if (strnicmp(sb_mountdata+off, "ip=", 3) == 0) { 170 off += noff; 171 continue; 172 } 173 - if (strnicmp(sb_mountdata+off, "prefixpath=", 3) == 0) { 174 off += noff; 175 continue; 176 } 177 - strncat(mountdata, sb_mountdata+off, noff); 178 off += noff; 179 - } 180 - strcat(mountdata, sb_mountdata+off); 181 mountdata[md_len] = '\0'; 182 183 /* copy new IP and ref share name */ 184 - strcat(mountdata, ",ip="); 185 strcat(mountdata, srvIP); 186 - strcat(mountdata, ",unc="); 187 strcat(mountdata, *devname); 188 189 /* 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 - } 197 } 198 199 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ 200 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ ··· 221 222 223 static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, 224 - struct dentry *dentry, char *ref_unc) 225 { 226 struct cifs_sb_info *cifs_sb; 227 struct vfsmount *mnt; ··· 230 231 cifs_sb = CIFS_SB(dentry->d_inode->i_sb); 232 mountdata = compose_mount_options(cifs_sb->mountdata, 233 - ref_unc, &devname); 234 235 if (IS_ERR(mountdata)) 236 return (struct vfsmount *)mountdata; ··· 333 } 334 mnt = cifs_dfs_do_refmount(nd->path.mnt, 335 nd->path.dentry, 336 - referrals[i].node_name); 337 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", 338 __func__, 339 referrals[i].node_name, mnt));
··· 106 /** 107 * compose_mount_options - creates mount options for refferral 108 * @sb_mountdata: parent/root DFS mount options (template) 109 + * @dentry: point where we are going to mount 110 + * @ref: server's referral 111 * @devname: pointer for saving device name 112 * 113 * creates mount options for submount based on template options sb_mountdata ··· 116 * Caller is responcible for freeing retunrned value if it is not error. 117 */ 118 static char *compose_mount_options(const char *sb_mountdata, 119 + struct dentry *dentry, 120 + const struct dfs_info3_param *ref, 121 char **devname) 122 { 123 int rc; ··· 126 char *srvIP = NULL; 127 char sep = ','; 128 int off, noff; 129 + char *fullpath; 130 131 if (sb_mountdata == NULL) 132 return ERR_PTR(-EINVAL); 133 134 + *devname = cifs_get_share_name(ref->node_name); 135 rc = dns_resolve_server_name_to_ip(*devname, &srvIP); 136 if (rc != 0) { 137 cERROR(1, ("%s: Failed to resolve server part of %s to IP", ··· 138 mountdata = ERR_PTR(rc); 139 goto compose_mount_options_out; 140 } 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; 147 mountdata = kzalloc(md_len+1, GFP_KERNEL); 148 if (mountdata == NULL) { 149 mountdata = ERR_PTR(-ENOMEM); ··· 152 strncpy(mountdata, sb_mountdata, 5); 153 off += 5; 154 } 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) { 164 off += noff; 165 continue; 166 } 167 + if (strnicmp(sb_mountdata + off, "ip=", 3) == 0) { 168 off += noff; 169 continue; 170 } 171 + if (strnicmp(sb_mountdata + off, "prefixpath=", 11) == 0) { 172 off += noff; 173 continue; 174 } 175 + strncat(mountdata, sb_mountdata + off, noff); 176 off += noff; 177 + } while (tkn_e); 178 + strcat(mountdata, sb_mountdata + off); 179 mountdata[md_len] = '\0'; 180 181 /* copy new IP and ref share name */ 182 + if (mountdata[strlen(mountdata) - 1] != sep) 183 + strncat(mountdata, &sep, 1); 184 + strcat(mountdata, "ip="); 185 strcat(mountdata, srvIP); 186 + strncat(mountdata, &sep, 1); 187 + strcat(mountdata, "unc="); 188 strcat(mountdata, *devname); 189 190 /* find & copy prefixpath */ 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)); 203 } 204 + kfree(fullpath); 205 206 /*cFYI(1,("%s: parent mountdata: %s", __func__,sb_mountdata));*/ 207 /*cFYI(1, ("%s: submount mountdata: %s", __func__, mountdata ));*/ ··· 198 199 200 static struct vfsmount *cifs_dfs_do_refmount(const struct vfsmount *mnt_parent, 201 + struct dentry *dentry, const struct dfs_info3_param *ref) 202 { 203 struct cifs_sb_info *cifs_sb; 204 struct vfsmount *mnt; ··· 207 208 cifs_sb = CIFS_SB(dentry->d_inode->i_sb); 209 mountdata = compose_mount_options(cifs_sb->mountdata, 210 + dentry, ref, &devname); 211 212 if (IS_ERR(mountdata)) 213 return (struct vfsmount *)mountdata; ··· 310 } 311 mnt = cifs_dfs_do_refmount(nd->path.mnt, 312 nd->path.dentry, 313 + referrals + i); 314 cFYI(1, ("%s: cifs_dfs_do_refmount:%s , mnt:%p", 315 __func__, 316 referrals[i].node_name, mnt));
+2 -2
fs/cifs/cifs_spnego.c
··· 73 * strlen(";sec=ntlmsspi") */ 74 #define MAX_MECH_STR_LEN 13 75 76 - /* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/60 */ 77 - #define MAX_IPV6_ADDR_LEN 42 78 79 /* strlen of "host=" */ 80 #define HOST_KEY_LEN 5
··· 73 * strlen(";sec=ntlmsspi") */ 74 #define MAX_MECH_STR_LEN 13 75 76 + /* max possible addr len eg FEDC:BA98:7654:3210:FEDC:BA98:7654:3210/128 */ 77 + #define MAX_IPV6_ADDR_LEN 43 78 79 /* strlen of "host=" */ 80 #define HOST_KEY_LEN 5
+15 -15
fs/cifs/cifsfs.c
··· 514 tcon = cifs_sb->tcon; 515 if (tcon == NULL) 516 return; 517 - down(&tcon->tconSem); 518 - if (atomic_read(&tcon->useCount) == 1) 519 tcon->tidStatus = CifsExiting; 520 - up(&tcon->tconSem); 521 522 /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ 523 /* cancel_notify_requests(tcon); */ ··· 1014 not bother sending an oplock release if session 1015 to server still is disconnected since oplock 1016 already released by the server in that case */ 1017 - if (pTcon->tidStatus != CifsNeedReconnect) { 1018 rc = CIFSSMBLock(0, pTcon, netfid, 1019 0 /* len */ , 0 /* offset */, 0, 1020 0, LOCKING_ANDX_OPLOCK_RELEASE, ··· 1032 static int cifs_dnotify_thread(void *dummyarg) 1033 { 1034 struct list_head *tmp; 1035 - struct cifsSesInfo *ses; 1036 1037 do { 1038 if (try_to_freeze()) 1039 continue; 1040 set_current_state(TASK_INTERRUPTIBLE); 1041 schedule_timeout(15*HZ); 1042 - read_lock(&GlobalSMBSeslock); 1043 /* check if any stuck requests that need 1044 to be woken up and wakeq so the 1045 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); 1051 } 1052 - read_unlock(&GlobalSMBSeslock); 1053 } while (!kthread_should_stop()); 1054 1055 return 0; ··· 1060 { 1061 int rc = 0; 1062 cifs_proc_init(); 1063 - /* INIT_LIST_HEAD(&GlobalServerList);*/ /* BB not implemented yet */ 1064 - INIT_LIST_HEAD(&GlobalSMBSessionList); 1065 - INIT_LIST_HEAD(&GlobalTreeConnectionList); 1066 INIT_LIST_HEAD(&GlobalOplock_Q); 1067 #ifdef CONFIG_CIFS_EXPERIMENTAL 1068 INIT_LIST_HEAD(&GlobalDnotifyReqList); ··· 1088 GlobalMaxActiveXid = 0; 1089 memset(Local_System_Name, 0, 15); 1090 rwlock_init(&GlobalSMBSeslock); 1091 spin_lock_init(&GlobalMid_Lock); 1092 1093 if (cifs_max_pending < 2) {
··· 514 tcon = cifs_sb->tcon; 515 if (tcon == NULL) 516 return; 517 + 518 + read_lock(&cifs_tcp_ses_lock); 519 + if (tcon->tc_count == 1) 520 tcon->tidStatus = CifsExiting; 521 + read_unlock(&cifs_tcp_ses_lock); 522 523 /* cancel_brl_requests(tcon); */ /* BB mark all brl mids as exiting */ 524 /* cancel_notify_requests(tcon); */ ··· 1013 not bother sending an oplock release if session 1014 to server still is disconnected since oplock 1015 already released by the server in that case */ 1016 + if (!pTcon->need_reconnect) { 1017 rc = CIFSSMBLock(0, pTcon, netfid, 1018 0 /* len */ , 0 /* offset */, 0, 1019 0, LOCKING_ANDX_OPLOCK_RELEASE, ··· 1031 static int cifs_dnotify_thread(void *dummyarg) 1032 { 1033 struct list_head *tmp; 1034 + struct TCP_Server_Info *server; 1035 1036 do { 1037 if (try_to_freeze()) 1038 continue; 1039 set_current_state(TASK_INTERRUPTIBLE); 1040 schedule_timeout(15*HZ); 1041 /* check if any stuck requests that need 1042 to be woken up and wakeq so the 1043 thread can wake up and error out */ 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); 1050 } 1051 + read_unlock(&cifs_tcp_ses_lock); 1052 } while (!kthread_should_stop()); 1053 1054 return 0; ··· 1059 { 1060 int rc = 0; 1061 cifs_proc_init(); 1062 + INIT_LIST_HEAD(&cifs_tcp_ses_list); 1063 INIT_LIST_HEAD(&GlobalOplock_Q); 1064 #ifdef CONFIG_CIFS_EXPERIMENTAL 1065 INIT_LIST_HEAD(&GlobalDnotifyReqList); ··· 1089 GlobalMaxActiveXid = 0; 1090 memset(Local_System_Name, 0, 15); 1091 rwlock_init(&GlobalSMBSeslock); 1092 + rwlock_init(&cifs_tcp_ses_lock); 1093 spin_lock_init(&GlobalMid_Lock); 1094 1095 if (cifs_max_pending < 2) {
+22 -19
fs/cifs/cifsglob.h
··· 85 }; 86 87 enum protocolEnum { 88 - IPV4 = 0, 89 - IPV6, 90 SCTP 91 /* Netbios frames protocol not supported at this time */ 92 }; ··· 121 */ 122 123 struct TCP_Server_Info { 124 /* 15 character server name + 0x20 16th byte indicating type = srv */ 125 char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; 126 char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; ··· 145 bool svlocal:1; /* local server or remote */ 146 bool noblocksnd; /* use blocking sendmsg */ 147 bool noautotune; /* do not autotune send buf sizes */ 148 - atomic_t socketUseCount; /* number of open cifs sessions on socket */ 149 atomic_t inFlight; /* number of requests on the wire to server */ 150 #ifdef CONFIG_CIFS_STATS2 151 atomic_t inSend; /* requests trying to send */ ··· 195 * Session structure. One of these for each uid session with a particular host 196 */ 197 struct cifsSesInfo { 198 - struct list_head cifsSessionList; 199 struct semaphore sesSem; 200 #if 0 201 struct cifsUidInfo *uidInfo; /* pointer to user info */ 202 #endif 203 struct TCP_Server_Info *server; /* pointer to server info */ 204 - atomic_t inUse; /* # of mounts (tree connections) on this ses */ 205 enum statusEnum status; 206 unsigned overrideSecFlg; /* if non-zero override global sec flags */ 207 __u16 ipc_tid; /* special tid for connection to IPC share */ ··· 218 char userName[MAX_USERNAME_SIZE + 1]; 219 char *domainName; 220 char *password; 221 }; 222 /* no more than one of the following three session flags may be set */ 223 #define CIFS_SES_NT4 1 ··· 233 * session 234 */ 235 struct cifsTconInfo { 236 - struct list_head cifsConnectionList; 237 struct list_head openFileList; 238 - struct semaphore tconSem; 239 struct cifsSesInfo *ses; /* pointer to session associated with */ 240 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ 241 char *nativeFileSystem; 242 __u16 tid; /* The 2 byte tree id */ 243 __u16 Flags; /* optional support bits */ 244 enum statusEnum tidStatus; 245 - atomic_t useCount; /* how many explicit/implicit mounts to share */ 246 #ifdef CONFIG_CIFS_STATS 247 atomic_t num_smbs_sent; 248 atomic_t num_writes; ··· 290 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol 291 for this mount even if server would support */ 292 bool local_lease:1; /* check leases (only) on local system not remote */ 293 /* BB add field for back pointer to sb struct(s)? */ 294 }; 295 ··· 591 #endif 592 593 /* 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. 597 */ 598 - /* Feature not supported */ 599 - /* GLOBAL_EXTERN struct servers_not_supported *NotSuppList; */ 600 601 /* 602 - * The following is a hash table of all the users we know about. 603 */ 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; 609 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 610 611 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
··· 85 }; 86 87 enum protocolEnum { 88 + TCP = 0, 89 SCTP 90 /* Netbios frames protocol not supported at this time */ 91 }; ··· 122 */ 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 */ 128 /* 15 character server name + 0x20 16th byte indicating type = srv */ 129 char server_RFC1001_name[SERVER_NAME_LEN_WITH_NULL]; 130 char unicode_server_Name[SERVER_NAME_LEN_WITH_NULL * 2]; ··· 143 bool svlocal:1; /* local server or remote */ 144 bool noblocksnd; /* use blocking sendmsg */ 145 bool noautotune; /* do not autotune send buf sizes */ 146 atomic_t inFlight; /* number of requests on the wire to server */ 147 #ifdef CONFIG_CIFS_STATS2 148 atomic_t inSend; /* requests trying to send */ ··· 194 * Session structure. One of these for each uid session with a particular host 195 */ 196 struct cifsSesInfo { 197 + struct list_head smb_ses_list; 198 + struct list_head tcon_list; 199 struct semaphore sesSem; 200 #if 0 201 struct cifsUidInfo *uidInfo; /* pointer to user info */ 202 #endif 203 struct TCP_Server_Info *server; /* pointer to server info */ 204 + int ses_count; /* reference counter */ 205 enum statusEnum status; 206 unsigned overrideSecFlg; /* if non-zero override global sec flags */ 207 __u16 ipc_tid; /* special tid for connection to IPC share */ ··· 216 char userName[MAX_USERNAME_SIZE + 1]; 217 char *domainName; 218 char *password; 219 + bool need_reconnect:1; /* connection reset, uid now invalid */ 220 }; 221 /* no more than one of the following three session flags may be set */ 222 #define CIFS_SES_NT4 1 ··· 230 * session 231 */ 232 struct cifsTconInfo { 233 + struct list_head tcon_list; 234 + int tc_count; 235 struct list_head openFileList; 236 struct cifsSesInfo *ses; /* pointer to session associated with */ 237 char treeName[MAX_TREE_SIZE + 1]; /* UNC name of resource in ASCII */ 238 char *nativeFileSystem; 239 __u16 tid; /* The 2 byte tree id */ 240 __u16 Flags; /* optional support bits */ 241 enum statusEnum tidStatus; 242 #ifdef CONFIG_CIFS_STATS 243 atomic_t num_smbs_sent; 244 atomic_t num_writes; ··· 288 bool unix_ext:1; /* if false disable Linux extensions to CIFS protocol 289 for this mount even if server would support */ 290 bool local_lease:1; /* check leases (only) on local system not remote */ 291 + bool need_reconnect:1; /* connection reset, tid now invalid */ 292 /* BB add field for back pointer to sb struct(s)? */ 293 }; 294 ··· 588 #endif 589 590 /* 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 596 */ 597 + GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; 598 599 /* 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. 604 */ 605 + GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; 606 GLOBAL_EXTERN rwlock_t GlobalSMBSeslock; /* protects list inserts on 3 above */ 607 608 GLOBAL_EXTERN struct list_head GlobalOplock_Q;
+73 -63
fs/cifs/cifssmb.c
··· 190 /* need to prevent multiple threads trying to 191 simultaneously reconnect the same SMB session */ 192 down(&tcon->ses->sesSem); 193 - if (tcon->ses->status == CifsNeedReconnect) 194 rc = cifs_setup_session(0, tcon->ses, 195 nls_codepage); 196 - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { 197 mark_open_files_invalid(tcon); 198 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 199 tcon, nls_codepage); ··· 295 check for tcp and smb session status done differently 296 for those three - in the calling routine */ 297 if (tcon) { 298 - if (tcon->tidStatus == CifsExiting) { 299 /* only tree disconnect, open, and write, 300 (and ulogoff which does not have tcon) 301 are allowed as we start force umount */ ··· 337 /* need to prevent multiple threads trying to 338 simultaneously reconnect the same SMB session */ 339 down(&tcon->ses->sesSem); 340 - if (tcon->ses->status == CifsNeedReconnect) 341 rc = cifs_setup_session(0, tcon->ses, 342 nls_codepage); 343 - if (!rc && (tcon->tidStatus == CifsNeedReconnect)) { 344 mark_open_files_invalid(tcon); 345 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 346 tcon, nls_codepage); ··· 664 rc = -EIO; 665 goto neg_err_exit; 666 } 667 - 668 - if (server->socketUseCount.counter > 1) { 669 if (memcmp(server->server_GUID, 670 pSMBr->u.extended_response. 671 GUID, 16) != 0) { ··· 675 pSMBr->u.extended_response.GUID, 676 16); 677 } 678 - } else 679 memcpy(server->server_GUID, 680 pSMBr->u.extended_response.GUID, 16); 681 682 if (count == 16) { 683 server->secType = RawNTLMSSP; ··· 742 int rc = 0; 743 744 cFYI(1, ("In tree disconnect")); 745 /* 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). 751 */ 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); 767 return 0; 768 - } 769 770 - if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) { 771 - up(&tcon->tconSem); 772 - return -EIO; 773 - } 774 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 775 (void **)&smb_buffer); 776 - if (rc) { 777 - up(&tcon->tconSem); 778 return rc; 779 - } 780 781 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); 782 if (rc) 783 cFYI(1, ("Tree disconnect failed %d", rc)); 784 785 - up(&tcon->tconSem); 786 - 787 /* No need to return error on this operation if tid invalidated and 788 - closed on server already e.g. due to tcp session crashing */ 789 if (rc == -EAGAIN) 790 rc = 0; 791 ··· 780 int rc = 0; 781 782 cFYI(1, ("In SMBLogoff for session disconnect")); 783 - if (ses) 784 - down(&ses->sesSem); 785 - else 786 return -EIO; 787 788 - atomic_dec(&ses->inUse); 789 - if (atomic_read(&ses->inUse) > 0) { 790 - up(&ses->sesSem); 791 - return -EBUSY; 792 - } 793 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); 794 if (rc) { 795 up(&ses->sesSem); 796 return rc; 797 } 798 799 - if (ses->server) { 800 - pSMB->hdr.Mid = GetNextMid(ses->server); 801 802 - if (ses->server->secMode & 803 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 804 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; 805 - } 806 807 pSMB->hdr.Uid = ses->Suid; 808 809 pSMB->AndXCommand = 0xFF; 810 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 - } 820 up(&ses->sesSem); 821 822 /* if session dead then we do not need to do ulogoff, ··· 3899 return rc; 3900 } 3901 3902 /* parses DFS refferal V3 structure 3903 * caller is responsible for freeing target_nodes 3904 * returns: ··· 3930 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, 3931 unsigned int *num_of_nodes, 3932 struct dfs_info3_param **target_nodes, 3933 - const struct nls_table *nls_codepage) 3934 { 3935 int i, rc = 0; 3936 char *data_end; ··· 3982 struct dfs_info3_param *node = (*target_nodes)+i; 3983 3984 node->flags = le16_to_cpu(pSMBr->DFSFlags); 3985 - node->path_consumed = le16_to_cpu(pSMBr->PathConsumed); 3986 node->server_type = le16_to_cpu(ref->ServerType); 3987 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); 3988 ··· 4125 4126 /* parse returned result into more usable form */ 4127 rc = parse_DFS_referrals(pSMBr, num_of_nodes, 4128 - target_nodes, nls_codepage); 4129 4130 GetDFSRefExit: 4131 cifs_buf_release(pSMB);
··· 190 /* need to prevent multiple threads trying to 191 simultaneously reconnect the same SMB session */ 192 down(&tcon->ses->sesSem); 193 + if (tcon->ses->need_reconnect) 194 rc = cifs_setup_session(0, tcon->ses, 195 nls_codepage); 196 + if (!rc && (tcon->need_reconnect)) { 197 mark_open_files_invalid(tcon); 198 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 199 tcon, nls_codepage); ··· 295 check for tcp and smb session status done differently 296 for those three - in the calling routine */ 297 if (tcon) { 298 + if (tcon->need_reconnect) { 299 /* only tree disconnect, open, and write, 300 (and ulogoff which does not have tcon) 301 are allowed as we start force umount */ ··· 337 /* need to prevent multiple threads trying to 338 simultaneously reconnect the same SMB session */ 339 down(&tcon->ses->sesSem); 340 + if (tcon->ses->need_reconnect) 341 rc = cifs_setup_session(0, tcon->ses, 342 nls_codepage); 343 + if (!rc && (tcon->need_reconnect)) { 344 mark_open_files_invalid(tcon); 345 rc = CIFSTCon(0, tcon->ses, tcon->treeName, 346 tcon, nls_codepage); ··· 664 rc = -EIO; 665 goto neg_err_exit; 666 } 667 + read_lock(&cifs_tcp_ses_lock); 668 + if (server->srv_count > 1) { 669 + read_unlock(&cifs_tcp_ses_lock); 670 if (memcmp(server->server_GUID, 671 pSMBr->u.extended_response. 672 GUID, 16) != 0) { ··· 674 pSMBr->u.extended_response.GUID, 675 16); 676 } 677 + } else { 678 + read_unlock(&cifs_tcp_ses_lock); 679 memcpy(server->server_GUID, 680 pSMBr->u.extended_response.GUID, 16); 681 + } 682 683 if (count == 16) { 684 server->secType = RawNTLMSSP; ··· 739 int rc = 0; 740 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 + 747 /* 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. 752 */ 753 + if (tcon->need_reconnect) 754 return 0; 755 756 rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, 757 (void **)&smb_buffer); 758 + if (rc) 759 return rc; 760 761 rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); 762 if (rc) 763 cFYI(1, ("Tree disconnect failed %d", rc)); 764 765 /* No need to return error on this operation if tid invalidated and 766 + closed on server already e.g. due to tcp session crashing */ 767 if (rc == -EAGAIN) 768 rc = 0; 769 ··· 796 int rc = 0; 797 798 cFYI(1, ("In SMBLogoff for session disconnect")); 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) 806 return -EIO; 807 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 */ 812 rc = small_smb_init(SMB_COM_LOGOFF_ANDX, 2, NULL, (void **)&pSMB); 813 if (rc) { 814 up(&ses->sesSem); 815 return rc; 816 } 817 818 + pSMB->hdr.Mid = GetNextMid(ses->server); 819 820 + if (ses->server->secMode & 821 (SECMODE_SIGN_REQUIRED | SECMODE_SIGN_ENABLED)) 822 pSMB->hdr.Flags2 |= SMBFLG2_SECURITY_SIGNATURE; 823 824 pSMB->hdr.Uid = ses->Suid; 825 826 pSMB->AndXCommand = 0xFF; 827 rc = SendReceiveNoRsp(xid, ses, (struct smb_hdr *) pSMB, 0); 828 + session_already_dead: 829 up(&ses->sesSem); 830 831 /* if session dead then we do not need to do ulogoff, ··· 3922 return rc; 3923 } 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 + 3946 /* parses DFS refferal V3 structure 3947 * caller is responsible for freeing target_nodes 3948 * returns: ··· 3932 parse_DFS_referrals(TRANSACTION2_GET_DFS_REFER_RSP *pSMBr, 3933 unsigned int *num_of_nodes, 3934 struct dfs_info3_param **target_nodes, 3935 + const struct nls_table *nls_codepage, int remap, 3936 + const char *searchName) 3937 { 3938 int i, rc = 0; 3939 char *data_end; ··· 3983 struct dfs_info3_param *node = (*target_nodes)+i; 3984 3985 node->flags = le16_to_cpu(pSMBr->DFSFlags); 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 + 3997 node->server_type = le16_to_cpu(ref->ServerType); 3998 node->ref_flag = le16_to_cpu(ref->ReferralEntryFlags); 3999 ··· 4116 4117 /* parse returned result into more usable form */ 4118 rc = parse_DFS_referrals(pSMBr, num_of_nodes, 4119 + target_nodes, nls_codepage, remap, 4120 + searchName); 4121 4122 GetDFSRefExit: 4123 cifs_buf_release(pSMB);
+413 -416
fs/cifs/connect.c
··· 124 cifs_reconnect(struct TCP_Server_Info *server) 125 { 126 int rc = 0; 127 - struct list_head *tmp; 128 struct cifsSesInfo *ses; 129 struct cifsTconInfo *tcon; 130 struct mid_q_entry *mid_entry; ··· 144 145 /* before reconnecting the tcp session, mark the smb session (uid) 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 - } 155 } 156 - /* else tcp and smb sessions need reconnection */ 157 } 158 - list_for_each(tmp, &GlobalTreeConnectionList) { 159 - tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); 160 - if ((tcon->ses) && (tcon->ses->server == server)) 161 - tcon->tidStatus = CifsNeedReconnect; 162 - } 163 - read_unlock(&GlobalSMBSeslock); 164 /* do not want to be sending data on a socket we are freeing */ 165 down(&server->tcpSem); 166 if (server->ssocket) { ··· 187 while ((server->tcpStatus != CifsExiting) && 188 (server->tcpStatus != CifsGood)) { 189 try_to_freeze(); 190 - if (server->protocolType == IPV6) { 191 rc = ipv6_connect(&server->addr.sockAddr6, 192 &server->ssocket, server->noautotune); 193 } else { ··· 411 msleep(1); /* minimum sleep to prevent looping 412 allowing socket to clear and app threads to set 413 tcpStatus CifsNeedReconnect if server hung */ 414 - if (pdu_length < 4) 415 goto incomplete_rcv; 416 - else 417 continue; 418 } else if (length <= 0) { 419 if (server->tcpStatus == CifsNew) { ··· 653 } 654 } /* end while !EXITING */ 655 656 spin_lock(&GlobalMid_Lock); 657 server->tcpStatus = CifsExiting; 658 spin_unlock(&GlobalMid_Lock); ··· 690 if (smallbuf) /* no sense logging a debug message if NULL */ 691 cifs_small_buf_release(smallbuf); 692 693 - read_lock(&GlobalSMBSeslock); 694 if (list_empty(&server->pending_mid_q)) { 695 /* loop through server session structures attached to this and 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 - } 705 } 706 - read_unlock(&GlobalSMBSeslock); 707 } else { 708 /* although we can not zero the server struct pointer yet, 709 since there are active requests which may depnd on them, 710 mark the corresponding SMB sessions as exiting too */ 711 - list_for_each(tmp, &GlobalSMBSessionList) { 712 ses = list_entry(tmp, struct cifsSesInfo, 713 - cifsSessionList); 714 - if (ses->server == server) 715 - ses->status = CifsExiting; 716 } 717 718 spin_lock(&GlobalMid_Lock); ··· 727 } 728 } 729 spin_unlock(&GlobalMid_Lock); 730 - read_unlock(&GlobalSMBSeslock); 731 /* 1/8th of sec is more than enough time for them to exit */ 732 msleep(125); 733 } ··· 749 if there are any pointing to this (e.g 750 if a crazy root user tried to kill cifsd 751 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; 758 } 759 - write_unlock(&GlobalSMBSeslock); 760 761 kfree(server->hostname); 762 task_to_wake = xchg(&server->tsk, NULL); ··· 1355 return 0; 1356 } 1357 1358 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) 1362 { 1363 struct list_head *tmp; 1364 struct cifsSesInfo *ses; 1365 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) 1372 continue; 1373 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 */ 1394 } 1395 - read_unlock(&GlobalSMBSeslock); 1396 - 1397 return NULL; 1398 } 1399 1400 static struct cifsTconInfo * 1401 - find_unc(__be32 new_target_ip_addr, char *uncName, char *userName) 1402 { 1403 struct list_head *tmp; 1404 struct cifsTconInfo *tcon; 1405 - __be32 old_ip; 1406 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) 1413 continue; 1414 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); 1439 return tcon; 1440 } 1441 - 1442 - read_unlock(&GlobalSMBSeslock); 1443 return NULL; 1444 } 1445 1446 int ··· 1943 } 1944 } 1945 1946 - static void 1947 - kill_cifsd(struct TCP_Server_Info *server) 1948 { 1949 - struct task_struct *task; 1950 1951 - task = xchg(&server->tsk, NULL); 1952 - if (task) 1953 - force_sig(SIGKILL, task); 1954 } 1955 1956 int ··· 2035 { 2036 int rc = 0; 2037 int xid; 2038 - int address_type = AF_INET; 2039 struct socket *csocket = NULL; 2040 - struct sockaddr_in sin_server; 2041 - struct sockaddr_in6 sin_server6; 2042 struct smb_vol volume_info; 2043 struct cifsSesInfo *pSesInfo = NULL; 2044 - struct cifsSesInfo *existingCifsSes = NULL; 2045 struct cifsTconInfo *tcon = NULL; 2046 struct TCP_Server_Info *srvTcp = NULL; 2047 ··· 2048 2049 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ 2050 2051 memset(&volume_info, 0, sizeof(struct smb_vol)); 2052 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { 2053 rc = -EINVAL; ··· 2071 2072 if (volume_info.UNCip && volume_info.UNC) { 2073 rc = cifs_inet_pton(AF_INET, volume_info.UNCip, 2074 - &sin_server.sin_addr.s_addr); 2075 2076 if (rc <= 0) { 2077 /* not ipv4 address, try ipv6 */ 2078 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, 2079 - &sin_server6.sin6_addr.in6_u); 2080 if (rc > 0) 2081 - address_type = AF_INET6; 2082 } else { 2083 - address_type = AF_INET; 2084 } 2085 2086 if (rc <= 0) { ··· 2120 } 2121 } 2122 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) { 2145 cFYI(1, ("attempting ipv6 connect")); 2146 /* BB should we allow ipv6 on port 139? */ 2147 /* other OS never observed in Wild doing 139 with v6 */ 2148 - rc = ipv6_connect(&sin_server6, &csocket, 2149 volume_info.noblocksnd); 2150 - } else 2151 - rc = ipv4_connect(&sin_server, &csocket, 2152 volume_info.source_rfc1001_name, 2153 volume_info.target_rfc1001_name, 2154 volume_info.noblocksnd, 2155 volume_info.noautotune); 2156 if (rc < 0) { 2157 - cERROR(1, ("Error connecting to IPv4 socket. " 2158 "Aborting operation")); 2159 if (csocket != NULL) 2160 sock_release(csocket); ··· 2153 } else { 2154 srvTcp->noblocksnd = volume_info.noblocksnd; 2155 srvTcp->noautotune = volume_info.noautotune; 2156 - memcpy(&srvTcp->addr.sockAddr, &sin_server, 2157 - sizeof(struct sockaddr_in)); 2158 atomic_set(&srvTcp->inFlight, 0); 2159 /* BB Add code for ipv6 case too */ 2160 srvTcp->ssocket = csocket; 2161 - srvTcp->protocolType = IPV4; 2162 srvTcp->hostname = extract_hostname(volume_info.UNC); 2163 if (IS_ERR(srvTcp->hostname)) { 2164 rc = PTR_ERR(srvTcp->hostname); ··· 2191 memcpy(srvTcp->server_RFC1001_name, 2192 volume_info.target_rfc1001_name, 16); 2193 srvTcp->sequence_number = 0; 2194 } 2195 } 2196 2197 - if (existingCifsSes) { 2198 - pSesInfo = existingCifsSes; 2199 cFYI(1, ("Existing smb sess found (status=%d)", 2200 pSesInfo->status)); 2201 down(&pSesInfo->sesSem); 2202 - if (pSesInfo->status == CifsNeedReconnect) { 2203 cFYI(1, ("Session needs reconnect")); 2204 rc = cifs_setup_session(xid, pSesInfo, 2205 cifs_sb->local_nls); ··· 2221 } else if (!rc) { 2222 cFYI(1, ("Existing smb sess not found")); 2223 pSesInfo = sesInfoAlloc(); 2224 - if (pSesInfo == NULL) 2225 rc = -ENOMEM; 2226 - else { 2227 - pSesInfo->server = srvTcp; 2228 - sprintf(pSesInfo->serverName, "%u.%u.%u.%u", 2229 - NIPQUAD(sin_server.sin_addr.s_addr)); 2230 } 2231 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); 2260 } 2261 } 2262 2263 /* search for existing tcon to this server share */ 2264 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; 2274 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); 2350 if (tcon) { 2351 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; 2359 if (tcon->seal != volume_info.seal) 2360 cERROR(1, ("transport encryption setting " 2361 "conflicts with existing tid")); 2362 } else { 2363 tcon = tconInfoAlloc(); 2364 - if (tcon == NULL) 2365 rc = -ENOMEM; 2366 - else { 2367 - /* check for null share name ie connecting to 2368 - * dfs root */ 2369 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; 2402 } 2403 } 2404 } 2405 } 2406 if (pSesInfo) { 2407 if (pSesInfo->capabilities & CAP_LARGE_FILES) { ··· 2327 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2328 sb->s_time_gran = 100; 2329 2330 - /* on error free sesinfo and tcon struct if needed */ 2331 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); 2382 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)); 2403 } 2404 2405 /* volume_info.password is freed above when existing session found 2406 (in which case it is not needed anymore) but when new sesion is created ··· 3539 /* above now done in SendReceive */ 3540 if ((rc == 0) && (tcon != NULL)) { 3541 tcon->tidStatus = CifsGood; 3542 tcon->tid = smb_buffer_response->Tid; 3543 bcc_ptr = pByteArea(smb_buffer_response); 3544 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); ··· 3611 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3612 { 3613 int rc = 0; 3614 - int xid; 3615 - struct cifsSesInfo *ses = NULL; 3616 char *tmp; 3617 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 - } 3646 3647 cifs_sb->tcon = NULL; 3648 tmp = cifs_sb->prepath; 3649 cifs_sb->prepathlen = 0; 3650 cifs_sb->prepath = NULL; 3651 kfree(tmp); 3652 - if (ses) 3653 - sesInfoFree(ses); 3654 3655 - FreeXid(xid); 3656 return rc; 3657 } 3658 ··· 3737 cFYI(1, ("CIFS Session Established successfully")); 3738 spin_lock(&GlobalMid_Lock); 3739 pSesInfo->status = CifsGood; 3740 spin_unlock(&GlobalMid_Lock); 3741 } 3742
··· 124 cifs_reconnect(struct TCP_Server_Info *server) 125 { 126 int rc = 0; 127 + struct list_head *tmp, *tmp2; 128 struct cifsSesInfo *ses; 129 struct cifsTconInfo *tcon; 130 struct mid_q_entry *mid_entry; ··· 144 145 /* before reconnecting the tcp session, mark the smb session (uid) 146 and the tid bad so they are not used until reconnected */ 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 } 156 } 157 + read_unlock(&cifs_tcp_ses_lock); 158 /* do not want to be sending data on a socket we are freeing */ 159 down(&server->tcpSem); 160 if (server->ssocket) { ··· 193 while ((server->tcpStatus != CifsExiting) && 194 (server->tcpStatus != CifsGood)) { 195 try_to_freeze(); 196 + if (server->addr.sockAddr6.sin6_family == AF_INET6) { 197 rc = ipv6_connect(&server->addr.sockAddr6, 198 &server->ssocket, server->noautotune); 199 } else { ··· 417 msleep(1); /* minimum sleep to prevent looping 418 allowing socket to clear and app threads to set 419 tcpStatus CifsNeedReconnect if server hung */ 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; 426 goto incomplete_rcv; 427 + } else 428 continue; 429 } else if (length <= 0) { 430 if (server->tcpStatus == CifsNew) { ··· 654 } 655 } /* end while !EXITING */ 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 + 662 spin_lock(&GlobalMid_Lock); 663 server->tcpStatus = CifsExiting; 664 spin_unlock(&GlobalMid_Lock); ··· 686 if (smallbuf) /* no sense logging a debug message if NULL */ 687 cifs_small_buf_release(smallbuf); 688 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 if (list_empty(&server->pending_mid_q)) { 695 /* loop through server session structures attached to this and 696 mark them dead */ 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; 702 } 703 + read_unlock(&cifs_tcp_ses_lock); 704 } else { 705 /* although we can not zero the server struct pointer yet, 706 since there are active requests which may depnd on them, 707 mark the corresponding SMB sessions as exiting too */ 708 + list_for_each(tmp, &server->smb_ses_list) { 709 ses = list_entry(tmp, struct cifsSesInfo, 710 + smb_ses_list); 711 + ses->status = CifsExiting; 712 } 713 714 spin_lock(&GlobalMid_Lock); ··· 723 } 724 } 725 spin_unlock(&GlobalMid_Lock); 726 + read_unlock(&cifs_tcp_ses_lock); 727 /* 1/8th of sec is more than enough time for them to exit */ 728 msleep(125); 729 } ··· 745 if there are any pointing to this (e.g 746 if a crazy root user tried to kill cifsd 747 kernel thread explicitly this might happen) */ 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; 753 } 754 + read_unlock(&cifs_tcp_ses_lock); 755 756 kfree(server->hostname); 757 task_to_wake = xchg(&server->tsk, NULL); ··· 1352 return 0; 1353 } 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 + 1417 static struct cifsSesInfo * 1418 + cifs_find_smb_ses(struct TCP_Server_Info *server, char *username) 1419 { 1420 struct list_head *tmp; 1421 struct cifsSesInfo *ses; 1422 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)) 1427 continue; 1428 1429 + ++ses->ses_count; 1430 + write_unlock(&cifs_tcp_ses_lock); 1431 + return ses; 1432 } 1433 + write_unlock(&cifs_tcp_ses_lock); 1434 return NULL; 1435 } 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 + 1461 static struct cifsTconInfo * 1462 + cifs_find_tcon(struct cifsSesInfo *ses, const char *unc) 1463 { 1464 struct list_head *tmp; 1465 struct cifsTconInfo *tcon; 1466 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)) 1473 continue; 1474 1475 + ++tcon->tc_count; 1476 + write_unlock(&cifs_tcp_ses_lock); 1477 return tcon; 1478 } 1479 + write_unlock(&cifs_tcp_ses_lock); 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); 1505 } 1506 1507 int ··· 1876 } 1877 } 1878 1879 + static void setup_cifs_sb(struct smb_vol *pvolume_info, 1880 + struct cifs_sb_info *cifs_sb) 1881 { 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; 1891 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")); 1963 } 1964 1965 int ··· 1892 { 1893 int rc = 0; 1894 int xid; 1895 struct socket *csocket = NULL; 1896 + struct sockaddr addr; 1897 + struct sockaddr_in *sin_server = (struct sockaddr_in *) &addr; 1898 + struct sockaddr_in6 *sin_server6 = (struct sockaddr_in6 *) &addr; 1899 struct smb_vol volume_info; 1900 struct cifsSesInfo *pSesInfo = NULL; 1901 struct cifsTconInfo *tcon = NULL; 1902 struct TCP_Server_Info *srvTcp = NULL; 1903 ··· 1906 1907 /* cFYI(1, ("Entering cifs_mount. Xid: %d with: %s", xid, mount_data)); */ 1908 1909 + memset(&addr, 0, sizeof(struct sockaddr)); 1910 memset(&volume_info, 0, sizeof(struct smb_vol)); 1911 if (cifs_parse_mount_options(mount_data, devname, &volume_info)) { 1912 rc = -EINVAL; ··· 1928 1929 if (volume_info.UNCip && volume_info.UNC) { 1930 rc = cifs_inet_pton(AF_INET, volume_info.UNCip, 1931 + &sin_server->sin_addr.s_addr); 1932 1933 if (rc <= 0) { 1934 /* not ipv4 address, try ipv6 */ 1935 rc = cifs_inet_pton(AF_INET6, volume_info.UNCip, 1936 + &sin_server6->sin6_addr.in6_u); 1937 if (rc > 0) 1938 + addr.sa_family = AF_INET6; 1939 } else { 1940 + addr.sa_family = AF_INET; 1941 } 1942 1943 if (rc <= 0) { ··· 1977 } 1978 } 1979 1980 + srvTcp = cifs_find_tcp_session(&addr); 1981 + if (!srvTcp) { /* create socket */ 1982 + if (addr.sa_family == AF_INET6) { 1983 cFYI(1, ("attempting ipv6 connect")); 1984 /* BB should we allow ipv6 on port 139? */ 1985 /* other OS never observed in Wild doing 139 with v6 */ 1986 + sin_server6->sin6_port = htons(volume_info.port); 1987 + rc = ipv6_connect(sin_server6, &csocket, 1988 volume_info.noblocksnd); 1989 + } else { 1990 + sin_server->sin_port = htons(volume_info.port); 1991 + rc = ipv4_connect(sin_server, &csocket, 1992 volume_info.source_rfc1001_name, 1993 volume_info.target_rfc1001_name, 1994 volume_info.noblocksnd, 1995 volume_info.noautotune); 1996 + } 1997 if (rc < 0) { 1998 + cERROR(1, ("Error connecting to socket. " 1999 "Aborting operation")); 2000 if (csocket != NULL) 2001 sock_release(csocket); ··· 2026 } else { 2027 srvTcp->noblocksnd = volume_info.noblocksnd; 2028 srvTcp->noautotune = volume_info.noautotune; 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)); 2035 atomic_set(&srvTcp->inFlight, 0); 2036 /* BB Add code for ipv6 case too */ 2037 srvTcp->ssocket = csocket; 2038 srvTcp->hostname = extract_hostname(volume_info.UNC); 2039 if (IS_ERR(srvTcp->hostname)) { 2040 rc = PTR_ERR(srvTcp->hostname); ··· 2061 memcpy(srvTcp->server_RFC1001_name, 2062 volume_info.target_rfc1001_name, 16); 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); 2071 } 2072 } 2073 2074 + pSesInfo = cifs_find_smb_ses(srvTcp, volume_info.username); 2075 + if (pSesInfo) { 2076 cFYI(1, ("Existing smb sess found (status=%d)", 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 + 2084 down(&pSesInfo->sesSem); 2085 + if (pSesInfo->need_reconnect) { 2086 cFYI(1, ("Session needs reconnect")); 2087 rc = cifs_setup_session(xid, pSesInfo, 2088 cifs_sb->local_nls); ··· 2078 } else if (!rc) { 2079 cFYI(1, ("Existing smb sess not found")); 2080 pSesInfo = sesInfoAlloc(); 2081 + if (pSesInfo == NULL) { 2082 rc = -ENOMEM; 2083 + goto mount_fail_check; 2084 } 2085 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; 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); 2119 } 2120 2121 /* search for existing tcon to this server share */ 2122 if (!rc) { 2123 + setup_cifs_sb(&volume_info, cifs_sb); 2124 2125 + tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); 2126 if (tcon) { 2127 cFYI(1, ("Found match on UNC path")); 2128 + /* existing tcon already has a reference */ 2129 + cifs_put_smb_ses(pSesInfo); 2130 if (tcon->seal != volume_info.seal) 2131 cERROR(1, ("transport encryption setting " 2132 "conflicts with existing tid")); 2133 } else { 2134 tcon = tconInfoAlloc(); 2135 + if (tcon == NULL) { 2136 rc = -ENOMEM; 2137 + goto mount_fail_check; 2138 + } 2139 + tcon->ses = pSesInfo; 2140 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)); 2159 } 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); 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; 2176 } 2177 if (pSesInfo) { 2178 if (pSesInfo->capabilities & CAP_LARGE_FILES) { ··· 2270 /* BB FIXME fix time_gran to be larger for LANMAN sessions */ 2271 sb->s_time_gran = 100; 2272 2273 + mount_fail_check: 2274 + /* on error free sesinfo and tcon struct if needed */ 2275 if (rc) { 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); 2282 else 2283 + cifs_put_tcp_session(srvTcp); 2284 + goto out; 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)); 2316 2317 /* volume_info.password is freed above when existing session found 2318 (in which case it is not needed anymore) but when new sesion is created ··· 3513 /* above now done in SendReceive */ 3514 if ((rc == 0) && (tcon != NULL)) { 3515 tcon->tidStatus = CifsGood; 3516 + tcon->need_reconnect = false; 3517 tcon->tid = smb_buffer_response->Tid; 3518 bcc_ptr = pByteArea(smb_buffer_response); 3519 length = strnlen(bcc_ptr, BCC(smb_buffer_response) - 2); ··· 3584 cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) 3585 { 3586 int rc = 0; 3587 char *tmp; 3588 3589 + if (cifs_sb->tcon) 3590 + cifs_put_tcon(cifs_sb->tcon); 3591 3592 cifs_sb->tcon = NULL; 3593 tmp = cifs_sb->prepath; 3594 cifs_sb->prepathlen = 0; 3595 cifs_sb->prepath = NULL; 3596 kfree(tmp); 3597 3598 return rc; 3599 } 3600 ··· 3741 cFYI(1, ("CIFS Session Established successfully")); 3742 spin_lock(&GlobalMid_Lock); 3743 pSesInfo->status = CifsGood; 3744 + pSesInfo->need_reconnect = false; 3745 spin_unlock(&GlobalMid_Lock); 3746 } 3747
+5 -2
fs/cifs/file.c
··· 493 if (pTcon) { 494 /* no sense reconnecting to close a file that is 495 already closed */ 496 - if (pTcon->tidStatus != CifsNeedReconnect) { 497 timeout = 2; 498 while ((atomic_read(&pSMBFile->wrtPending) != 0) 499 && (timeout <= 2048)) { ··· 1404 if ((wbc->nr_to_write -= n_iov) <= 0) 1405 done = 1; 1406 index = next; 1407 - } 1408 pagevec_release(&pvec); 1409 } 1410 if (!scanned && !done) {
··· 493 if (pTcon) { 494 /* no sense reconnecting to close a file that is 495 already closed */ 496 + if (!pTcon->need_reconnect) { 497 timeout = 2; 498 while ((atomic_read(&pSMBFile->wrtPending) != 0) 499 && (timeout <= 2048)) { ··· 1404 if ((wbc->nr_to_write -= n_iov) <= 0) 1405 done = 1; 1406 index = next; 1407 + } else 1408 + /* Need to re-find the pages we skipped */ 1409 + index = pvec.pages[0]->index + 1; 1410 + 1411 pagevec_release(&pvec); 1412 } 1413 if (!scanned && !done) {
+41 -49
fs/cifs/misc.c
··· 75 76 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); 77 if (ret_buf) { 78 - write_lock(&GlobalSMBSeslock); 79 atomic_inc(&sesInfoAllocCount); 80 ret_buf->status = CifsNew; 81 - list_add(&ret_buf->cifsSessionList, &GlobalSMBSessionList); 82 init_MUTEX(&ret_buf->sesSem); 83 - write_unlock(&GlobalSMBSeslock); 84 } 85 return ret_buf; 86 } ··· 93 return; 94 } 95 96 - write_lock(&GlobalSMBSeslock); 97 atomic_dec(&sesInfoAllocCount); 98 - list_del(&buf_to_free->cifsSessionList); 99 - write_unlock(&GlobalSMBSeslock); 100 kfree(buf_to_free->serverOS); 101 kfree(buf_to_free->serverDomain); 102 kfree(buf_to_free->serverNOS); ··· 108 struct cifsTconInfo *ret_buf; 109 ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); 110 if (ret_buf) { 111 - write_lock(&GlobalSMBSeslock); 112 atomic_inc(&tconInfoAllocCount); 113 - list_add(&ret_buf->cifsConnectionList, 114 - &GlobalTreeConnectionList); 115 ret_buf->tidStatus = CifsNew; 116 INIT_LIST_HEAD(&ret_buf->openFileList); 117 - init_MUTEX(&ret_buf->tconSem); 118 #ifdef CONFIG_CIFS_STATS 119 spin_lock_init(&ret_buf->stat_lock); 120 #endif 121 - write_unlock(&GlobalSMBSeslock); 122 } 123 return ret_buf; 124 } ··· 127 cFYI(1, ("Null buffer passed to tconInfoFree")); 128 return; 129 } 130 - write_lock(&GlobalSMBSeslock); 131 atomic_dec(&tconInfoAllocCount); 132 - list_del(&buf_to_free->cifsConnectionList); 133 - write_unlock(&GlobalSMBSeslock); 134 kfree(buf_to_free->nativeFileSystem); 135 kfree(buf_to_free); 136 } ··· 341 if (current->fsuid != treeCon->ses->linux_uid) { 342 cFYI(1, ("Multiuser mode and UID " 343 "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); 347 if (ses->linux_uid == current->fsuid) { 348 if (ses->server == treeCon->ses->server) { 349 cFYI(1, ("found matching uid substitute right smb_uid")); ··· 355 } 356 } 357 } 358 - read_unlock(&GlobalSMBSeslock); 359 } 360 } 361 } ··· 488 is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) 489 { 490 struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; 491 - struct list_head *tmp; 492 - struct list_head *tmp1; 493 struct cifsTconInfo *tcon; 494 struct cifsFileInfo *netfile; 495 496 cFYI(1, ("Checking for oplock break or dnotify response")); ··· 546 return false; 547 548 /* 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)) { 553 cifs_stats_inc(&tcon->num_oplock_brks); 554 - list_for_each(tmp1, &tcon->openFileList) { 555 - netfile = list_entry(tmp1, struct cifsFileInfo, 556 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 - } 578 } 579 - read_unlock(&GlobalSMBSeslock); 580 cFYI(1, ("No matching file for oplock break")); 581 return true; 582 } 583 } 584 - read_unlock(&GlobalSMBSeslock); 585 cFYI(1, ("Can not process oplock break for non-existent connection")); 586 return true; 587 }
··· 75 76 ret_buf = kzalloc(sizeof(struct cifsSesInfo), GFP_KERNEL); 77 if (ret_buf) { 78 atomic_inc(&sesInfoAllocCount); 79 ret_buf->status = CifsNew; 80 + ++ret_buf->ses_count; 81 + INIT_LIST_HEAD(&ret_buf->smb_ses_list); 82 + INIT_LIST_HEAD(&ret_buf->tcon_list); 83 init_MUTEX(&ret_buf->sesSem); 84 } 85 return ret_buf; 86 } ··· 93 return; 94 } 95 96 atomic_dec(&sesInfoAllocCount); 97 kfree(buf_to_free->serverOS); 98 kfree(buf_to_free->serverDomain); 99 kfree(buf_to_free->serverNOS); ··· 111 struct cifsTconInfo *ret_buf; 112 ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); 113 if (ret_buf) { 114 atomic_inc(&tconInfoAllocCount); 115 ret_buf->tidStatus = CifsNew; 116 + ++ret_buf->tc_count; 117 INIT_LIST_HEAD(&ret_buf->openFileList); 118 + INIT_LIST_HEAD(&ret_buf->tcon_list); 119 #ifdef CONFIG_CIFS_STATS 120 spin_lock_init(&ret_buf->stat_lock); 121 #endif 122 } 123 return ret_buf; 124 } ··· 133 cFYI(1, ("Null buffer passed to tconInfoFree")); 134 return; 135 } 136 atomic_dec(&tconInfoAllocCount); 137 kfree(buf_to_free->nativeFileSystem); 138 kfree(buf_to_free); 139 } ··· 350 if (current->fsuid != treeCon->ses->linux_uid) { 351 cFYI(1, ("Multiuser mode and UID " 352 "did not match tcon uid")); 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); 356 if (ses->linux_uid == current->fsuid) { 357 if (ses->server == treeCon->ses->server) { 358 cFYI(1, ("found matching uid substitute right smb_uid")); ··· 364 } 365 } 366 } 367 + read_unlock(&cifs_tcp_ses_lock); 368 } 369 } 370 } ··· 497 is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) 498 { 499 struct smb_com_lock_req *pSMB = (struct smb_com_lock_req *)buf; 500 + struct list_head *tmp, *tmp1, *tmp2; 501 + struct cifsSesInfo *ses; 502 struct cifsTconInfo *tcon; 503 + struct cifsInodeInfo *pCifsInode; 504 struct cifsFileInfo *netfile; 505 506 cFYI(1, ("Checking for oplock break or dnotify response")); ··· 554 return false; 555 556 /* look up tcon based on tid & uid */ 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 + 565 cifs_stats_inc(&tcon->num_oplock_brks); 566 + list_for_each(tmp2, &tcon->openFileList) { 567 + netfile = list_entry(tmp2, struct cifsFileInfo, 568 tlist); 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; 586 } 587 + read_unlock(&cifs_tcp_ses_lock); 588 cFYI(1, ("No matching file for oplock break")); 589 return true; 590 } 591 } 592 + read_unlock(&cifs_tcp_ses_lock); 593 cFYI(1, ("Can not process oplock break for non-existent connection")); 594 return true; 595 }