aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsglob.h12
-rw-r--r--fs/cifs/cifsproto.h7
-rw-r--r--fs/cifs/connect.c1
-rw-r--r--fs/cifs/dir.c9
-rw-r--r--fs/cifs/file.c35
-rw-r--r--fs/cifs/misc.c30
-rw-r--r--fs/cifs/smb2misc.c74
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 */
864extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb); 866extern struct cifs_tcon *cifs_sb_master_tcon(struct cifs_sb_info *cifs_sb);
865 867
868#define CIFS_OPLOCK_NO_CHANGE 0xfe
869
870struct 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
908struct cifs_fid_locks { 920struct 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);
187extern void cifs_add_pending_open(struct cifs_fid *fid,
188 struct tcon_link *tlink,
189 struct cifs_pending_open *open);
190extern void cifs_add_pending_open_locked(struct cifs_fid *fid,
191 struct tcon_link *tlink,
192 struct cifs_pending_open *open);
193extern 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)
189extern void cifs_dfs_release_automount_timer(void); 196extern 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
370int cifs_open(struct inode *inode, struct file *file) 387int 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
583void
584cifs_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
591void
592cifs_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
604void
605cifs_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
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}