diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 121821e6c872..e320d39b01f5 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -147,6 +147,6 @@ extern const struct export_operations cifs_export_ops; #endif /* CONFIG_CIFS_NFSD_EXPORT */ /* when changing internal version - update following two lines at same time */ -#define SMB3_PRODUCT_BUILD 58 -#define CIFS_VERSION "2.58" +#define SMB3_PRODUCT_BUILD 59 +#define CIFS_VERSION "2.59" #endif /* _CIFSFS_H */ diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 7eb0131963dd..080ea601c209 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -515,8 +515,10 @@ struct smb_version_operations { /* check for STATUS_NETWORK_SESSION_EXPIRED */ bool (*is_session_expired)(char *); /* send oplock break response */ - int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid, __u64 volatile_fid, - __u16 net_fid, struct cifsInodeInfo *cifs_inode); + int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid, + __u64 volatile_fid, __u16 net_fid, + struct cifsInodeInfo *cifs_inode, + unsigned int oplock); /* query remote filesystem */ int (*queryfs)(const unsigned int, struct cifs_tcon *, const char *, struct cifs_sb_info *, struct kstatfs *); @@ -1531,10 +1533,6 @@ int cifs_file_set_size(const unsigned int xid, struct dentry *dentry, #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) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RO_CACHE)) -#define CIFS_CACHE_HANDLE(cinode) (cinode->oplock & CIFS_CACHE_HANDLE_FLG) -#define CIFS_CACHE_WRITE(cinode) ((cinode->oplock & CIFS_CACHE_WRITE_FLG) || (CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags & CIFS_MOUNT_RW_CACHE)) - /* * One of these for each file inode */ @@ -2312,4 +2310,30 @@ static inline void cifs_requeue_server_reconn(struct TCP_Server_Info *server) queue_delayed_work(cifsiod_wq, &server->reconnect, delay * HZ); } +static inline bool __cifs_cache_state_check(struct cifsInodeInfo *cinode, + unsigned int oplock_flags, + unsigned int sb_flags) +{ + struct cifs_sb_info *cifs_sb = CIFS_SB(cinode->netfs.inode.i_sb); + unsigned int oplock = READ_ONCE(cinode->oplock); + unsigned int sflags = cifs_sb->mnt_cifs_flags; + + return (oplock & oplock_flags) || (sflags & sb_flags); +} + +#define CIFS_CACHE_READ(cinode) \ + __cifs_cache_state_check(cinode, CIFS_CACHE_READ_FLG, \ + CIFS_MOUNT_RO_CACHE) +#define CIFS_CACHE_HANDLE(cinode) \ + __cifs_cache_state_check(cinode, CIFS_CACHE_HANDLE_FLG, 0) +#define CIFS_CACHE_WRITE(cinode) \ + __cifs_cache_state_check(cinode, CIFS_CACHE_WRITE_FLG, \ + CIFS_MOUNT_RW_CACHE) + +static inline void cifs_reset_oplock(struct cifsInodeInfo *cinode) +{ + scoped_guard(spinlock, &cinode->open_file_lock) + WRITE_ONCE(cinode->oplock, 0); +} + #endif /* _CIFS_GLOB_H */ diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index 51360d64b7b2..88273f82812b 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -731,14 +731,14 @@ struct cifsFileInfo *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); atomic_inc(&tcon->num_local_opens); /* if readable file instance put first in list*/ spin_lock(&cinode->open_file_lock); + fid->purge_cache = false; + server->ops->set_fid(cfile, fid, oplock); + if (file->f_mode & FMODE_READ) list_add(&cfile->flist, &cinode->openFileList); else @@ -1410,7 +1410,8 @@ reopen_success: oplock = 0; } - server->ops->set_fid(cfile, &cfile->fid, oplock); + scoped_guard(spinlock, &cinode->open_file_lock) + server->ops->set_fid(cfile, &cfile->fid, oplock); if (oparms.reconnect) cifs_relock_file(cfile); @@ -1437,11 +1438,11 @@ smb2_can_defer_close(struct inode *inode, struct cifs_deferred_close *dclose) { struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifsInodeInfo *cinode = CIFS_I(inode); + unsigned int oplock = READ_ONCE(cinode->oplock); - return (cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose && - (cinode->oplock == CIFS_CACHE_RHW_FLG || - cinode->oplock == CIFS_CACHE_RH_FLG) && - !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags)); + return cifs_sb->ctx->closetimeo && cinode->lease_granted && dclose && + (oplock == CIFS_CACHE_RHW_FLG || oplock == CIFS_CACHE_RH_FLG) && + !test_bit(CIFS_INO_CLOSE_ON_LOCK, &cinode->flags); } @@ -2371,7 +2372,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, cifs_zap_mapping(inode); cifs_dbg(FYI, "Set no oplock for inode=%p due to mand locks\n", inode); - CIFS_I(inode)->oplock = 0; + cifs_reset_oplock(CIFS_I(inode)); } rc = server->ops->mand_lock(xid, cfile, flock->fl_start, length, @@ -2930,7 +2931,7 @@ cifs_strict_writev(struct kiocb *iocb, struct iov_iter *from) cifs_zap_mapping(inode); cifs_dbg(FYI, "Set Oplock/Lease to NONE for inode=%p after write\n", inode); - cinode->oplock = 0; + cifs_reset_oplock(cinode); } out: cifs_put_writer(cinode); @@ -2966,7 +2967,7 @@ ssize_t cifs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) cifs_dbg(FYI, "Set no oplock for inode=%p after a write operation\n", inode); - cinode->oplock = 0; + cifs_reset_oplock(cinode); } return written; } @@ -3154,9 +3155,11 @@ void cifs_oplock_break(struct work_struct *work) struct super_block *sb = inode->i_sb; struct cifs_sb_info *cifs_sb = CIFS_SB(sb); struct cifsInodeInfo *cinode = CIFS_I(inode); + bool cache_read, cache_write, cache_handle; struct cifs_tcon *tcon; struct TCP_Server_Info *server; struct tcon_link *tlink; + unsigned int oplock; int rc = 0; bool purge_cache = false, oplock_break_cancelled; __u64 persistent_fid, volatile_fid; @@ -3177,29 +3180,40 @@ void cifs_oplock_break(struct work_struct *work) tcon = tlink_tcon(tlink); server = tcon->ses->server; - server->ops->downgrade_oplock(server, cinode, cfile->oplock_level, - cfile->oplock_epoch, &purge_cache); + scoped_guard(spinlock, &cinode->open_file_lock) { + unsigned int sbflags = cifs_sb->mnt_cifs_flags; - if (!CIFS_CACHE_WRITE(cinode) && CIFS_CACHE_READ(cinode) && - cifs_has_mand_locks(cinode)) { + server->ops->downgrade_oplock(server, cinode, cfile->oplock_level, + cfile->oplock_epoch, &purge_cache); + oplock = READ_ONCE(cinode->oplock); + cache_read = (oplock & CIFS_CACHE_READ_FLG) || + (sbflags & CIFS_MOUNT_RO_CACHE); + cache_write = (oplock & CIFS_CACHE_WRITE_FLG) || + (sbflags & CIFS_MOUNT_RW_CACHE); + cache_handle = oplock & CIFS_CACHE_HANDLE_FLG; + } + + if (!cache_write && cache_read && cifs_has_mand_locks(cinode)) { cifs_dbg(FYI, "Reset oplock to None for inode=%p due to mand locks\n", inode); - cinode->oplock = 0; + cifs_reset_oplock(cinode); + oplock = 0; + cache_read = cache_write = cache_handle = false; } if (S_ISREG(inode->i_mode)) { - if (CIFS_CACHE_READ(cinode)) + if (cache_read) break_lease(inode, O_RDONLY); else break_lease(inode, O_WRONLY); rc = filemap_fdatawrite(inode->i_mapping); - if (!CIFS_CACHE_READ(cinode) || purge_cache) { + if (!cache_read || purge_cache) { rc = filemap_fdatawait(inode->i_mapping); mapping_set_error(inode->i_mapping, rc); cifs_zap_mapping(inode); } cifs_dbg(FYI, "Oplock flush inode %p rc %d\n", inode, rc); - if (CIFS_CACHE_WRITE(cinode)) + if (cache_write) goto oplock_break_ack; } @@ -3214,7 +3228,7 @@ oplock_break_ack: * So, new open will not use cached handle. */ - if (!CIFS_CACHE_HANDLE(cinode) && !list_empty(&cinode->deferred_closes)) + if (!cache_handle && !list_empty(&cinode->deferred_closes)) cifs_close_deferred_file(cinode); persistent_fid = cfile->fid.persistent_fid; @@ -3232,7 +3246,8 @@ oplock_break_ack: if (!oplock_break_cancelled && !list_empty(&cinode->openFileList)) { spin_unlock(&cinode->open_file_lock); rc = server->ops->oplock_response(tcon, persistent_fid, - volatile_fid, net_fid, cinode); + volatile_fid, net_fid, + cinode, oplock); cifs_dbg(FYI, "Oplock release rc = %d\n", rc); } else spin_unlock(&cinode->open_file_lock); diff --git a/fs/smb/client/fs_context.c b/fs/smb/client/fs_context.c index ec84204aee18..412c5b534791 100644 --- a/fs/smb/client/fs_context.c +++ b/fs/smb/client/fs_context.c @@ -825,9 +825,7 @@ static int smb3_fs_context_parse_monolithic(struct fs_context *fc, if (ret < 0) break; } - ret = smb3_handle_conflicting_options(fc); - - return ret; + return ret ?: smb3_handle_conflicting_options(fc); } /* diff --git a/fs/smb/client/nterr.c b/fs/smb/client/nterr.c index ab5a2119efd0..279566cac435 100644 --- a/fs/smb/client/nterr.c +++ b/fs/smb/client/nterr.c @@ -14,6 +14,7 @@ const struct nt_err_code_struct nt_errs[] = { {"NT_STATUS_OK", NT_STATUS_OK}, {"NT_STATUS_PENDING", NT_STATUS_PENDING}, + {"NT_STATUS_NOTIFY_ENUM_DIR", NT_STATUS_NOTIFY_ENUM_DIR}, {"NT_STATUS_MEDIA_CHANGED", NT_STATUS_MEDIA_CHANGED}, {"NT_STATUS_END_OF_MEDIA", NT_STATUS_END_OF_MEDIA}, {"NT_STATUS_MEDIA_CHECK", NT_STATUS_MEDIA_CHECK}, @@ -694,7 +695,7 @@ const struct nt_err_code_struct nt_errs[] = { {"NT_STATUS_NETWORK_SESSION_EXPIRED", NT_STATUS_NETWORK_SESSION_EXPIRED}, {"NT_STATUS_NO_MORE_ENTRIES", NT_STATUS_NO_MORE_ENTRIES}, {"NT_STATUS_MORE_ENTRIES", NT_STATUS_MORE_ENTRIES}, - {"NT_STATUS_SOME_UNMAPPED", NT_STATUS_SOME_UNMAPPED}, + {"NT_STATUS_SOME_NOT_MAPPED", NT_STATUS_SOME_NOT_MAPPED}, {"NT_STATUS_NO_SUCH_JOB", NT_STATUS_NO_SUCH_JOB}, {"NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP", NT_STATUS_NO_PREAUTH_INTEGRITY_HASH_OVERLAP}, diff --git a/fs/smb/client/nterr.h b/fs/smb/client/nterr.h index b04cd0d786b1..9a4a450c6571 100644 --- a/fs/smb/client/nterr.h +++ b/fs/smb/client/nterr.h @@ -22,21 +22,21 @@ struct nt_err_code_struct { extern const struct nt_err_code_struct nt_errs[]; -/* Win32 Status codes. */ -#define NT_STATUS_MORE_ENTRIES 0x0105 +/* Win32 Error Codes. */ #define NT_ERROR_INVALID_PARAMETER 0x0057 #define NT_ERROR_INSUFFICIENT_BUFFER 0x007a -#define NT_STATUS_1804 0x070c -#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c +#define NT_ERROR_INVALID_DATATYPE 0x070c /* - * Win32 Error codes extracted using a loop in smbclient then printing a netmon + * NTSTATUS Values extracted using a loop in smbclient then printing a netmon * sniff to a file. */ #define NT_STATUS_OK 0x0000 #define NT_STATUS_PENDING 0x0103 -#define NT_STATUS_SOME_UNMAPPED 0x0107 +#define NT_STATUS_MORE_ENTRIES 0x0105 +#define NT_STATUS_SOME_NOT_MAPPED 0x0107 +#define NT_STATUS_NOTIFY_ENUM_DIR 0x010c #define NT_STATUS_BUFFER_OVERFLOW 0x80000005 #define NT_STATUS_NO_MORE_ENTRIES 0x8000001a #define NT_STATUS_MEDIA_CHANGED 0x8000001c diff --git a/fs/smb/client/smb1maperror.c b/fs/smb/client/smb1maperror.c index 277ef0865be0..e1964fd2b85e 100644 --- a/fs/smb/client/smb1maperror.c +++ b/fs/smb/client/smb1maperror.c @@ -112,6 +112,10 @@ static const struct { __u32 ntstatus; } ntstatus_to_dos_map[] = { { + ERRSRV, ERR_NOTIFY_ENUM_DIR, NT_STATUS_NOTIFY_ENUM_DIR}, { + ERRDOS, ERRmoredata, NT_STATUS_BUFFER_OVERFLOW}, { + ERRDOS, ERRmoredata, NT_STATUS_MORE_PROCESSING_REQUIRED}, { + ERRDOS, ERRnoaccess, NT_STATUS_PRIVILEGE_NOT_HELD}, { ERRDOS, ERRgeneral, NT_STATUS_UNSUCCESSFUL}, { ERRDOS, ERRbadfunc, NT_STATUS_NOT_IMPLEMENTED}, { ERRDOS, ERRbadpipe, NT_STATUS_INVALID_INFO_CLASS}, { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 9c3b97d2a20a..970aeffe936e 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -395,6 +395,7 @@ cifs_downgrade_oplock(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch, bool *purge_cache) { + lockdep_assert_held(&cinode->open_file_lock); cifs_set_oplock_level(cinode, oplock); } @@ -894,6 +895,9 @@ static void cifs_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) { struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); + + lockdep_assert_held(&cinode->open_file_lock); + cfile->fid.netfid = fid->netfid; cifs_set_oplock_level(cinode, oplock); cinode->can_cache_brlcks = CIFS_CACHE_WRITE(cinode); @@ -1139,12 +1143,16 @@ cifs_close_dir(const unsigned int xid, struct cifs_tcon *tcon, return CIFSFindClose(xid, tcon, fid->netfid); } -static int -cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, - __u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode) +static int cifs_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, + __u64 volatile_fid, __u16 net_fid, + struct cifsInodeInfo *cinode, unsigned int oplock) { + unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags; + __u8 op; + + op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE)); return CIFSSMBLock(0, tcon, net_fid, current->tgid, 0, 0, 0, 0, - LOCKING_ANDX_OPLOCK_RELEASE, false, CIFS_CACHE_READ(cinode) ? 1 : 0); + LOCKING_ANDX_OPLOCK_RELEASE, false, op); } static int diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 0b8b852cfc0d..38d6d5538b96 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -29,7 +29,6 @@ #include "cifs_debug.h" #include "smbdirect.h" #include "compress.h" -#include "cifs_debug.h" /* Max number of iovectors we can use off the stack when sending requests. */ #define CIFS_MAX_IOV_SIZE 8 @@ -170,12 +169,18 @@ cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, iov[0].iov_base = mid->resp_buf; iov[0].iov_len = len; - /* FIXME: add code to kill session */ + rc = cifs_verify_signature(&rqst, server, mid->sequence_number); - if (rc) + if (rc) { cifs_server_dbg(VFS, "SMB signature verification returned error = %d\n", rc); + + if (!(server->sec_mode & SECMODE_SIGN_REQUIRED)) { + cifs_reconnect(server, true); + return rc; + } + } } /* BB special case reconnect tid and uid here? */ diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 0871b9f1f86a..d1ae839e4863 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -484,16 +484,16 @@ cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb) return to; } -__le32 -smb2_get_lease_state(struct cifsInodeInfo *cinode) +__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock) { + unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags; __le32 lease = 0; - if (CIFS_CACHE_WRITE(cinode)) + if ((oplock & CIFS_CACHE_WRITE_FLG) || (sbflags & CIFS_MOUNT_RW_CACHE)) lease |= SMB2_LEASE_WRITE_CACHING_LE; - if (CIFS_CACHE_HANDLE(cinode)) + if (oplock & CIFS_CACHE_HANDLE_FLG) lease |= SMB2_LEASE_HANDLE_CACHING_LE; - if (CIFS_CACHE_READ(cinode)) + if ((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE)) lease |= SMB2_LEASE_READ_CACHING_LE; return lease; } diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 262df6d2c2c8..7370d7a18cd0 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -1185,6 +1185,7 @@ smb2_set_ea(const unsigned int xid, struct cifs_tcon *tcon, replay_again: /* reinitialize for possible replay */ + used_len = 0; flags = CIFS_CP_CREATE_CLOSE_OP; oplock = SMB2_OPLOCK_LEVEL_NONE; server = cifs_pick_channel(ses); @@ -1460,6 +1461,8 @@ smb2_set_fid(struct cifsFileInfo *cfile, struct cifs_fid *fid, __u32 oplock) struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); struct TCP_Server_Info *server = tlink_tcon(cfile->tlink)->ses->server; + lockdep_assert_held(&cinode->open_file_lock); + cfile->fid.persistent_fid = fid->persistent_fid; cfile->fid.volatile_fid = fid->volatile_fid; cfile->fid.access = fid->access; @@ -1586,6 +1589,7 @@ smb2_ioctl_query_info(const unsigned int xid, replay_again: /* reinitialize for possible replay */ + buffer = NULL; flags = CIFS_CP_CREATE_CLOSE_OP; oplock = SMB2_OPLOCK_LEVEL_NONE; server = cifs_pick_channel(ses); @@ -2684,16 +2688,19 @@ smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) return false; } -static int -smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, - __u64 volatile_fid, __u16 net_fid, struct cifsInodeInfo *cinode) +static int smb2_oplock_response(struct cifs_tcon *tcon, __u64 persistent_fid, + __u64 volatile_fid, __u16 net_fid, + struct cifsInodeInfo *cinode, unsigned int oplock) { + unsigned int sbflags = CIFS_SB(cinode->netfs.inode.i_sb)->mnt_cifs_flags; + __u8 op; + if (tcon->ses->server->capabilities & SMB2_GLOBAL_CAP_LEASING) return SMB2_lease_break(0, tcon, cinode->lease_key, - smb2_get_lease_state(cinode)); + smb2_get_lease_state(cinode, oplock)); - return SMB2_oplock_break(0, tcon, persistent_fid, volatile_fid, - CIFS_CACHE_READ(cinode) ? 1 : 0); + op = !!((oplock & CIFS_CACHE_READ_FLG) || (sbflags & CIFS_MOUNT_RO_CACHE)); + return SMB2_oplock_break(0, tcon, persistent_fid, volatile_fid, op); } void @@ -3176,8 +3183,6 @@ smb2_get_dfs_refer(const unsigned int xid, struct cifs_ses *ses, if (tcon && !tcon->ipc) { /* ipc tcons are not refcounted */ cifs_put_tcon(tcon, netfs_trace_tcon_ref_put_dfs_refer); - trace_smb3_tcon_ref(tcon->debug_id, tcon->tc_count, - netfs_trace_tcon_ref_dec_dfs_refer); } kfree(utf16_path); kfree(dfs_req); @@ -4053,6 +4058,7 @@ smb2_downgrade_oplock(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch, bool *purge_cache) { + lockdep_assert_held(&cinode->open_file_lock); server->ops->set_oplock_level(cinode, oplock, 0, NULL); } @@ -4093,19 +4099,19 @@ smb2_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, if (oplock == SMB2_OPLOCK_LEVEL_NOCHANGE) return; if (oplock == SMB2_OPLOCK_LEVEL_BATCH) { - cinode->oplock = CIFS_CACHE_RHW_FLG; + WRITE_ONCE(cinode->oplock, CIFS_CACHE_RHW_FLG); cifs_dbg(FYI, "Batch Oplock granted on inode %p\n", &cinode->netfs.inode); } else if (oplock == SMB2_OPLOCK_LEVEL_EXCLUSIVE) { - cinode->oplock = CIFS_CACHE_RW_FLG; + WRITE_ONCE(cinode->oplock, CIFS_CACHE_RW_FLG); cifs_dbg(FYI, "Exclusive Oplock granted on inode %p\n", &cinode->netfs.inode); } else if (oplock == SMB2_OPLOCK_LEVEL_II) { - cinode->oplock = CIFS_CACHE_READ_FLG; + WRITE_ONCE(cinode->oplock, CIFS_CACHE_READ_FLG); cifs_dbg(FYI, "Level II Oplock granted on inode %p\n", &cinode->netfs.inode); } else - cinode->oplock = 0; + WRITE_ONCE(cinode->oplock, 0); } static void @@ -4140,7 +4146,7 @@ smb21_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, if (!new_oplock) strscpy(message, "None"); - cinode->oplock = new_oplock; + WRITE_ONCE(cinode->oplock, new_oplock); cifs_dbg(FYI, "%s Lease granted on inode %p\n", message, &cinode->netfs.inode); } @@ -4149,30 +4155,32 @@ static void smb3_set_oplock_level(struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch, bool *purge_cache) { - unsigned int old_oplock = cinode->oplock; + unsigned int old_oplock = READ_ONCE(cinode->oplock); + unsigned int new_oplock; smb21_set_oplock_level(cinode, oplock, epoch, purge_cache); + new_oplock = READ_ONCE(cinode->oplock); if (purge_cache) { *purge_cache = false; if (old_oplock == CIFS_CACHE_READ_FLG) { - if (cinode->oplock == CIFS_CACHE_READ_FLG && + if (new_oplock == CIFS_CACHE_READ_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; - else if (cinode->oplock == CIFS_CACHE_RH_FLG && + else if (new_oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; - else if (cinode->oplock == CIFS_CACHE_RHW_FLG && + else if (new_oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; - else if (cinode->oplock == 0 && + else if (new_oplock == 0 && (epoch - cinode->epoch > 0)) *purge_cache = true; } else if (old_oplock == CIFS_CACHE_RH_FLG) { - if (cinode->oplock == CIFS_CACHE_RH_FLG && + if (new_oplock == CIFS_CACHE_RH_FLG && (epoch - cinode->epoch > 0)) *purge_cache = true; - else if (cinode->oplock == CIFS_CACHE_RHW_FLG && + else if (new_oplock == CIFS_CACHE_RHW_FLG && (epoch - cinode->epoch > 1)) *purge_cache = true; } diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 4602b4dfe832..7f3edf42b9c3 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2908,6 +2908,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode, replay_again: /* reinitialize for possible replay */ + pc_buf = NULL; flags = 0; n_iov = 2; server = cifs_pick_channel(ses); diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index c7759e37d975..881e42cf66ce 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -42,7 +42,7 @@ struct mid_q_entry *smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *rqst); struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid); -__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode); +__le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int oplock); bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server); int smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid); diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 191f02344dcd..9228f95cae2b 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -168,7 +168,6 @@ E_(cifs_trace_rw_credits_zero_in_flight, "ZERO-IN-FLT") #define smb3_tcon_ref_traces \ - EM(netfs_trace_tcon_ref_dec_dfs_refer, "DEC DfsRef") \ EM(netfs_trace_tcon_ref_free, "FRE ") \ EM(netfs_trace_tcon_ref_free_fail, "FRE Fail ") \ EM(netfs_trace_tcon_ref_free_ipc, "FRE Ipc ") \