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