Loading fs/cifs/cifsfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,7 @@ cifs_alloc_inode(struct super_block *sb) cifs_inode->server_eof = 0; cifs_inode->uniqueid = 0; cifs_inode->createtime = 0; cifs_inode->epoch = 0; #ifdef CONFIG_CIFS_SMB2 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE); #endif Loading fs/cifs/cifsglob.h +10 −3 Original line number Diff line number Diff line Loading @@ -373,11 +373,12 @@ struct smb_version_operations { /* if we can do cache read operations */ bool (*is_read_op)(__u32); /* set oplock level for the inode */ void (*set_oplock_level)(struct cifsInodeInfo *, __u32); void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int, bool *); /* create lease context buffer for CREATE request */ char * (*create_lease_buf)(u8 *, u8); /* parse lease context buffer and return oplock info */ __u8 (*parse_lease_buf)(void *); /* parse lease context buffer and return oplock/epoch info */ __u8 (*parse_lease_buf)(void *, unsigned int *); }; struct smb_version_values { Loading Loading @@ -940,6 +941,8 @@ struct cifs_fid { __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ #endif struct cifs_pending_open *pending_open; unsigned int epoch; bool purge_cache; }; struct cifs_fid_locks { Loading Loading @@ -1039,7 +1042,10 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); #define CIFS_CACHE_READ_FLG 1 #define CIFS_CACHE_HANDLE_FLG 2 #define CIFS_CACHE_RH_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_HANDLE_FLG) #define CIFS_CACHE_WRITE_FLG 4 #define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG) #define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG) #define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG) #define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) Loading @@ -1057,6 +1063,7 @@ struct cifsInodeInfo { struct list_head openFileList; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ unsigned int oplock; /* oplock/lease level we have */ unsigned int epoch; /* used to track lease state changes */ bool delete_pending; /* DELETE_ON_CLOSE is set */ bool invalid_mapping; /* pagecache is invalid */ unsigned long time; /* jiffies of last update of inode */ Loading fs/cifs/file.c +4 −0 Original line number Diff line number Diff line Loading @@ -323,6 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, oplock = fid->pending_open->oplock; list_del(&fid->pending_open->olist); fid->purge_cache = false; server->ops->set_fid(cfile, fid, oplock); list_add(&cfile->tlist, &tcon->openFileList); Loading @@ -333,6 +334,9 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, list_add_tail(&cfile->flist, &cinode->openFileList); spin_unlock(&cifs_file_list_lock); if (fid->purge_cache) cifs_invalidate_mapping(inode); file->private_data = cfile; return cfile; } Loading fs/cifs/smb2misc.c +4 −2 Original line number Diff line number Diff line Loading @@ -420,6 +420,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, __u8 lease_state; struct list_head *tmp; struct cifsFileInfo *cfile; struct TCP_Server_Info *server = tcon->ses->server; struct cifs_pending_open *open; struct cifsInodeInfo *cinode; int ack_req = le32_to_cpu(rsp->Flags & Loading @@ -439,7 +440,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, cifs_dbg(FYI, "lease key match, lease break 0x%d\n", le32_to_cpu(rsp->NewLeaseState)); tcon->ses->server->ops->set_oplock_level(cinode, lease_state); server->ops->set_oplock_level(cinode, lease_state, 0, NULL); if (ack_req) cfile->oplock_break_cancelled = false; Loading Loading @@ -575,7 +576,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cfile->oplock_break_cancelled = false; server->ops->set_oplock_level(cinode, rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0); rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0, 0, NULL); queue_work(cifsiod_wq, &cfile->oplock_break); Loading fs/cifs/smb2ops.c +48 −9 Original line number Diff line number Diff line Loading @@ -381,7 +381,8 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) cfile->fid.persistent_fid = fid->persistent_fid; cfile->fid.volatile_fid = fid->volatile_fid; server->ops->set_oplock_level(cinode, oplock); server->ops->set_oplock_level(cinode, oplock, fid->epoch, &fid->purge_cache); cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); } Loading Loading @@ -651,18 +652,18 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, } static void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { oplock &= 0xFF; if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) return; if (oplock == SMB2_OPLOCK_LEVEL_BATCH) { cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG | CIFS_CACHE_HANDLE_FLG; cinode->oplock = CIFS_CACHE_RHW_FLG; cifs_dbg(FYI, "Batch Oplock granted on inode %p\n", &cinode->vfs_inode); } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG; cinode->oplock = CIFS_CACHE_RW_FLG; cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", &cinode->vfs_inode); } else if (oplock == SMB2_OPLOCK_LEVEL_II) { Loading @@ -674,7 +675,8 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) } static void smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { char message[5] = {0}; Loading @@ -701,6 +703,41 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) &cinode->vfs_inode); } static void smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { unsigned int old_oplock = cinode->oplock; smb21_set_oplock_level(cinode, oplock, epoch, purge_cache); if (purge_cache) { *purge_cache = false; if (old_oplock == CIFS_CACHE_READ_FLG) { if (cinode->oplock == CIFS_CACHE_READ_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; else if (cinode->oplock == 0 && (epoch - cinode->epoch > 0)) *purge_cache = true; } else if (old_oplock == CIFS_CACHE_RH_FLG) { if (cinode->oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; } cinode->epoch = epoch; } } static bool smb2_is_read_op(__u32 oplock) { Loading Loading @@ -780,20 +817,22 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock) } static __u8 smb2_parse_lease_buf(void *buf) smb2_parse_lease_buf(void *buf, unsigned int *epoch) { struct create_lease *lc = (struct create_lease *)buf; *epoch = 0; /* not used */ if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) return SMB2_OPLOCK_LEVEL_NOCHANGE; return le32_to_cpu(lc->lcontext.LeaseState); } static __u8 smb3_parse_lease_buf(void *buf) smb3_parse_lease_buf(void *buf, unsigned int *epoch) { struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; *epoch = le16_to_cpu(lc->lcontext.Epoch); if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) return SMB2_OPLOCK_LEVEL_NOCHANGE; return le32_to_cpu(lc->lcontext.LeaseState); Loading Loading @@ -1009,7 +1048,7 @@ struct smb_version_operations smb30_operations = { .generate_signingkey = generate_smb3signingkey, .calc_signature = smb3_calc_signature, .is_read_op = smb21_is_read_op, .set_oplock_level = smb21_set_oplock_level, .set_oplock_level = smb3_set_oplock_level, .create_lease_buf = smb3_create_lease_buf, .parse_lease_buf = smb3_parse_lease_buf, }; Loading Loading
fs/cifs/cifsfs.c +1 −0 Original line number Diff line number Diff line Loading @@ -255,6 +255,7 @@ cifs_alloc_inode(struct super_block *sb) cifs_inode->server_eof = 0; cifs_inode->uniqueid = 0; cifs_inode->createtime = 0; cifs_inode->epoch = 0; #ifdef CONFIG_CIFS_SMB2 get_random_bytes(cifs_inode->lease_key, SMB2_LEASE_KEY_SIZE); #endif Loading
fs/cifs/cifsglob.h +10 −3 Original line number Diff line number Diff line Loading @@ -373,11 +373,12 @@ struct smb_version_operations { /* if we can do cache read operations */ bool (*is_read_op)(__u32); /* set oplock level for the inode */ void (*set_oplock_level)(struct cifsInodeInfo *, __u32); void (*set_oplock_level)(struct cifsInodeInfo *, __u32, unsigned int, bool *); /* create lease context buffer for CREATE request */ char * (*create_lease_buf)(u8 *, u8); /* parse lease context buffer and return oplock info */ __u8 (*parse_lease_buf)(void *); /* parse lease context buffer and return oplock/epoch info */ __u8 (*parse_lease_buf)(void *, unsigned int *); }; struct smb_version_values { Loading Loading @@ -940,6 +941,8 @@ struct cifs_fid { __u8 lease_key[SMB2_LEASE_KEY_SIZE]; /* lease key for smb2 */ #endif struct cifs_pending_open *pending_open; unsigned int epoch; bool purge_cache; }; struct cifs_fid_locks { Loading Loading @@ -1039,7 +1042,10 @@ void cifsFileInfo_put(struct cifsFileInfo *cifs_file); #define CIFS_CACHE_READ_FLG 1 #define CIFS_CACHE_HANDLE_FLG 2 #define CIFS_CACHE_RH_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_HANDLE_FLG) #define CIFS_CACHE_WRITE_FLG 4 #define CIFS_CACHE_RW_FLG (CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG) #define CIFS_CACHE_RHW_FLG (CIFS_CACHE_RW_FLG | CIFS_CACHE_HANDLE_FLG) #define CIFS_CACHE_READ(cinode) (cinode->oplock & CIFS_CACHE_READ_FLG) #define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) Loading @@ -1057,6 +1063,7 @@ struct cifsInodeInfo { struct list_head openFileList; __u32 cifsAttrs; /* e.g. DOS archive bit, sparse, compressed, system */ unsigned int oplock; /* oplock/lease level we have */ unsigned int epoch; /* used to track lease state changes */ bool delete_pending; /* DELETE_ON_CLOSE is set */ bool invalid_mapping; /* pagecache is invalid */ unsigned long time; /* jiffies of last update of inode */ Loading
fs/cifs/file.c +4 −0 Original line number Diff line number Diff line Loading @@ -323,6 +323,7 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, oplock = fid->pending_open->oplock; list_del(&fid->pending_open->olist); fid->purge_cache = false; server->ops->set_fid(cfile, fid, oplock); list_add(&cfile->tlist, &tcon->openFileList); Loading @@ -333,6 +334,9 @@ cifs_new_fileinfo(struct cifs_fid *fid, struct file *file, list_add_tail(&cfile->flist, &cinode->openFileList); spin_unlock(&cifs_file_list_lock); if (fid->purge_cache) cifs_invalidate_mapping(inode); file->private_data = cfile; return cfile; } Loading
fs/cifs/smb2misc.c +4 −2 Original line number Diff line number Diff line Loading @@ -420,6 +420,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, __u8 lease_state; struct list_head *tmp; struct cifsFileInfo *cfile; struct TCP_Server_Info *server = tcon->ses->server; struct cifs_pending_open *open; struct cifsInodeInfo *cinode; int ack_req = le32_to_cpu(rsp->Flags & Loading @@ -439,7 +440,7 @@ smb2_tcon_has_lease(struct cifs_tcon *tcon, struct smb2_lease_break *rsp, cifs_dbg(FYI, "lease key match, lease break 0x%d\n", le32_to_cpu(rsp->NewLeaseState)); tcon->ses->server->ops->set_oplock_level(cinode, lease_state); server->ops->set_oplock_level(cinode, lease_state, 0, NULL); if (ack_req) cfile->oplock_break_cancelled = false; Loading Loading @@ -575,7 +576,8 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) cfile->oplock_break_cancelled = false; server->ops->set_oplock_level(cinode, rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0); rsp->OplockLevel ? SMB2_OPLOCK_LEVEL_II : 0, 0, NULL); queue_work(cifsiod_wq, &cfile->oplock_break); Loading
fs/cifs/smb2ops.c +48 −9 Original line number Diff line number Diff line Loading @@ -381,7 +381,8 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) cfile->fid.persistent_fid = fid->persistent_fid; cfile->fid.volatile_fid = fid->volatile_fid; server->ops->set_oplock_level(cinode, oplock); server->ops->set_oplock_level(cinode, oplock, fid->epoch, &fid->purge_cache); cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); } Loading Loading @@ -651,18 +652,18 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon, } static void smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { oplock &= 0xFF; if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) return; if (oplock == SMB2_OPLOCK_LEVEL_BATCH) { cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG | CIFS_CACHE_HANDLE_FLG; cinode->oplock = CIFS_CACHE_RHW_FLG; cifs_dbg(FYI, "Batch Oplock granted on inode %p\n", &cinode->vfs_inode); } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { cinode->oplock = CIFS_CACHE_READ_FLG | CIFS_CACHE_WRITE_FLG; cinode->oplock = CIFS_CACHE_RW_FLG; cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", &cinode->vfs_inode); } else if (oplock == SMB2_OPLOCK_LEVEL_II) { Loading @@ -674,7 +675,8 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) } static void smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { char message[5] = {0}; Loading @@ -701,6 +703,41 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock) &cinode->vfs_inode); } static void smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, unsigned int epoch, bool *purge_cache) { unsigned int old_oplock = cinode->oplock; smb21_set_oplock_level(cinode, oplock, epoch, purge_cache); if (purge_cache) { *purge_cache = false; if (old_oplock == CIFS_CACHE_READ_FLG) { if (cinode->oplock == CIFS_CACHE_READ_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; else if (cinode->oplock == 0 && (epoch - cinode->epoch > 0)) *purge_cache = true; } else if (old_oplock == CIFS_CACHE_RH_FLG) { if (cinode->oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; else if (cinode->oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; } cinode->epoch = epoch; } } static bool smb2_is_read_op(__u32 oplock) { Loading Loading @@ -780,20 +817,22 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock) } static __u8 smb2_parse_lease_buf(void *buf) smb2_parse_lease_buf(void *buf, unsigned int *epoch) { struct create_lease *lc = (struct create_lease *)buf; *epoch = 0; /* not used */ if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) return SMB2_OPLOCK_LEVEL_NOCHANGE; return le32_to_cpu(lc->lcontext.LeaseState); } static __u8 smb3_parse_lease_buf(void *buf) smb3_parse_lease_buf(void *buf, unsigned int *epoch) { struct create_lease_v2 *lc = (struct create_lease_v2 *)buf; *epoch = le16_to_cpu(lc->lcontext.Epoch); if (lc->lcontext.LeaseFlags & SMB2_LEASE_FLAG_BREAK_IN_PROGRESS) return SMB2_OPLOCK_LEVEL_NOCHANGE; return le32_to_cpu(lc->lcontext.LeaseState); Loading Loading @@ -1009,7 +1048,7 @@ struct smb_version_operations smb30_operations = { .generate_signingkey = generate_smb3signingkey, .calc_signature = smb3_calc_signature, .is_read_op = smb21_is_read_op, .set_oplock_level = smb21_set_oplock_level, .set_oplock_level = smb3_set_oplock_level, .create_lease_buf = smb3_create_lease_buf, .parse_lease_buf = smb3_parse_lease_buf, }; Loading