diff options
-rw-r--r-- | fs/cifs/cifsfs.c | 1 | ||||
-rw-r--r-- | fs/cifs/cifsglob.h | 13 | ||||
-rw-r--r-- | fs/cifs/file.c | 4 | ||||
-rw-r--r-- | fs/cifs/smb2misc.c | 6 | ||||
-rw-r--r-- | fs/cifs/smb2ops.c | 57 | ||||
-rw-r--r-- | fs/cifs/smb2pdu.c | 7 |
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 | ||
383 | struct smb_version_values { | 384 | struct 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 | ||
945 | struct cifs_fid_locks { | 948 | struct 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 | ||
653 | static void | 654 | static void |
654 | smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | 655 | smb2_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 | ||
676 | static void | 677 | static void |
677 | smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) | 678 | smb21_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 | ||
706 | static void | ||
707 | smb3_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 | |||
704 | static bool | 741 | static bool |
705 | smb2_is_read_op(__u32 oplock) | 742 | smb2_is_read_op(__u32 oplock) |
706 | { | 743 | { |
@@ -780,20 +817,22 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock) | |||
780 | } | 817 | } |
781 | 818 | ||
782 | static __u8 | 819 | static __u8 |
783 | smb2_parse_lease_buf(void *buf) | 820 | smb2_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 | ||
792 | static __u8 | 830 | static __u8 |
793 | smb3_parse_lease_buf(void *buf) | 831 | smb3_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 | ||
905 | static __u8 | 905 | static __u8 |
906 | parse_lease_state(struct TCP_Server_Info *server, struct smb2_create_rsp *rsp) | 906 | parse_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; |
1108 | creat_exit: | 1109 | creat_exit: |