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.c74
1 files changed, 69 insertions, 5 deletions
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 3a7f8bd5127d..cd31715f03f4 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -389,6 +389,27 @@ __u8 smb2_map_lease_to_oplock(__le32 lease_state)
389 return 0; 389 return 0;
390} 390}
391 391
392struct smb2_lease_break_work {
393 struct work_struct lease_break;
394 struct tcon_link *tlink;
395 __u8 lease_key[16];
396 __le32 lease_state;
397};
398
399static void
400cifs_ses_oplock_break(struct work_struct *work)
401{
402 struct smb2_lease_break_work *lw = container_of(work,
403 struct smb2_lease_break_work, lease_break);
404 int rc;
405
406 rc = SMB2_lease_break(0, tlink_tcon(lw->tlink), lw->lease_key,
407 lw->lease_state);
408 cFYI(1, "Lease release rc %d", rc);
409 cifs_put_tlink(lw->tlink);
410 kfree(lw);
411}
412
392static bool 413static bool
393smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) 414smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
394{ 415{
@@ -398,6 +419,19 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
398 struct cifs_tcon *tcon; 419 struct cifs_tcon *tcon;
399 struct cifsInodeInfo *cinode; 420 struct cifsInodeInfo *cinode;
400 struct cifsFileInfo *cfile; 421 struct cifsFileInfo *cfile;
422 struct cifs_pending_open *open;
423 struct smb2_lease_break_work *lw;
424 bool found;
425 int ack_req = rsp->Flags & SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED;
426
427 lw = kmalloc(sizeof(struct smb2_lease_break_work), GFP_KERNEL);
428 if (!lw) {
429 cERROR(1, "Memory allocation failed during lease break check");
430 return false;
431 }
432
433 INIT_WORK(&lw->lease_break, cifs_ses_oplock_break);
434 lw->lease_state = rsp->NewLeaseState;
401 435
402 cFYI(1, "Checking for lease break"); 436 cFYI(1, "Checking for lease break");
403 437
@@ -405,28 +439,29 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
405 spin_lock(&cifs_tcp_ses_lock); 439 spin_lock(&cifs_tcp_ses_lock);
406 list_for_each(tmp, &server->smb_ses_list) { 440 list_for_each(tmp, &server->smb_ses_list) {
407 ses = list_entry(tmp, struct cifs_ses, smb_ses_list); 441 ses = list_entry(tmp, struct cifs_ses, smb_ses_list);
442
443 spin_lock(&cifs_file_list_lock);
408 list_for_each(tmp1, &ses->tcon_list) { 444 list_for_each(tmp1, &ses->tcon_list) {
409 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list); 445 tcon = list_entry(tmp1, struct cifs_tcon, tcon_list);
410 446
411 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); 447 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks);
412 spin_lock(&cifs_file_list_lock);
413 list_for_each(tmp2, &tcon->openFileList) { 448 list_for_each(tmp2, &tcon->openFileList) {
414 cfile = list_entry(tmp2, struct cifsFileInfo, 449 cfile = list_entry(tmp2, struct cifsFileInfo,
415 tlist); 450 tlist);
416 cinode = CIFS_I(cfile->dentry->d_inode); 451 cinode = CIFS_I(cfile->dentry->d_inode);
417 452
418 if (memcmp(cinode->lease_key, rsp->LeaseKey, 453 if (memcmp(cinode->lease_key, rsp->LeaseKey,
419 SMB2_LEASE_KEY_SIZE)) 454 SMB2_LEASE_KEY_SIZE))
420 continue; 455 continue;
421 456
457 cFYI(1, "found in the open list");
422 cFYI(1, "lease key match, lease break 0x%d", 458 cFYI(1, "lease key match, lease break 0x%d",
423 le32_to_cpu(rsp->NewLeaseState)); 459 le32_to_cpu(rsp->NewLeaseState));
424 460
425 smb2_set_oplock_level(cinode, 461 smb2_set_oplock_level(cinode,
426 smb2_map_lease_to_oplock(rsp->NewLeaseState)); 462 smb2_map_lease_to_oplock(rsp->NewLeaseState));
427 463
428 if (rsp->Flags & 464 if (ack_req)
429 SMB2_NOTIFY_BREAK_LEASE_FLAG_ACK_REQUIRED)
430 cfile->oplock_break_cancelled = false; 465 cfile->oplock_break_cancelled = false;
431 else 466 else
432 cfile->oplock_break_cancelled = true; 467 cfile->oplock_break_cancelled = true;
@@ -437,10 +472,39 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server)
437 spin_unlock(&cifs_tcp_ses_lock); 472 spin_unlock(&cifs_tcp_ses_lock);
438 return true; 473 return true;
439 } 474 }
440 spin_unlock(&cifs_file_list_lock); 475
476 found = false;
477 list_for_each_entry(open, &tcon->pending_opens, olist) {
478 if (memcmp(open->lease_key, rsp->LeaseKey,
479 SMB2_LEASE_KEY_SIZE))
480 continue;
481
482 if (!found && ack_req) {
483 found = true;
484 memcpy(lw->lease_key, open->lease_key,
485 SMB2_LEASE_KEY_SIZE);
486 lw->tlink = cifs_get_tlink(open->tlink);
487 queue_work(cifsiod_wq,
488 &lw->lease_break);
489 }
490
491 cFYI(1, "found in the pending open list");
492 cFYI(1, "lease key match, lease break 0x%d",
493 le32_to_cpu(rsp->NewLeaseState));
494
495 open->oplock =
496 smb2_map_lease_to_oplock(rsp->NewLeaseState);
497 }
498 if (found) {
499 spin_unlock(&cifs_file_list_lock);
500 spin_unlock(&cifs_tcp_ses_lock);
501 return true;
502 }
441 } 503 }
504 spin_unlock(&cifs_file_list_lock);
442 } 505 }
443 spin_unlock(&cifs_tcp_ses_lock); 506 spin_unlock(&cifs_tcp_ses_lock);
507 kfree(lw);
444 cFYI(1, "Can not process lease break - no lease matched"); 508 cFYI(1, "Can not process lease break - no lease matched");
445 return false; 509 return false;
446} 510}