aboutsummaryrefslogtreecommitdiffstats
path: root/fs/cifs/smb2misc.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/cifs/smb2misc.c')
-rw-r--r--fs/cifs/smb2misc.c90
1 files changed, 89 insertions, 1 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 01479a3fee8d..3a7f8bd5127d 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -148,6 +148,13 @@ smb2_check_message(char *buf, unsigned int length)
148 cERROR(1, "Illegal response size %u for command %d", 148 cERROR(1, "Illegal response size %u for command %d",
149 le16_to_cpu(pdu->StructureSize2), command); 149 le16_to_cpu(pdu->StructureSize2), command);
150 return 1; 150 return 1;
151 } else if (command == SMB2_OPLOCK_BREAK_HE && (hdr->Status == 0)
152 && (le16_to_cpu(pdu->StructureSize2) != 44)
153 && (le16_to_cpu(pdu->StructureSize2) != 36)) {
154 /* special case for SMB2.1 lease break message */
155 cERROR(1, "Illegal response size %d for oplock break",
156 le16_to_cpu(pdu->StructureSize2));
157 return 1;
151 } 158 }
152 } 159 }
153 160
@@ -360,6 +367,84 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb)
360 return to; 367 return to;
361} 368}
362 369
370__le32
371smb2_get_lease_state(struct cifsInodeInfo *cinode)
372{
373 if (cinode->clientCanCacheAll)
374 return SMB2_LEASE_WRITE_CACHING | SMB2_LEASE_READ_CACHING;
375 else if (cinode->clientCanCacheRead)
376 return SMB2_LEASE_READ_CACHING;
377 return 0;
378}
379
380__u8 smb2_map_lease_to_oplock(__le32 lease_state)
381{
382 if (lease_state & SMB2_LEASE_WRITE_CACHING) {
383 if (lease_state & SMB2_LEASE_HANDLE_CACHING)
384 return SMB2_OPLOCK_LEVEL_BATCH;
385 else
386 return SMB2_OPLOCK_LEVEL_EXCLUSIVE;
387 } else if (lease_state & SMB2_LEASE_READ_CACHING)
388 return SMB2_OPLOCK_LEVEL_II;
389 return 0;
390}
391
392static bool
393smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
394{
395 struct smb2_lease_break *rsp = (struct smb2_lease_break *)buffer;
396 struct list_head *tmp, *tmp1, *tmp2;
397 struct cifs_ses *ses;
398 struct cifs_tcon *tcon;
399 struct cifsInodeInfo *cinode;
400 struct cifsFileInfo *cfile;
401
402 cFYI(1, "Checking for lease break");
403
404 /* look up tcon based on tid & uid */
405 spin_lock(&cifs_tcp_ses_lock);
406 list_for_each(tmp, &server->smb_ses_list) {
407 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
408 list_for_each(tmp1, &ses->tcon_list) {
409 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
410
411 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
412 spin_lock(&cifs_file_list_lock);
413 list_for_each(tmp2, &tcon->openFileList) {
414 cfile = list_entry(tmp2, struct cifsFileInfo,
415 tlist);
416 cinode = CIFS_I(cfile->dentry->d_inode);
417
418 if (memcmp(cinode->lease_key, rsp->LeaseKey,
419 SMB2_LEASE_KEY_SIZE))
420 continue;
421
422 cFYI(1, "lease key match, lease break 0x%d",
423 le32_to_cpu(rsp->NewLeaseState));
424
425 smb2_set_oplock_level(cinode,
426 smb2_map_lease_to_oplock(rsp->NewLeaseState));
427
428 if (rsp->Flags &
429 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)
430 cfile->oplock_break_cancelled = false;
431 else
432 cfile->oplock_break_cancelled = true;
433
434 queue_work(cifsiod_wq, &cfile->oplock_break);
435
436 spin_unlock(&cifs_file_list_lock);
437 spin_unlock(&cifs_tcp_ses_lock);
438 return true;
439 }
440 spin_unlock(&cifs_file_list_lock);
441 }
442 }
443 spin_unlock(&cifs_tcp_ses_lock);
444 cFYI(1, "Can not process lease break - no lease matched");
445 return false;
446}
447
363bool 448bool
364smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) 449smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
365{ 450{
@@ -377,7 +462,10 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
377 462
378 if (le16_to_cpu(rsp->StructureSize) != 463 if (le16_to_cpu(rsp->StructureSize) !=
379 smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { 464 smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) {
380 return false; 465 if (le16_to_cpu(rsp->StructureSize) == 44)
466 return smb2_is_valid_lease_break(buffer, server);
467 else
468 return false;
381 } 469 }
382 470
383 cFYI(1, "oplock level 0x%d", rsp->OplockLevel); 471 cFYI(1, "oplock level 0x%d", rsp->OplockLevel);