diff options
-rw-r--r-- | fs/cifs/cifsglob.h | 12 | ||||
-rw-r--r-- | fs/cifs/cifsproto.h | 7 | ||||
-rw-r--r-- | fs/cifs/connect.c | 1 | ||||
-rw-r--r-- | fs/cifs/dir.c | 9 | ||||
-rw-r--r-- | fs/cifs/file.c | 35 | ||||
-rw-r--r-- | fs/cifs/misc.c | 30 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 74 |
7 files changed, 158 insertions, 10 deletions
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h index b6ec142028e8..a39e5b7fc844 100644 --- a/fs/cifs/cifsglob.h +++ b/fs/cifs/cifsglob.h | |||
@@ -715,6 +715,7 @@ struct cifs_ses { | |||
715 | __u16 session_flags; | 715 | __u16 session_flags; |
716 | #endif /* CONFIG_CIFS_SMB2 */ | 716 | #endif /* CONFIG_CIFS_SMB2 */ |
717 | }; | 717 | }; |
718 | |||
718 | /* no more than one of the following three session flags may be set */ | 719 | /* no more than one of the following three session flags may be set */ |
719 | #define CIFS_SES_NT4 1 | 720 | #define CIFS_SES_NT4 1 |
720 | #define CIFS_SES_OS2 2 | 721 | #define CIFS_SES_OS2 2 |
@@ -821,6 +822,7 @@ struct cifs_tcon { | |||
821 | u64 resource_id; /* server resource id */ | 822 | u64 resource_id; /* server resource id */ |
822 | struct fscache_cookie *fscache; /* cookie for share */ | 823 | struct fscache_cookie *fscache; /* cookie for share */ |
823 | #endif | 824 | #endif |
825 | struct list_head pending_opens; /* list of incomplete opens */ | ||
824 | /* BB add field for back pointer to sb struct(s)? */ | 826 | /* BB add field for back pointer to sb struct(s)? */ |
825 | }; | 827 | }; |
826 | 828 | ||
@@ -863,6 +865,15 @@ cifs_get_tlink(struct tcon_link *tlink) | |||
863 | /* This function is always expected to succeed */ | 865 | /* This function is always expected to succeed */ |
864 | extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); | 866 | extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); |
865 | 867 | ||
868 | #define CIFS_OPLOCK_NO_CHANGE 0xfe | ||
869 | |||
870 | struct cifs_pending_open { | ||
871 | struct list_head olist; | ||
872 | struct tcon_link *tlink; | ||
873 | __u8 lease_key[16]; | ||
874 | __u32 oplock; | ||
875 | }; | ||
876 | |||
866 | /* | 877 | /* |
867 | * This info hangs off the cifsFileInfo structure, pointed to by llist. | 878 | * This info hangs off the cifsFileInfo structure, pointed to by llist. |
868 | * This is used to track byte stream locks on the file | 879 | * This is used to track byte stream locks on the file |
@@ -903,6 +914,7 @@ struct cifs_fid { | |||
903 | __u64 volatile_fid; /* volatile file id for smb2 */ | 914 | __u64 volatile_fid; /* volatile file id for smb2 */ |
904 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ | 915 | __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ |
905 | #endif | 916 | #endif |
917 | struct cifs_pending_open *pending_open; | ||
906 | }; | 918 | }; |
907 | 919 | ||
908 | struct cifs_fid_locks { | 920 | struct cifs_fid_locks { |
diff --git a/fs/cifs/cifsproto.h b/fs/cifs/cifsproto.h index c758ee7b0307..09ea6321c55a 100644 --- a/fs/cifs/cifsproto.h +++ b/fs/cifs/cifsproto.h | |||
@@ -184,6 +184,13 @@ extern bool cifs_find_lock_conflict(struct cifsFileInfo *cfile, __u64 offset, | |||
184 | __u64 length, __u8 type, | 184 | __u64 length, __u8 type, |
185 | struct cifsLockInfo **conf_lock, | 185 | struct cifsLockInfo **conf_lock, |
186 | bool rw_check); | 186 | bool rw_check); |
187 | extern void cifs_add_pending_open(struct cifs_fid *fid, | ||
188 | struct tcon_link *tlink, | ||
189 | struct cifs_pending_open *open); | ||
190 | extern void cifs_add_pending_open_locked(struct cifs_fid *fid, | ||
191 | struct tcon_link *tlink, | ||
192 | struct cifs_pending_open *open); | ||
193 | extern void cifs_del_pending_open(struct cifs_pending_open *open); | ||
187 | 194 | ||
188 | #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) | 195 | #if IS_ENABLED(CONFIG_CIFS_DFS_UPCALL) |
189 | extern void cifs_dfs_release_automount_timer(void); | 196 | extern void cifs_dfs_release_automount_timer(void); |
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index 443e39633107..59c595e8a1b0 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c | |||
@@ -2645,6 +2645,7 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb_vol *volume_info) | |||
2645 | tcon->retry = volume_info->retry; | 2645 | tcon->retry = volume_info->retry; |
2646 | tcon->nocase = volume_info->nocase; | 2646 | tcon->nocase = volume_info->nocase; |
2647 | tcon->local_lease = volume_info->local_lease; | 2647 | tcon->local_lease = volume_info->local_lease; |
2648 | INIT_LIST_HEAD(&tcon->pending_opens); | ||
2648 | 2649 | ||
2649 | spin_lock(&cifs_tcp_ses_lock); | 2650 | spin_lock(&cifs_tcp_ses_lock); |
2650 | list_add(&tcon->tcon_list, &ses->tcon_list); | 2651 | list_add(&tcon->tcon_list, &ses->tcon_list); |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 4f2147c5adb6..7c0a81283645 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -382,6 +382,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
382 | struct cifs_tcon *tcon; | 382 | struct cifs_tcon *tcon; |
383 | struct TCP_Server_Info *server; | 383 | struct TCP_Server_Info *server; |
384 | struct cifs_fid fid; | 384 | struct cifs_fid fid; |
385 | struct cifs_pending_open open; | ||
385 | __u32 oplock; | 386 | __u32 oplock; |
386 | struct cifsFileInfo *file_info; | 387 | struct cifsFileInfo *file_info; |
387 | 388 | ||
@@ -423,16 +424,21 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
423 | if (server->ops->new_lease_key) | 424 | if (server->ops->new_lease_key) |
424 | server->ops->new_lease_key(&fid); | 425 | server->ops->new_lease_key(&fid); |
425 | 426 | ||
427 | cifs_add_pending_open(&fid, tlink, &open); | ||
428 | |||
426 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, | 429 | rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode, |
427 | &oplock, &fid, opened); | 430 | &oplock, &fid, opened); |
428 | 431 | ||
429 | if (rc) | 432 | if (rc) { |
433 | cifs_del_pending_open(&open); | ||
430 | goto out; | 434 | goto out; |
435 | } | ||
431 | 436 | ||
432 | rc = finish_open(file, direntry, generic_file_open, opened); | 437 | rc = finish_open(file, direntry, generic_file_open, opened); |
433 | if (rc) { | 438 | if (rc) { |
434 | if (server->ops->close) | 439 | if (server->ops->close) |
435 | server->ops->close(xid, tcon, &fid); | 440 | server->ops->close(xid, tcon, &fid); |
441 | cifs_del_pending_open(&open); | ||
436 | goto out; | 442 | goto out; |
437 | } | 443 | } |
438 | 444 | ||
@@ -440,6 +446,7 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry, | |||
440 | if (file_info == NULL) { | 446 | if (file_info == NULL) { |
441 | if (server->ops->close) | 447 | if (server->ops->close) |
442 | server->ops->close(xid, tcon, &fid); | 448 | server->ops->close(xid, tcon, &fid); |
449 | cifs_del_pending_open(&open); | ||
443 | rc = -ENOMEM; | 450 | rc = -ENOMEM; |
444 | } | 451 | } |
445 | 452 | ||
diff --git a/fs/cifs/file.c b/fs/cifs/file.c index e93e3d2c69e6..88e9c74e2cac 100644 --- a/fs/cifs/file.c +++ b/fs/cifs/file.c | |||
@@ -247,6 +247,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
247 | struct cifsInodeInfo *cinode = CIFS_I(inode); | 247 | struct cifsInodeInfo *cinode = CIFS_I(inode); |
248 | struct cifsFileInfo *cfile; | 248 | struct cifsFileInfo *cfile; |
249 | struct cifs_fid_locks *fdlocks; | 249 | struct cifs_fid_locks *fdlocks; |
250 | struct cifs_tcon *tcon = tlink_tcon(tlink); | ||
250 | 251 | ||
251 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); | 252 | cfile = kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL); |
252 | if (cfile == NULL) | 253 | if (cfile == NULL) |
@@ -274,10 +275,15 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, | |||
274 | cfile->tlink = cifs_get_tlink(tlink); | 275 | cfile->tlink = cifs_get_tlink(tlink); |
275 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); | 276 | INIT_WORK(&cfile->oplock_break, cifs_oplock_break); |
276 | mutex_init(&cfile->fh_mutex); | 277 | mutex_init(&cfile->fh_mutex); |
277 | tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); | ||
278 | 278 | ||
279 | spin_lock(&cifs_file_list_lock); | 279 | spin_lock(&cifs_file_list_lock); |
280 | list_add(&cfile->tlist, &(tlink_tcon(tlink)->openFileList)); | 280 | if (fid->pending_open->oplock != CIFS_OPLOCK_NO_CHANGE) |
281 | oplock = fid->pending_open->oplock; | ||
282 | list_del(&fid->pending_open->olist); | ||
283 | |||
284 | tlink_tcon(tlink)->ses->server->ops->set_fid(cfile, fid, oplock); | ||
285 | |||
286 | list_add(&cfile->tlist, &tcon->openFileList); | ||
281 | /* if readable file instance put first in list*/ | 287 | /* if readable file instance put first in list*/ |
282 | if (file->f_mode & FMODE_READ) | 288 | if (file->f_mode & FMODE_READ) |
283 | list_add(&cfile->flist, &cinode->openFileList); | 289 | list_add(&cfile->flist, &cinode->openFileList); |
@@ -307,9 +313,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
307 | { | 313 | { |
308 | struct inode *inode = cifs_file->dentry->d_inode; | 314 | struct inode *inode = cifs_file->dentry->d_inode; |
309 | struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); | 315 | struct cifs_tcon *tcon = tlink_tcon(cifs_file->tlink); |
316 | struct TCP_Server_Info *server = tcon->ses->server; | ||
310 | struct cifsInodeInfo *cifsi = CIFS_I(inode); | 317 | struct cifsInodeInfo *cifsi = CIFS_I(inode); |
311 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); | 318 | struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); |
312 | struct cifsLockInfo *li, *tmp; | 319 | struct cifsLockInfo *li, *tmp; |
320 | struct cifs_fid fid; | ||
321 | struct cifs_pending_open open; | ||
313 | 322 | ||
314 | spin_lock(&cifs_file_list_lock); | 323 | spin_lock(&cifs_file_list_lock); |
315 | if (--cifs_file->count > 0) { | 324 | if (--cifs_file->count > 0) { |
@@ -317,6 +326,12 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
317 | return; | 326 | return; |
318 | } | 327 | } |
319 | 328 | ||
329 | if (server->ops->get_lease_key) | ||
330 | server->ops->get_lease_key(inode, &fid); | ||
331 | |||
332 | /* store open in pending opens to make sure we don't miss lease break */ | ||
333 | cifs_add_pending_open_locked(&fid, cifs_file->tlink, &open); | ||
334 | |||
320 | /* remove it from the lists */ | 335 | /* remove it from the lists */ |
321 | list_del(&cifs_file->flist); | 336 | list_del(&cifs_file->flist); |
322 | list_del(&cifs_file->tlist); | 337 | list_del(&cifs_file->tlist); |
@@ -348,6 +363,8 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
348 | free_xid(xid); | 363 | free_xid(xid); |
349 | } | 364 | } |
350 | 365 | ||
366 | cifs_del_pending_open(&open); | ||
367 | |||
351 | /* | 368 | /* |
352 | * Delete any outstanding lock records. We'll lose them when the file | 369 | * Delete any outstanding lock records. We'll lose them when the file |
353 | * is closed anyway. | 370 | * is closed anyway. |
@@ -368,6 +385,7 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file) | |||
368 | } | 385 | } |
369 | 386 | ||
370 | int cifs_open(struct inode *inode, struct file *file) | 387 | int cifs_open(struct inode *inode, struct file *file) |
388 | |||
371 | { | 389 | { |
372 | int rc = -EACCES; | 390 | int rc = -EACCES; |
373 | unsigned int xid; | 391 | unsigned int xid; |
@@ -380,6 +398,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
380 | char *full_path = NULL; | 398 | char *full_path = NULL; |
381 | bool posix_open_ok = false; | 399 | bool posix_open_ok = false; |
382 | struct cifs_fid fid; | 400 | struct cifs_fid fid; |
401 | struct cifs_pending_open open; | ||
383 | 402 | ||
384 | xid = get_xid(); | 403 | xid = get_xid(); |
385 | 404 | ||
@@ -401,7 +420,7 @@ int cifs_open(struct inode *inode, struct file *file) | |||
401 | cFYI(1, "inode = 0x%p file flags are 0x%x for %s", | 420 | cFYI(1, "inode = 0x%p file flags are 0x%x for %s", |
402 | inode, file->f_flags, full_path); | 421 | inode, file->f_flags, full_path); |
403 | 422 | ||
404 | if (tcon->ses->server->oplocks) | 423 | if (server->oplocks) |
405 | oplock = REQ_OPLOCK; | 424 | oplock = REQ_OPLOCK; |
406 | else | 425 | else |
407 | oplock = 0; | 426 | oplock = 0; |
@@ -434,20 +453,28 @@ int cifs_open(struct inode *inode, struct file *file) | |||
434 | */ | 453 | */ |
435 | } | 454 | } |
436 | 455 | ||
456 | if (server->ops->get_lease_key) | ||
457 | server->ops->get_lease_key(inode, &fid); | ||
458 | |||
459 | cifs_add_pending_open(&fid, tlink, &open); | ||
460 | |||
437 | if (!posix_open_ok) { | 461 | if (!posix_open_ok) { |
438 | if (server->ops->get_lease_key) | 462 | if (server->ops->get_lease_key) |
439 | server->ops->get_lease_key(inode, &fid); | 463 | server->ops->get_lease_key(inode, &fid); |
440 | 464 | ||
441 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, | 465 | rc = cifs_nt_open(full_path, inode, cifs_sb, tcon, |
442 | file->f_flags, &oplock, &fid, xid); | 466 | file->f_flags, &oplock, &fid, xid); |
443 | if (rc) | 467 | if (rc) { |
468 | cifs_del_pending_open(&open); | ||
444 | goto out; | 469 | goto out; |
470 | } | ||
445 | } | 471 | } |
446 | 472 | ||
447 | cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); | 473 | cfile = cifs_new_fileinfo(&fid, file, tlink, oplock); |
448 | if (cfile == NULL) { | 474 | if (cfile == NULL) { |
449 | if (server->ops->close) | 475 | if (server->ops->close) |
450 | server->ops->close(xid, tcon, &fid); | 476 | server->ops->close(xid, tcon, &fid); |
477 | cifs_del_pending_open(&open); | ||
451 | rc = -ENOMEM; | 478 | rc = -ENOMEM; |
452 | goto out; | 479 | goto out; |
453 | } | 480 | } |
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c index a921b0712eff..3a00c0d0cead 100644 --- a/fs/cifs/misc.c +++ b/fs/cifs/misc.c | |||
@@ -579,3 +579,33 @@ backup_cred(struct cifs_sb_info *cifs_sb) | |||
579 | 579 | ||
580 | return false; | 580 | return false; |
581 | } | 581 | } |
582 | |||
583 | void | ||
584 | cifs_del_pending_open(struct cifs_pending_open *open) | ||
585 | { | ||
586 | spin_lock(&cifs_file_list_lock); | ||
587 | list_del(&open->olist); | ||
588 | spin_unlock(&cifs_file_list_lock); | ||
589 | } | ||
590 | |||
591 | void | ||
592 | cifs_add_pending_open_locked(struct cifs_fid *fid, struct tcon_link *tlink, | ||
593 | struct cifs_pending_open *open) | ||
594 | { | ||
595 | #ifdef CONFIG_CIFS_SMB2 | ||
596 | memcpy(open->lease_key, fid->lease_key, SMB2_LEASE_KEY_SIZE); | ||
597 | #endif | ||
598 | open->oplock = CIFS_OPLOCK_NO_CHANGE; | ||
599 | open->tlink = tlink; | ||
600 | fid->pending_open = open; | ||
601 | list_add_tail(&open->olist, &tlink_tcon(tlink)->pending_opens); | ||
602 | } | ||
603 | |||
604 | void | ||
605 | cifs_add_pending_open(struct cifs_fid *fid, struct tcon_link *tlink, | ||
606 | struct cifs_pending_open *open) | ||
607 | { | ||
608 | spin_lock(&cifs_file_list_lock); | ||
609 | cifs_add_pending_open_locked(fid, tlink, open); | ||
610 | spin_unlock(&cifs_file_list_lock); | ||
611 | } | ||
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 | ||
392 | struct 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 | |||
399 | static void | ||
400 | cifs_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 | |||
392 | static bool | 413 | static bool |
393 | smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) | 414 | smb2_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 | } |