aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/cifs/cifsfs.c1
-rw-r--r--fs/cifs/cifsglob.h13
-rw-r--r--fs/cifs/file.c4
-rw-r--r--fs/cifs/smb2misc.c6
-rw-r--r--fs/cifs/smb2ops.c57
-rw-r--r--fs/cifs/smb2pdu.c7
6 files changed, 71 insertions, 17 deletions
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index ab88efe014a5..a16b4e58bcc6 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -255,6 +255,7 @@ cifs_alloc_inode(struct super_block *sb)
255 cifs_inode->server_eof = 0; 255 cifs_inode->server_eof = 0;
256 cifs_inode->uniqueid = 0; 256 cifs_inode->uniqueid = 0;
257 cifs_inode->createtime = 0; 257 cifs_inode->createtime = 0;
258 cifs_inode->epoch = 0;
258#ifdef CONFIG_CIFS_SMB2 259#ifdef CONFIG_CIFS_SMB2
259 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE); 260 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE);
260#endif 261#endif
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 38118938f0b6..cfa14c80ef3b 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -373,11 +373,12 @@ struct smb_version_operations {
373 /* if we can do cache read operations */ 373 /* if we can do cache read operations */
374 bool (*is_read_op)(__u32); 374 bool (*is_read_op)(__u32);
375 /* set oplock level for the inode */ 375 /* set oplock level for the inode */
376 void (*set_oplock_level)(struct cifsInodeInfo *, __u32); 376 void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int,
377 bool *);
377 /* create lease context buffer for CREATE request */ 378 /* create lease context buffer for CREATE request */
378 char * (*create_lease_buf)(u8 *, u8); 379 char * (*create_lease_buf)(u8 *, u8);
379 /* parse lease context buffer and return oplock info */ 380 /* parse lease context buffer and return oplock/epoch info */
380 __u8 (*parse_lease_buf)(void *); 381 __u8 (*parse_lease_buf)(void *, unsigned int *);
381}; 382};
382 383
383struct smb_version_values { 384struct smb_version_values {
@@ -940,6 +941,8 @@ struct cifs_fid {
940 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ 941 __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */
941#endif 942#endif
942 struct cifs_pending_open *pending_open; 943 struct cifs_pending_open *pending_open;
944 unsigned int epoch;
945 bool purge_cache;
943}; 946};
944 947
945struct cifs_fid_locks { 948struct cifs_fid_locks {
@@ -1039,7 +1042,10 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file);
1039 1042
1040#define CIFS_CACHE_READ_FLG 1 1043#define CIFS_CACHE_READ_FLG 1
1041#define CIFS_CACHE_HANDLE_FLG 2 1044#define CIFS_CACHE_HANDLE_FLG 2
1045#define CIFS_CACHE_RH_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_HANDLE_FLG)
1042#define CIFS_CACHE_WRITE_FLG 4 1046#define CIFS_CACHE_WRITE_FLG 4
1047#define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG)
1048#define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG)
1043 1049
1044#define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG) 1050#define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG)
1045#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) 1051#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG)
@@ -1057,6 +1063,7 @@ struct cifsInodeInfo {
1057 struct list_head openFileList; 1063 struct list_head openFileList;
1058 __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ 1064 __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */
1059 unsigned int oplock; /* oplock/lease level we have */ 1065 unsigned int oplock; /* oplock/lease level we have */
1066 unsigned int epoch; /* used to track lease state changes */
1060 bool delete_pending; /* DELETE_ON_CLOSE is set */ 1067 bool delete_pending; /* DELETE_ON_CLOSE is set */
1061 bool invalid_mapping; /* pagecache is invalid */ 1068 bool invalid_mapping; /* pagecache is invalid */
1062 unsigned long time; /* jiffies of last update of inode */ 1069 unsigned long time; /* jiffies of last update of inode */
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 188b2470b1fb..d044b35ce228 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -323,6 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
323 oplock = fid->pending_open->oplock; 323 oplock = fid->pending_open->oplock;
324 list_del(&fid->pending_open->olist); 324 list_del(&fid->pending_open->olist);
325 325
326 fid->purge_cache = false;
326 server->ops->set_fid(cfile, fid, oplock); 327 server->ops->set_fid(cfile, fid, oplock);
327 328
328 list_add(&cfile->tlist, &tcon->openFileList); 329 list_add(&cfile->tlist, &tcon->openFileList);
@@ -333,6 +334,9 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file,
333 list_add_tail(&cfile->flist, &cinode->openFileList); 334 list_add_tail(&cfile->flist, &cinode->openFileList);
334 spin_unlock(&cifs_file_list_lock); 335 spin_unlock(&cifs_file_list_lock);
335 336
337 if (fid->purge_cache)
338 cifs_invalidate_mapping(inode);
339
336 file->private_data = cfile; 340 file->private_data = cfile;
337 return cfile; 341 return cfile;
338} 342}
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 4aa59b34ec23..fb3966265b6e 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -420,6 +420,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
420 __u8 lease_state; 420 __u8 lease_state;
421 struct list_head *tmp; 421 struct list_head *tmp;
422 struct cifsFileInfo *cfile; 422 struct cifsFileInfo *cfile;
423 struct TCP_Server_Info *server = tcon->ses->server;
423 struct cifs_pending_open *open; 424 struct cifs_pending_open *open;
424 struct cifsInodeInfo *cinode; 425 struct cifsInodeInfo *cinode;
425 int ack_req = le32_to_cpu(rsp->Flags & 426 int ack_req = le32_to_cpu(rsp->Flags &
@@ -439,7 +440,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp,
439 cifs_dbg(FYI, "lease key match, lease break 0x%d\n", 440 cifs_dbg(FYI, "lease key match, lease break 0x%d\n",
440 le32_to_cpu(rsp->NewLeaseState)); 441 le32_to_cpu(rsp->NewLeaseState));
441 442
442 tcon->ses->server->ops->set_oplock_level(cinode, lease_state); 443 server->ops->set_oplock_level(cinode, lease_state, 0, NULL);
443 444
444 if (ack_req) 445 if (ack_req)
445 cfile->oplock_break_cancelled = false; 446 cfile->oplock_break_cancelled = false;
@@ -575,7 +576,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server)
575 cfile->oplock_break_cancelled = false; 576 cfile->oplock_break_cancelled = false;
576 577
577 server->ops->set_oplock_level(cinode, 578 server->ops->set_oplock_level(cinode,
578 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0); 579 rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0,
580 0, NULL);
579 581
580 queue_work(cifsiod_wq, &cfile->oplock_break); 582 queue_work(cifsiod_wq, &cfile->oplock_break);
581 583
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index a9256bd374f8..861b33214144 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -381,7 +381,8 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock)
381 381
382 cfile->fid.persistent_fid = fid->persistent_fid; 382 cfile->fid.persistent_fid = fid->persistent_fid;
383 cfile->fid.volatile_fid = fid->volatile_fid; 383 cfile->fid.volatile_fid = fid->volatile_fid;
384 server->ops->set_oplock_level(cinode, oplock); 384 server->ops->set_oplock_level(cinode, oplock, fid->epoch,
385 &fid->purge_cache);
385 cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); 386 cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode);
386} 387}
387 388
@@ -651,18 +652,18 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
651} 652}
652 653
653static void 654static void
654smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) 655smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
656 unsigned int epoch, bool *purge_cache)
655{ 657{
656 oplock &= 0xFF; 658 oplock &= 0xFF;
657 if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) 659 if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE)
658 return; 660 return;
659 if (oplock == SMB2_OPLOCK_LEVEL_BATCH) { 661 if (oplock == SMB2_OPLOCK_LEVEL_BATCH) {
660 cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG | 662 cinode->oplock = CIFS_CACHE_RHW_FLG;
661 CIFS_CACHE_HANDLE_FLG;
662 cifs_dbg(FYI, "Batch Oplock granted on inode %p\n", 663 cifs_dbg(FYI, "Batch Oplock granted on inode %p\n",
663 &cinode->vfs_inode); 664 &cinode->vfs_inode);
664 } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { 665 } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) {
665 cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG; 666 cinode->oplock = CIFS_CACHE_RW_FLG;
666 cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", 667 cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n",
667 &cinode->vfs_inode); 668 &cinode->vfs_inode);
668 } else if (oplock == SMB2_OPLOCK_LEVEL_II) { 669 } else if (oplock == SMB2_OPLOCK_LEVEL_II) {
@@ -674,7 +675,8 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
674} 675}
675 676
676static void 677static void
677smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) 678smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
679 unsigned int epoch, bool *purge_cache)
678{ 680{
679 char message[5] = {0}; 681 char message[5] = {0};
680 682
@@ -701,6 +703,41 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock)
701 &cinode->vfs_inode); 703 &cinode->vfs_inode);
702} 704}
703 705
706static void
707smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock,
708 unsigned int epoch, bool *purge_cache)
709{
710 unsigned int old_oplock = cinode->oplock;
711
712 smb21_set_oplock_level(cinode, oplock, epoch, purge_cache);
713
714 if (purge_cache) {
715 *purge_cache = false;
716 if (old_oplock == CIFS_CACHE_READ_FLG) {
717 if (cinode->oplock == CIFS_CACHE_READ_FLG &&
718 (epoch - cinode->epoch > 0))
719 *purge_cache = true;
720 else if (cinode->oplock == CIFS_CACHE_RH_FLG &&
721 (epoch - cinode->epoch > 1))
722 *purge_cache = true;
723 else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
724 (epoch - cinode->epoch > 1))
725 *purge_cache = true;
726 else if (cinode->oplock == 0 &&
727 (epoch - cinode->epoch > 0))
728 *purge_cache = true;
729 } else if (old_oplock == CIFS_CACHE_RH_FLG) {
730 if (cinode->oplock == CIFS_CACHE_RH_FLG &&
731 (epoch - cinode->epoch > 0))
732 *purge_cache = true;
733 else if (cinode->oplock == CIFS_CACHE_RHW_FLG &&
734 (epoch - cinode->epoch > 1))
735 *purge_cache = true;
736 }
737 cinode->epoch = epoch;
738 }
739}
740
704static bool 741static bool
705smb2_is_read_op(__u32 oplock) 742smb2_is_read_op(__u32 oplock)
706{ 743{
@@ -780,20 +817,22 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock)
780} 817}
781 818
782static __u8 819static __u8
783smb2_parse_lease_buf(void *buf) 820smb2_parse_lease_buf(void *buf, unsigned int *epoch)
784{ 821{
785 struct create_lease *lc = (struct create_lease *)buf; 822 struct create_lease *lc = (struct create_lease *)buf;
786 823
824 *epoch = 0; /* not used */
787 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) 825 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
788 return SMB2_OPLOCK_LEVEL_NOCHANGE; 826 return SMB2_OPLOCK_LEVEL_NOCHANGE;
789 return le32_to_cpu(lc->lcontext.LeaseState); 827 return le32_to_cpu(lc->lcontext.LeaseState);
790} 828}
791 829
792static __u8 830static __u8
793smb3_parse_lease_buf(void *buf) 831smb3_parse_lease_buf(void *buf, unsigned int *epoch)
794{ 832{
795 struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; 833 struct create_lease_v2 *lc = (struct create_lease_v2 *)buf;
796 834
835 *epoch = le16_to_cpu(lc->lcontext.Epoch);
797 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) 836 if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS)
798 return SMB2_OPLOCK_LEVEL_NOCHANGE; 837 return SMB2_OPLOCK_LEVEL_NOCHANGE;
799 return le32_to_cpu(lc->lcontext.LeaseState); 838 return le32_to_cpu(lc->lcontext.LeaseState);
@@ -1009,7 +1048,7 @@ struct smb_version_operations smb30_operations = {
1009 .generate_signingkey = generate_smb3signingkey, 1048 .generate_signingkey = generate_smb3signingkey,
1010 .calc_signature = smb3_calc_signature, 1049 .calc_signature = smb3_calc_signature,
1011 .is_read_op = smb21_is_read_op, 1050 .is_read_op = smb21_is_read_op,
1012 .set_oplock_level = smb21_set_oplock_level, 1051 .set_oplock_level = smb3_set_oplock_level,
1013 .create_lease_buf = smb3_create_lease_buf, 1052 .create_lease_buf = smb3_create_lease_buf,
1014 .parse_lease_buf = smb3_parse_lease_buf, 1053 .parse_lease_buf = smb3_parse_lease_buf,
1015}; 1054};
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 6eef8b67e709..eba0efde66d7 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -903,7 +903,8 @@ create_reconnect_durable_buf(struct cifs_fid *fid)
903} 903}
904 904
905static __u8 905static __u8
906parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp) 906parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp,
907 unsigned int *epoch)
907{ 908{
908 char *data_offset; 909 char *data_offset;
909 struct create_context *cc; 910 struct create_context *cc;
@@ -920,7 +921,7 @@ parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp)
920 next = le32_to_cpu(cc->Next); 921 next = le32_to_cpu(cc->Next);
921 continue; 922 continue;
922 } 923 }
923 return server->ops->parse_lease_buf(cc); 924 return server->ops->parse_lease_buf(cc, epoch);
924 } while (next != 0); 925 } while (next != 0);
925 926
926 return 0; 927 return 0;
@@ -1102,7 +1103,7 @@ SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *path,
1102 } 1103 }
1103 1104
1104 if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE) 1105 if (rsp->OplockLevel == SMB2_OPLOCK_LEVEL_LEASE)
1105 *oplock = parse_lease_state(server, rsp); 1106 *oplock = parse_lease_state(server, rsp, &oparms->fid->epoch);
1106 else 1107 else
1107 *oplock = rsp->OplockLevel; 1108 *oplock = rsp->OplockLevel;
1108creat_exit: 1109creat_exit: