diff options
| author | Jeff Layton <jlayton@redhat.com> | 2008-11-15 11:12:47 -0500 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2008-11-16 22:14:12 -0500 |
| commit | f1987b44f642e96176adc88b7ce23a1d74806f89 (patch) | |
| tree | fceaebf6b6d7eb1d1150120c44a842cbce8347f6 | |
| parent | d82c2df54e2f7e447476350848d8eccc8d2fe46a (diff) | |
cifs: reinstate sharing of tree connections
Use a similar approach to the SMB session sharing. Add a list of tcons
attached to each SMB session. Move the refcount to non-atomic. Protect
all of the above with the cifs_tcp_ses_lock. Add functions to
properly find and put references to the tcons.
Signed-off-by: Jeff Layton <jlayton@redhat.com>
Signed-off-by: Steve French <sfrench@us.ibm.com>
| -rw-r--r-- | fs/cifs/cifs_debug.c | 236 | ||||
| -rw-r--r-- | fs/cifs/cifsfs.c | 8 | ||||
| -rw-r--r-- | fs/cifs/cifsglob.h | 13 | ||||
| -rw-r--r-- | fs/cifs/cifssmb.c | 43 | ||||
| -rw-r--r-- | fs/cifs/connect.c | 93 | ||||
| -rw-r--r-- | fs/cifs/misc.c | 74 |
6 files changed, 249 insertions, 218 deletions
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c index 59841a68b0b6..1d6dfa8923ca 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, *tmp2, *tmp3; | 110 | struct list_head *tmp1, *tmp2, *tmp3; |
| 111 | struct mid_q_entry *mid_entry; | 111 | struct mid_q_entry *mid_entry; |
| 112 | struct TCP_Server_Info *server; | 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" |
| @@ -123,8 +124,8 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 123 | 124 | ||
| 124 | i = 0; | 125 | i = 0; |
| 125 | read_lock(&cifs_tcp_ses_lock); | 126 | read_lock(&cifs_tcp_ses_lock); |
| 126 | list_for_each(tmp, &cifs_tcp_ses_list) { | 127 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
| 127 | server = list_entry(tmp, struct TCP_Server_Info, | 128 | server = list_entry(tmp1, struct TCP_Server_Info, |
| 128 | tcp_ses_list); | 129 | tcp_ses_list); |
| 129 | i++; | 130 | i++; |
| 130 | list_for_each(tmp2, &server->smb_ses_list) { | 131 | list_for_each(tmp2, &server->smb_ses_list) { |
| @@ -133,12 +134,12 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 133 | if ((ses->serverDomain == NULL) || | 134 | if ((ses->serverDomain == NULL) || |
| 134 | (ses->serverOS == NULL) || | 135 | (ses->serverOS == NULL) || |
| 135 | (ses->serverNOS == NULL)) { | 136 | (ses->serverNOS == NULL)) { |
| 136 | seq_printf(m, "\nentry for %s not fully " | 137 | seq_printf(m, "\n%d) entry for %s not fully " |
| 137 | "displayed\n\t", ses->serverName); | 138 | "displayed\n\t", i, ses->serverName); |
| 138 | } else { | 139 | } else { |
| 139 | seq_printf(m, | 140 | seq_printf(m, |
| 140 | "\n%d) Name: %s Domain: %s Mounts: %d OS:" | 141 | "\n%d) Name: %s Domain: %s Uses: %d OS:" |
| 141 | " %s \n\tNOS: %s\tCapability: 0x%x\n\tSMB" | 142 | " %s\n\tNOS: %s\tCapability: 0x%x\n\tSMB" |
| 142 | " session status: %d\t", | 143 | " session status: %d\t", |
| 143 | i, ses->serverName, ses->serverDomain, | 144 | i, ses->serverName, ses->serverDomain, |
| 144 | ses->ses_count, ses->serverOS, ses->serverNOS, | 145 | ses->ses_count, ses->serverOS, ses->serverNOS, |
| @@ -156,14 +157,44 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 156 | atomic_read(&server->num_waiters)); | 157 | atomic_read(&server->num_waiters)); |
| 157 | #endif | 158 | #endif |
| 158 | 159 | ||
| 159 | 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"); | ||
| 160 | 192 | ||
| 161 | spin_lock(&GlobalMid_Lock); | 193 | spin_lock(&GlobalMid_Lock); |
| 162 | list_for_each(tmp3, &server->pending_mid_q) { | 194 | list_for_each(tmp3, &server->pending_mid_q) { |
| 163 | mid_entry = list_entry(tmp3, struct | 195 | mid_entry = list_entry(tmp3, struct mid_q_entry, |
| 164 | mid_q_entry, | ||
| 165 | qhead); | 196 | qhead); |
| 166 | seq_printf(m, "State: %d com: %d pid:" | 197 | seq_printf(m, "\tState: %d com: %d pid:" |
| 167 | " %d tsk: %p mid %d\n", | 198 | " %d tsk: %p mid %d\n", |
| 168 | mid_entry->midState, | 199 | mid_entry->midState, |
| 169 | (int)mid_entry->command, | 200 | (int)mid_entry->command, |
| @@ -177,41 +208,6 @@ static int cifs_debug_data_proc_show(struct seq_file *m, void *v) | |||
| 177 | read_unlock(&cifs_tcp_ses_lock); | 208 | read_unlock(&cifs_tcp_ses_lock); |
| 178 | seq_putc(m, '\n'); | 209 | seq_putc(m, '\n'); |
| 179 | 210 | ||
| 180 | seq_puts(m, "Shares:"); | ||
| 181 | |||
| 182 | i = 0; | ||
| 183 | read_lock(&GlobalSMBSeslock); | ||
| 184 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
| 185 | __u32 dev_type; | ||
| 186 | i++; | ||
| 187 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
| 188 | dev_type = le32_to_cpu(tcon->fsDevInfo.DeviceType); | ||
| 189 | seq_printf(m, "\n%d) %s Uses: %d ", i, | ||
| 190 | tcon->treeName, atomic_read(&tcon->useCount)); | ||
| 191 | if (tcon->nativeFileSystem) { | ||
| 192 | seq_printf(m, "Type: %s ", | ||
| 193 | tcon->nativeFileSystem); | ||
| 194 | } | ||
| 195 | seq_printf(m, "DevInfo: 0x%x Attributes: 0x%x" | ||
| 196 | "\nPathComponentMax: %d Status: %d", | ||
| 197 | le32_to_cpu(tcon->fsDevInfo.DeviceCharacteristics), | ||
| 198 | le32_to_cpu(tcon->fsAttrInfo.Attributes), | ||
| 199 | le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength), | ||
| 200 | tcon->tidStatus); | ||
| 201 | if (dev_type == FILE_DEVICE_DISK) | ||
| 202 | seq_puts(m, " type: DISK "); | ||
| 203 | else if (dev_type == FILE_DEVICE_CD_ROM) | ||
| 204 | seq_puts(m, " type: CDROM "); | ||
| 205 | else | ||
| 206 | seq_printf(m, " type: %d ", dev_type); | ||
| 207 | |||
| 208 | if (tcon->need_reconnect) | ||
| 209 | seq_puts(m, "\tDISCONNECTED "); | ||
| 210 | } | ||
| 211 | read_unlock(&GlobalSMBSeslock); | ||
| 212 | |||
| 213 | seq_putc(m, '\n'); | ||
| 214 | |||
| 215 | /* 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 */ |
| 216 | return 0; | 212 | return 0; |
| 217 | } | 213 | } |
| @@ -235,7 +231,9 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
| 235 | { | 231 | { |
| 236 | char c; | 232 | char c; |
| 237 | int rc; | 233 | int rc; |
| 238 | struct list_head *tmp; | 234 | struct list_head *tmp1, *tmp2, *tmp3; |
| 235 | struct TCP_Server_Info *server; | ||
| 236 | struct cifsSesInfo *ses; | ||
| 239 | struct cifsTconInfo *tcon; | 237 | struct cifsTconInfo *tcon; |
| 240 | 238 | ||
| 241 | rc = get_user(c, buffer); | 239 | rc = get_user(c, buffer); |
| @@ -243,33 +241,42 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
| 243 | return rc; | 241 | return rc; |
| 244 | 242 | ||
| 245 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { | 243 | if (c == '1' || c == 'y' || c == 'Y' || c == '0') { |
| 246 | read_lock(&GlobalSMBSeslock); | ||
| 247 | #ifdef CONFIG_CIFS_STATS2 | 244 | #ifdef CONFIG_CIFS_STATS2 |
| 248 | atomic_set(&totBufAllocCount, 0); | 245 | atomic_set(&totBufAllocCount, 0); |
| 249 | atomic_set(&totSmBufAllocCount, 0); | 246 | atomic_set(&totSmBufAllocCount, 0); |
| 250 | #endif /* CONFIG_CIFS_STATS2 */ | 247 | #endif /* CONFIG_CIFS_STATS2 */ |
| 251 | list_for_each(tmp, &GlobalTreeConnectionList) { | 248 | read_lock(&cifs_tcp_ses_lock); |
| 252 | tcon = list_entry(tmp, struct cifsTconInfo, | 249 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
| 253 | cifsConnectionList); | 250 | server = list_entry(tmp1, struct TCP_Server_Info, |
| 254 | atomic_set(&tcon->num_smbs_sent, 0); | 251 | tcp_ses_list); |
| 255 | atomic_set(&tcon->num_writes, 0); | 252 | list_for_each(tmp2, &server->smb_session_list) { |
| 256 | atomic_set(&tcon->num_reads, 0); | 253 | ses = list_entry(tmp2, struct cifsSesInfo, |
| 257 | atomic_set(&tcon->num_oplock_brks, 0); | 254 | smb_session_list); |
| 258 | atomic_set(&tcon->num_opens, 0); | 255 | list_for_each(tmp3, &ses->tcon_list) { |
| 259 | atomic_set(&tcon->num_closes, 0); | 256 | tcon = list_entry(tmp3, |
| 260 | atomic_set(&tcon->num_deletes, 0); | 257 | struct cifsTconInfo, |
| 261 | atomic_set(&tcon->num_mkdirs, 0); | 258 | tcon_list); |
| 262 | atomic_set(&tcon->num_rmdirs, 0); | 259 | atomic_set(&tcon->num_smbs_sent, 0); |
| 263 | atomic_set(&tcon->num_renames, 0); | 260 | atomic_set(&tcon->num_writes, 0); |
| 264 | atomic_set(&tcon->num_t2renames, 0); | 261 | atomic_set(&tcon->num_reads, 0); |
| 265 | atomic_set(&tcon->num_ffirst, 0); | 262 | atomic_set(&tcon->num_oplock_brks, 0); |
| 266 | atomic_set(&tcon->num_fnext, 0); | 263 | atomic_set(&tcon->num_opens, 0); |
| 267 | atomic_set(&tcon->num_fclose, 0); | 264 | atomic_set(&tcon->num_closes, 0); |
| 268 | atomic_set(&tcon->num_hardlinks, 0); | 265 | atomic_set(&tcon->num_deletes, 0); |
| 269 | atomic_set(&tcon->num_symlinks, 0); | 266 | atomic_set(&tcon->num_mkdirs, 0); |
| 270 | 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 | } | ||
| 271 | } | 278 | } |
| 272 | read_unlock(&GlobalSMBSeslock); | 279 | read_unlock(&cifs_tcp_ses_lock); |
| 273 | } | 280 | } |
| 274 | 281 | ||
| 275 | return count; | 282 | return count; |
| @@ -278,7 +285,9 @@ static ssize_t cifs_stats_proc_write(struct file *file, | |||
| 278 | 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) |
| 279 | { | 286 | { |
| 280 | int i; | 287 | int i; |
| 281 | struct list_head *tmp; | 288 | struct list_head *tmp1, *tmp2, *tmp3; |
| 289 | struct TCP_Server_Info *server; | ||
| 290 | struct cifsSesInfo *ses; | ||
| 282 | struct cifsTconInfo *tcon; | 291 | struct cifsTconInfo *tcon; |
| 283 | 292 | ||
| 284 | seq_printf(m, | 293 | seq_printf(m, |
| @@ -307,44 +316,55 @@ static int cifs_stats_proc_show(struct seq_file *m, void *v) | |||
| 307 | GlobalCurrentXid, GlobalMaxActiveXid); | 316 | GlobalCurrentXid, GlobalMaxActiveXid); |
| 308 | 317 | ||
| 309 | i = 0; | 318 | i = 0; |
| 310 | read_lock(&GlobalSMBSeslock); | 319 | read_lock(&cifs_tcp_ses_lock); |
| 311 | list_for_each(tmp, &GlobalTreeConnectionList) { | 320 | list_for_each(tmp1, &cifs_tcp_ses_list) { |
| 312 | i++; | 321 | server = list_entry(tmp1, struct TCP_Server_Info, |
| 313 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 322 | tcp_ses_list); |
| 314 | seq_printf(m, "\n%d) %s", i, tcon->treeName); | 323 | list_for_each(tmp2, &server->smb_ses_list) { |
| 315 | if (tcon->need_reconnect) | 324 | ses = list_entry(tmp2, struct cifsSesInfo, |
| 316 | seq_puts(m, "\tDISCONNECTED "); | 325 | smb_ses_list); |
| 317 | seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", | 326 | list_for_each(tmp3, &ses->tcon_list) { |
| 318 | atomic_read(&tcon->num_smbs_sent), | 327 | tcon = list_entry(tmp3, |
| 319 | atomic_read(&tcon->num_oplock_brks)); | 328 | struct cifsTconInfo, |
| 320 | seq_printf(m, "\nReads: %d Bytes: %lld", | 329 | tcon_list); |
| 321 | atomic_read(&tcon->num_reads), | 330 | i++; |
| 322 | (long long)(tcon->bytes_read)); | 331 | seq_printf(m, "\n%d) %s", i, tcon->treeName); |
| 323 | seq_printf(m, "\nWrites: %d Bytes: %lld", | 332 | if (tcon->need_reconnect) |
| 324 | atomic_read(&tcon->num_writes), | 333 | seq_puts(m, "\tDISCONNECTED "); |
| 325 | (long long)(tcon->bytes_written)); | 334 | seq_printf(m, "\nSMBs: %d Oplock Breaks: %d", |
| 326 | seq_printf(m, | 335 | atomic_read(&tcon->num_smbs_sent), |
| 327 | "\nLocks: %d HardLinks: %d Symlinks: %d", | 336 | atomic_read(&tcon->num_oplock_brks)); |
| 328 | atomic_read(&tcon->num_locks), | 337 | seq_printf(m, "\nReads: %d Bytes: %lld", |
| 329 | atomic_read(&tcon->num_hardlinks), | 338 | atomic_read(&tcon->num_reads), |
| 330 | atomic_read(&tcon->num_symlinks)); | 339 | (long long)(tcon->bytes_read)); |
| 331 | 340 | seq_printf(m, "\nWrites: %d Bytes: %lld", | |
| 332 | seq_printf(m, "\nOpens: %d Closes: %d Deletes: %d", | 341 | atomic_read(&tcon->num_writes), |
| 333 | atomic_read(&tcon->num_opens), | 342 | (long long)(tcon->bytes_written)); |
| 334 | atomic_read(&tcon->num_closes), | 343 | seq_printf(m, "\nLocks: %d HardLinks: %d " |
| 335 | atomic_read(&tcon->num_deletes)); | 344 | "Symlinks: %d", |
| 336 | seq_printf(m, "\nMkdirs: %d Rmdirs: %d", | 345 | atomic_read(&tcon->num_locks), |
| 337 | atomic_read(&tcon->num_mkdirs), | 346 | atomic_read(&tcon->num_hardlinks), |
| 338 | atomic_read(&tcon->num_rmdirs)); | 347 | atomic_read(&tcon->num_symlinks)); |
| 339 | seq_printf(m, "\nRenames: %d T2 Renames %d", | 348 | seq_printf(m, "\nOpens: %d Closes: %d" |
| 340 | atomic_read(&tcon->num_renames), | 349 | "Deletes: %d", |
| 341 | atomic_read(&tcon->num_t2renames)); | 350 | atomic_read(&tcon->num_opens), |
| 342 | seq_printf(m, "\nFindFirst: %d FNext %d FClose %d", | 351 | atomic_read(&tcon->num_closes), |
| 343 | atomic_read(&tcon->num_ffirst), | 352 | atomic_read(&tcon->num_deletes)); |
| 344 | atomic_read(&tcon->num_fnext), | 353 | seq_printf(m, "\nMkdirs: %d Rmdirs: %d", |
| 345 | 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 | } | ||
| 346 | } | 366 | } |
| 347 | read_unlock(&GlobalSMBSeslock); | 367 | read_unlock(&cifs_tcp_ses_lock); |
| 348 | 368 | ||
| 349 | seq_putc(m, '\n'); | 369 | seq_putc(m, '\n'); |
| 350 | return 0; | 370 | return 0; |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index a1e96620b097..d9cf467309e8 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); */ |
| @@ -1060,7 +1061,6 @@ init_cifs(void) | |||
| 1060 | int rc = 0; | 1061 | int rc = 0; |
| 1061 | cifs_proc_init(); | 1062 | cifs_proc_init(); |
| 1062 | INIT_LIST_HEAD(&cifs_tcp_ses_list); | 1063 | INIT_LIST_HEAD(&cifs_tcp_ses_list); |
| 1063 | INIT_LIST_HEAD(&GlobalTreeConnectionList); /* BB to be removed by jl */ | ||
| 1064 | INIT_LIST_HEAD(&GlobalOplock_Q); | 1064 | INIT_LIST_HEAD(&GlobalOplock_Q); |
| 1065 | #ifdef CONFIG_CIFS_EXPERIMENTAL | 1065 | #ifdef CONFIG_CIFS_EXPERIMENTAL |
| 1066 | INIT_LIST_HEAD(&GlobalDnotifyReqList); | 1066 | INIT_LIST_HEAD(&GlobalDnotifyReqList); |
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index 631a99f72f22..f1ae1f57c30d 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
| @@ -233,16 +233,15 @@ struct cifsSesInfo { | |||
| 233 | * session | 233 | * session |
| 234 | */ | 234 | */ |
| 235 | struct cifsTconInfo { | 235 | struct cifsTconInfo { |
| 236 | struct list_head cifsConnectionList; | 236 | struct list_head tcon_list; |
| 237 | int tc_count; | ||
| 237 | struct list_head openFileList; | 238 | struct list_head openFileList; |
| 238 | struct semaphore tconSem; | ||
| 239 | struct cifsSesInfo *ses; /* pointer to session associated with */ | 239 | struct cifsSesInfo *ses; /* pointer to session associated with */ |
| 240 | 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 */ |
| 241 | char *nativeFileSystem; | 241 | char *nativeFileSystem; |
| 242 | __u16 tid; /* The 2 byte tree id */ | 242 | __u16 tid; /* The 2 byte tree id */ |
| 243 | __u16 Flags; /* optional support bits */ | 243 | __u16 Flags; /* optional support bits */ |
| 244 | enum statusEnum tidStatus; | 244 | enum statusEnum tidStatus; |
| 245 | atomic_t useCount; /* how many explicit/implicit mounts to share */ | ||
| 246 | #ifdef CONFIG_CIFS_STATS | 245 | #ifdef CONFIG_CIFS_STATS |
| 247 | atomic_t num_smbs_sent; | 246 | atomic_t num_smbs_sent; |
| 248 | atomic_t num_writes; | 247 | atomic_t num_writes; |
| @@ -600,9 +599,13 @@ require use of the stronger protocol */ | |||
| 600 | */ | 599 | */ |
| 601 | GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; | 600 | GLOBAL_EXTERN struct list_head cifs_tcp_ses_list; |
| 602 | 601 | ||
| 603 | /* protects cifs_tcp_ses_list and srv_count for each tcp session */ | 602 | /* |
| 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. | ||
| 607 | */ | ||
| 604 | GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; | 608 | GLOBAL_EXTERN rwlock_t cifs_tcp_ses_lock; |
| 605 | GLOBAL_EXTERN struct list_head GlobalTreeConnectionList; /* BB to be removed */ | ||
| 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 9c95617baa4d..e6bb2d9d5b09 100644 --- a/fs/cifs/cifssmb.c +++ b/fs/cifs/cifssmb.c | |||
| @@ -742,50 +742,31 @@ CIFSSMBTDis(const int xid, struct cifsTconInfo *tcon) | |||
| 742 | int rc = 0; | 742 | int rc = 0; |
| 743 | 743 | ||
| 744 | cFYI(1, ("In tree disconnect")); | 744 | cFYI(1, ("In tree disconnect")); |
| 745 | /* | ||
| 746 | * If last user of the connection and | ||
| 747 | * connection alive - disconnect it | ||
| 748 | * If this is the last connection on the server session disconnect it | ||
| 749 | * (and inside session disconnect we should check if tcp socket needs | ||
| 750 | * to be freed and kernel thread woken up). | ||
| 751 | */ | ||
| 752 | if (tcon) | ||
| 753 | down(&tcon->tconSem); | ||
| 754 | else | ||
| 755 | return -EIO; | ||
| 756 | 745 | ||
| 757 | atomic_dec(&tcon->useCount); | 746 | /* BB: do we need to check this? These should never be NULL. */ |
| 758 | if (atomic_read(&tcon->useCount) > 0) { | 747 | if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) |
| 759 | up(&tcon->tconSem); | 748 | return -EIO; |
| 760 | return -EBUSY; | ||
| 761 | } | ||
| 762 | 749 | ||
| 763 | /* No need to return error on this operation if tid invalidated and | 750 | /* |
| 764 | closed on server already e.g. due to tcp session crashing */ | 751 | * No need to return error on this operation if tid invalidated and |
| 765 | if (tcon->need_reconnect) { | 752 | * closed on server already e.g. due to tcp session crashing. Also, |
| 766 | 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) | ||
| 767 | return 0; | 757 | return 0; |
| 768 | } | ||
| 769 | 758 | ||
| 770 | if ((tcon->ses == NULL) || (tcon->ses->server == NULL)) { | ||
| 771 | up(&tcon->tconSem); | ||
| 772 | return -EIO; | ||
| 773 | } | ||
| 774 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, | 759 | rc = small_smb_init(SMB_COM_TREE_DISCONNECT, 0, tcon, |
| 775 | (void **)&smb_buffer); | 760 | (void **)&smb_buffer); |
| 776 | if (rc) { | 761 | if (rc) |
| 777 | up(&tcon->tconSem); | ||
| 778 | return rc; | 762 | return rc; |
| 779 | } | ||
| 780 | 763 | ||
| 781 | rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); | 764 | rc = SendReceiveNoRsp(xid, tcon->ses, smb_buffer, 0); |
| 782 | if (rc) | 765 | if (rc) |
| 783 | cFYI(1, ("Tree disconnect failed %d", rc)); | 766 | cFYI(1, ("Tree disconnect failed %d", rc)); |
| 784 | 767 | ||
| 785 | up(&tcon->tconSem); | ||
| 786 | |||
| 787 | /* 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 |
| 788 | closed on server already e.g. due to tcp session crashing */ | 769 | closed on server already e.g. due to tcp session crashing */ |
| 789 | if (rc == -EAGAIN) | 770 | if (rc == -EAGAIN) |
| 790 | rc = 0; | 771 | rc = 0; |
| 791 | 772 | ||
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index a3dc0d7cafc3..2f2be8faabb3 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; |
| @@ -149,13 +149,12 @@ cifs_reconnect(struct TCP_Server_Info *server) | |||
| 149 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); | 149 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| 150 | ses->need_reconnect = true; | 150 | ses->need_reconnect = true; |
| 151 | ses->ipc_tid = 0; | 151 | ses->ipc_tid = 0; |
| 152 | } | 152 | list_for_each(tmp2, &ses->tcon_list) { |
| 153 | read_unlock(&cifs_tcp_ses_lock); | 153 | tcon = list_entry(tmp2, struct cifsTconInfo, tcon_list); |
| 154 | list_for_each(tmp, &GlobalTreeConnectionList) { | ||
| 155 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | ||
| 156 | if ((tcon->ses) && (tcon->ses->server == server)) | ||
| 157 | tcon->need_reconnect = true; | 154 | tcon->need_reconnect = true; |
| 155 | } | ||
| 158 | } | 156 | } |
| 157 | read_unlock(&cifs_tcp_ses_lock); | ||
| 159 | /* 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 */ |
| 160 | down(&server->tcpSem); | 159 | down(&server->tcpSem); |
| 161 | if (server->ssocket) { | 160 | if (server->ssocket) { |
| @@ -1462,6 +1461,52 @@ cifs_put_smb_ses(struct cifsSesInfo *ses) | |||
| 1462 | cifs_put_tcp_session(server); | 1461 | cifs_put_tcp_session(server); |
| 1463 | } | 1462 | } |
| 1464 | 1463 | ||
| 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)) | ||
| 1476 | continue; | ||
| 1477 | |||
| 1478 | ++tcon->tc_count; | ||
| 1479 | write_unlock(&cifs_tcp_ses_lock); | ||
| 1480 | return tcon; | ||
| 1481 | } | ||
| 1482 | write_unlock(&cifs_tcp_ses_lock); | ||
| 1483 | return NULL; | ||
| 1484 | } | ||
| 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 | |||
| 1465 | int | 1510 | int |
| 1466 | 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, |
| 1467 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, | 1512 | const struct nls_table *nls_codepage, unsigned int *pnum_referrals, |
| @@ -2220,11 +2265,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2220 | if (!rc) { | 2265 | if (!rc) { |
| 2221 | setup_cifs_sb(&volume_info, cifs_sb); | 2266 | setup_cifs_sb(&volume_info, cifs_sb); |
| 2222 | 2267 | ||
| 2268 | tcon = cifs_find_tcon(pSesInfo, volume_info.UNC); | ||
| 2223 | if (tcon) { | 2269 | if (tcon) { |
| 2224 | cFYI(1, ("Found match on UNC path")); | 2270 | cFYI(1, ("Found match on UNC path")); |
| 2225 | if (tcon->seal != volume_info.seal) | 2271 | /* existing tcon already has a reference */ |
| 2226 | cERROR(1, ("transport encryption setting " | 2272 | cifs_put_smb_ses(pSesInfo); |
| 2227 | "conflicts with existing tid")); | ||
| 2228 | } else { | 2273 | } else { |
| 2229 | tcon = tconInfoAlloc(); | 2274 | tcon = tconInfoAlloc(); |
| 2230 | if (tcon == NULL) { | 2275 | if (tcon == NULL) { |
| @@ -2257,6 +2302,10 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, | |||
| 2257 | if (rc) | 2302 | if (rc) |
| 2258 | goto mount_fail_check; | 2303 | goto mount_fail_check; |
| 2259 | tcon->seal = volume_info.seal; | 2304 | tcon->seal = volume_info.seal; |
| 2305 | tcon->ses = pSesInfo; | ||
| 2306 | write_lock(&cifs_tcp_ses_lock); | ||
| 2307 | list_add(&tcon->tcon_list, &pSesInfo->tcon_list); | ||
| 2308 | write_unlock(&cifs_tcp_ses_lock); | ||
| 2260 | } | 2309 | } |
| 2261 | 2310 | ||
| 2262 | /* we can have only one retry value for a connection | 2311 | /* we can have only one retry value for a connection |
| @@ -2283,18 +2332,14 @@ mount_fail_check: | |||
| 2283 | /* If find_unc succeeded then rc == 0 so we can not end */ | 2332 | /* If find_unc succeeded then rc == 0 so we can not end */ |
| 2284 | /* up accidently freeing someone elses tcon struct */ | 2333 | /* up accidently freeing someone elses tcon struct */ |
| 2285 | if (tcon) | 2334 | if (tcon) |
| 2286 | tconInfoFree(tcon); | 2335 | cifs_put_tcon(tcon); |
| 2287 | 2336 | else if (pSesInfo) | |
| 2288 | /* should also end up putting our tcp session ref if needed */ | ||
| 2289 | if (pSesInfo) | ||
| 2290 | cifs_put_smb_ses(pSesInfo); | 2337 | cifs_put_smb_ses(pSesInfo); |
| 2291 | else | 2338 | else |
| 2292 | cifs_put_tcp_session(srvTcp); | 2339 | cifs_put_tcp_session(srvTcp); |
| 2293 | goto out; | 2340 | goto out; |
| 2294 | } | 2341 | } |
| 2295 | atomic_inc(&tcon->useCount); | ||
| 2296 | cifs_sb->tcon = tcon; | 2342 | cifs_sb->tcon = tcon; |
| 2297 | tcon->ses = pSesInfo; | ||
| 2298 | 2343 | ||
| 2299 | /* do not care if following two calls succeed - informational */ | 2344 | /* do not care if following two calls succeed - informational */ |
| 2300 | if (!tcon->ipc) { | 2345 | if (!tcon->ipc) { |
| @@ -3565,23 +3610,10 @@ int | |||
| 3565 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | 3610 | cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) |
| 3566 | { | 3611 | { |
| 3567 | int rc = 0; | 3612 | int rc = 0; |
| 3568 | int xid; | ||
| 3569 | struct cifsSesInfo *ses = NULL; | ||
| 3570 | char *tmp; | 3613 | char *tmp; |
| 3571 | 3614 | ||
| 3572 | xid = GetXid(); | 3615 | if (cifs_sb->tcon) |
| 3573 | 3616 | cifs_put_tcon(cifs_sb->tcon); | |
| 3574 | if (cifs_sb->tcon) { | ||
| 3575 | ses = cifs_sb->tcon->ses; /* save ptr to ses before delete tcon!*/ | ||
| 3576 | rc = CIFSSMBTDis(xid, cifs_sb->tcon); | ||
| 3577 | if (rc == -EBUSY) { | ||
| 3578 | FreeXid(xid); | ||
| 3579 | return 0; | ||
| 3580 | } | ||
| 3581 | DeleteTconOplockQEntries(cifs_sb->tcon); | ||
| 3582 | tconInfoFree(cifs_sb->tcon); | ||
| 3583 | cifs_put_smb_ses(ses); | ||
| 3584 | } | ||
| 3585 | 3617 | ||
| 3586 | cifs_sb->tcon = NULL; | 3618 | cifs_sb->tcon = NULL; |
| 3587 | tmp = cifs_sb->prepath; | 3619 | tmp = cifs_sb->prepath; |
| @@ -3589,7 +3621,6 @@ cifs_umount(struct super_block *sb, struct cifs_sb_info *cifs_sb) | |||
| 3589 | cifs_sb->prepath = NULL; | 3621 | cifs_sb->prepath = NULL; |
| 3590 | kfree(tmp); | 3622 | kfree(tmp); |
| 3591 | 3623 | ||
| 3592 | FreeXid(xid); | ||
| 3593 | return rc; | 3624 | return rc; |
| 3594 | } | 3625 | } |
| 3595 | 3626 | ||
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index 46c8c7baccba..addd1dcc2d79 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
| @@ -79,6 +79,7 @@ sesInfoAlloc(void) | |||
| 79 | ret_buf->status = CifsNew; | 79 | ret_buf->status = CifsNew; |
| 80 | ++ret_buf->ses_count; | 80 | ++ret_buf->ses_count; |
| 81 | INIT_LIST_HEAD(&ret_buf->smb_ses_list); | 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 | } | 84 | } |
| 84 | return ret_buf; | 85 | return ret_buf; |
| @@ -107,17 +108,14 @@ tconInfoAlloc(void) | |||
| 107 | struct cifsTconInfo *ret_buf; | 108 | struct cifsTconInfo *ret_buf; |
| 108 | ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); | 109 | ret_buf = kzalloc(sizeof(struct cifsTconInfo), GFP_KERNEL); |
| 109 | if (ret_buf) { | 110 | if (ret_buf) { |
| 110 | write_lock(&GlobalSMBSeslock); | ||
| 111 | atomic_inc(&tconInfoAllocCount); | 111 | atomic_inc(&tconInfoAllocCount); |
| 112 | list_add(&ret_buf->cifsConnectionList, | ||
| 113 | &GlobalTreeConnectionList); | ||
| 114 | ret_buf->tidStatus = CifsNew; | 112 | ret_buf->tidStatus = CifsNew; |
| 113 | ++ret_buf->tc_count; | ||
| 115 | INIT_LIST_HEAD(&ret_buf->openFileList); | 114 | INIT_LIST_HEAD(&ret_buf->openFileList); |
| 116 | init_MUTEX(&ret_buf->tconSem); | 115 | INIT_LIST_HEAD(&ret_buf->tcon_list); |
| 117 | #ifdef CONFIG_CIFS_STATS | 116 | #ifdef CONFIG_CIFS_STATS |
| 118 | spin_lock_init(&ret_buf->stat_lock); | 117 | spin_lock_init(&ret_buf->stat_lock); |
| 119 | #endif | 118 | #endif |
| 120 | write_unlock(&GlobalSMBSeslock); | ||
| 121 | } | 119 | } |
| 122 | return ret_buf; | 120 | return ret_buf; |
| 123 | } | 121 | } |
| @@ -129,10 +127,7 @@ tconInfoFree(struct cifsTconInfo *buf_to_free) | |||
| 129 | cFYI(1, ("Null buffer passed to tconInfoFree")); | 127 | cFYI(1, ("Null buffer passed to tconInfoFree")); |
| 130 | return; | 128 | return; |
| 131 | } | 129 | } |
| 132 | write_lock(&GlobalSMBSeslock); | ||
| 133 | atomic_dec(&tconInfoAllocCount); | 130 | atomic_dec(&tconInfoAllocCount); |
| 134 | list_del(&buf_to_free->cifsConnectionList); | ||
| 135 | write_unlock(&GlobalSMBSeslock); | ||
| 136 | kfree(buf_to_free->nativeFileSystem); | 131 | kfree(buf_to_free->nativeFileSystem); |
| 137 | kfree(buf_to_free); | 132 | kfree(buf_to_free); |
| 138 | } | 133 | } |
| @@ -493,9 +488,10 @@ bool | |||
| 493 | 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) |
| 494 | { | 489 | { |
| 495 | 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; |
| 496 | struct list_head *tmp; | 491 | struct list_head *tmp, *tmp1, *tmp2; |
| 497 | struct list_head *tmp1; | 492 | struct cifsSesInfo *ses; |
| 498 | struct cifsTconInfo *tcon; | 493 | struct cifsTconInfo *tcon; |
| 494 | struct cifsInodeInfo *pCifsInode; | ||
| 499 | struct cifsFileInfo *netfile; | 495 | struct cifsFileInfo *netfile; |
| 500 | 496 | ||
| 501 | cFYI(1, ("Checking for oplock break or dnotify response")); | 497 | cFYI(1, ("Checking for oplock break or dnotify response")); |
| @@ -550,42 +546,42 @@ is_valid_oplock_break(struct smb_hdr *buf, struct TCP_Server_Info *srv) | |||
| 550 | return false; | 546 | return false; |
| 551 | 547 | ||
| 552 | /* look up tcon based on tid & uid */ | 548 | /* look up tcon based on tid & uid */ |
| 553 | read_lock(&GlobalSMBSeslock); | 549 | read_lock(&cifs_tcp_ses_lock); |
| 554 | list_for_each(tmp, &GlobalTreeConnectionList) { | 550 | list_for_each(tmp, &srv->smb_ses_list) { |
| 555 | tcon = list_entry(tmp, struct cifsTconInfo, cifsConnectionList); | 551 | ses = list_entry(tmp, struct cifsSesInfo, smb_ses_list); |
| 556 | 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 | |||
| 557 | cifs_stats_inc(&tcon->num_oplock_brks); | 557 | cifs_stats_inc(&tcon->num_oplock_brks); |
| 558 | list_for_each(tmp1, &tcon->openFileList) { | 558 | list_for_each(tmp2, &tcon->openFileList) { |
| 559 | netfile = list_entry(tmp1, struct cifsFileInfo, | 559 | netfile = list_entry(tmp2, struct cifsFileInfo, |
| 560 | tlist); | 560 | tlist); |
| 561 | if (pSMB->Fid == netfile->netfid) { | 561 | if (pSMB->Fid != netfile->netfid) |
| 562 | struct cifsInodeInfo *pCifsInode; | 562 | continue; |
| 563 | read_unlock(&GlobalSMBSeslock); | 563 | |
| 564 | cFYI(1, | 564 | read_unlock(&cifs_tcp_ses_lock); |
| 565 | ("file id match, oplock break")); | 565 | cFYI(1, ("file id match, oplock break")); |
| 566 | pCifsInode = | 566 | pCifsInode = CIFS_I(netfile->pInode); |
| 567 | CIFS_I(netfile->pInode); | 567 | pCifsInode->clientCanCacheAll = false; |
| 568 | pCifsInode->clientCanCacheAll = false; | 568 | if (pSMB->OplockLevel == 0) |
| 569 | if (pSMB->OplockLevel == 0) | 569 | pCifsInode->clientCanCacheRead = false; |
| 570 | pCifsInode->clientCanCacheRead | 570 | pCifsInode->oplockPending = true; |
| 571 | = false; | 571 | AllocOplockQEntry(netfile->pInode, |
| 572 | pCifsInode->oplockPending = true; | 572 | netfile->netfid, tcon); |
| 573 | AllocOplockQEntry(netfile->pInode, | 573 | cFYI(1, ("about to wake up oplock thread")); |
| 574 | netfile->netfid, | 574 | if (oplockThread) |
| 575 | tcon); | 575 | wake_up_process(oplockThread); |
| 576 | cFYI(1, | 576 | |
| 577 | ("about to wake up oplock thread")); | 577 | return true; |
| 578 | if (oplockThread) | ||
| 579 | wake_up_process(oplockThread); | ||
| 580 | return true; | ||
| 581 | } | ||
| 582 | } | 578 | } |
| 583 | read_unlock(&GlobalSMBSeslock); | 579 | read_unlock(&cifs_tcp_ses_lock); |
| 584 | cFYI(1, ("No matching file for oplock break")); | 580 | cFYI(1, ("No matching file for oplock break")); |
| 585 | return true; | 581 | return true; |
| 586 | } | 582 | } |
| 587 | } | 583 | } |
| 588 | read_unlock(&GlobalSMBSeslock); | 584 | read_unlock(&cifs_tcp_ses_lock); |
| 589 | cFYI(1, ("Can not process oplock break for non-existent connection")); | 585 | cFYI(1, ("Can not process oplock break for non-existent connection")); |
| 590 | return true; | 586 | return true; |
| 591 | } | 587 | } |
