diff --git a/MAINTAINERS b/MAINTAINERS index 06a8c74577aa..54b33d43e9fd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -6386,7 +6386,7 @@ L: linux-cifs@vger.kernel.org L: samba-technical@lists.samba.org (moderated for non-subscribers) S: Supported W: https://wiki.samba.org/index.php/LinuxCIFS -T: git git://git.samba.org/sfrench/cifs-2.6.git +T: git https://git.samba.org/sfrench/cifs-2.6.git F: Documentation/admin-guide/cifs/ F: fs/smb/client/ F: fs/smb/common/ @@ -14007,7 +14007,7 @@ R: Sergey Senozhatsky R: Tom Talpey L: linux-cifs@vger.kernel.org S: Maintained -T: git git://git.samba.org/ksmbd.git +T: git https://git.samba.org/ksmbd.git F: Documentation/filesystems/smb/ksmbd.rst F: fs/smb/common/ F: fs/smb/server/ diff --git a/fs/dcache.c b/fs/dcache.c index df11bbba0342..dbcbd0affb26 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -3196,15 +3196,18 @@ void d_mark_tmpfile(struct file *file, struct inode *inode) } EXPORT_SYMBOL(d_mark_tmpfile); -void d_mark_tmpfile_name(struct file *file, const struct qstr *name) +int d_mark_tmpfile_name(struct file *file, const struct qstr *name) { struct dentry *dentry = file->f_path.dentry; char *dname = dentry->d_shortname.string; - BUG_ON(dname_external(dentry)); - BUG_ON(d_really_is_positive(dentry)); - BUG_ON(!d_unlinked(dentry)); - BUG_ON(name->len > DNAME_INLINE_LEN - 1); + if (unlikely(dname_external(dentry) || + d_really_is_positive(dentry) || + !d_unlinked(dentry))) + return -EINVAL; + if (unlikely(name->len > DNAME_INLINE_LEN - 1)) + return -ENAMETOOLONG; + spin_lock(&dentry->d_parent->d_lock); spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED); dentry->__d_name.len = name->len; @@ -3212,6 +3215,7 @@ void d_mark_tmpfile_name(struct file *file, const struct qstr *name) dname[name->len] = '\0'; spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_parent->d_lock); + return 0; } EXPORT_SYMBOL(d_mark_tmpfile_name); diff --git a/fs/smb/client/cifsfs.h b/fs/smb/client/cifsfs.h index 18f9f93a01b4..7370b38da938 100644 --- a/fs/smb/client/cifsfs.h +++ b/fs/smb/client/cifsfs.h @@ -10,6 +10,7 @@ #define _CIFSFS_H #include +#include #define ROOT_I 2 @@ -149,17 +150,11 @@ struct dentry *cifs_smb3_do_mount(struct file_system_type *fs_type, int flags, char *cifs_silly_fullpath(struct dentry *dentry); -#define CIFS_TMPNAME_PREFIX ".__smbfile_tmp" -#define CIFS_TMPNAME_PREFIX_LEN ((int)sizeof(CIFS_TMPNAME_PREFIX) - 1) -#define CIFS_TMPNAME_COUNTER_LEN ((int)sizeof(cifs_tmpcounter) * 2) -#define CIFS_TMPNAME_LEN \ - (CIFS_TMPNAME_PREFIX_LEN + CIFS_TMPNAME_COUNTER_LEN) +#define CIFS_TMPNAME_PREFIX ".__smbfile_tmp" +#define CIFS_TMPNAME_LEN (DNAME_INLINE_LEN - 1) -#define CIFS_SILLYNAME_PREFIX ".__smbfile_silly" -#define CIFS_SILLYNAME_PREFIX_LEN ((int)sizeof(CIFS_SILLYNAME_PREFIX) - 1) -#define CIFS_SILLYNAME_COUNTER_LEN ((int)sizeof(cifs_sillycounter) * 2) -#define CIFS_SILLYNAME_LEN \ - (CIFS_SILLYNAME_PREFIX_LEN + CIFS_SILLYNAME_COUNTER_LEN) +#define CIFS_SILLYNAME_PREFIX ".__smbfile_silly" +#define CIFS_SILLYNAME_LEN (DNAME_INLINE_LEN - 1) #ifdef CONFIG_CIFS_NFSD_EXPORT extern const struct export_operations cifs_export_ops; diff --git a/fs/smb/client/dir.c b/fs/smb/client/dir.c index 6ea1ae7f7a46..e4295a5b55b3 100644 --- a/fs/smb/client/dir.c +++ b/fs/smb/client/dir.c @@ -1056,9 +1056,9 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, { struct dentry *dentry = file->f_path.dentry; struct cifs_sb_info *cifs_sb = CIFS_SB(dir); + size_t namesize = CIFS_TMPNAME_LEN + 1; char *path __free(kfree) = NULL, *name; unsigned int oflags = file->f_flags; - size_t size = CIFS_TMPNAME_LEN + 1; int retries = 0, max_retries = 16; struct TCP_Server_Info *server; struct cifs_pending_open open; @@ -1070,6 +1070,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, struct inode *inode; unsigned int xid; __u32 oplock; + int namelen; int rc; if (unlikely(cifs_forced_shutdown(cifs_sb))) @@ -1093,7 +1094,7 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, server->ops->new_lease_key(&fid); cifs_add_pending_open(&fid, tlink, &open); - path = alloc_parent_path(dentry, size - 1); + path = alloc_parent_path(dentry, namesize - 1); if (IS_ERR(path)) { cifs_del_pending_open(&open); rc = PTR_ERR(path); @@ -1103,16 +1104,22 @@ int cifs_tmpfile(struct mnt_idmap *idmap, struct inode *dir, name = path + strlen(path); do { - scnprintf(name, size, - CIFS_TMPNAME_PREFIX "%0*x", - CIFS_TMPNAME_COUNTER_LEN, - atomic_inc_return(&cifs_tmpcounter)); + /* Append tmpfile name to @path */ + namelen = scnprintf(name, namesize, CIFS_TMPNAME_PREFIX "%x", + atomic_inc_return(&cifs_tmpcounter)); rc = __cifs_do_create(dir, dentry, path, xid, tlink, oflags, mode, &oplock, &fid, NULL, &inode); if (!rc) { + rc = d_mark_tmpfile_name(file, &QSTR_LEN(name, namelen)); + if (rc) { + cifs_dbg(VFS | ONCE, "%s: failed to set filename in dentry: %d\n", + __func__, rc); + rc = -EISDIR; + iput(inode); + goto err_open; + } set_nlink(inode, 0); mark_inode_dirty(inode); - d_mark_tmpfile_name(file, &QSTR_LEN(name, size - 1)); d_instantiate(dentry, inode); break; } @@ -1168,9 +1175,7 @@ char *cifs_silly_fullpath(struct dentry *dentry) do { dput(sdentry); - scnprintf(name, namesize, - CIFS_SILLYNAME_PREFIX "%0*x", - CIFS_SILLYNAME_COUNTER_LEN, + scnprintf(name, namesize, CIFS_SILLYNAME_PREFIX "%x", atomic_inc_return(&cifs_sillycounter)); sdentry = lookup_noperm(&QSTR(name), dentry->d_parent); if (IS_ERR(sdentry)) diff --git a/fs/smb/client/file.c b/fs/smb/client/file.c index ebafc7994cb4..f743f058667f 100644 --- a/fs/smb/client/file.c +++ b/fs/smb/client/file.c @@ -1082,6 +1082,9 @@ int cifs_open(struct inode *inode, struct file *file) rc = cfile ? 0 : -ENOENT; } if (rc == 0) { + trace_smb3_open_cached(xid, tcon->tid, tcon->ses->Suid, + cfile->fid.persistent_fid, + file->f_flags, cfile->f_flags); file->private_data = cfile; spin_lock(&CIFS_I(inode)->deferred_lock); cifs_del_deferred_close(cfile); @@ -1441,6 +1444,7 @@ int cifs_close(struct inode *inode, struct file *file) struct cifsInodeInfo *cinode = CIFS_I(inode); struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb); struct cifs_deferred_close *dclose; + struct cifs_tcon *tcon; cifs_fscache_unuse_inode_cookie(inode, file->f_mode & FMODE_WRITE); @@ -1467,6 +1471,10 @@ int cifs_close(struct inode *inode, struct file *file) cifsFileInfo_get(cfile); } else { /* Deferred close for files */ + tcon = tlink_tcon(cfile->tlink); + trace_smb3_close_cached(tcon->tid, tcon->ses->Suid, + cfile->fid.persistent_fid, + cifs_sb->ctx->closetimeo); queue_delayed_work(deferredclose_wq, &cfile->deferred, cifs_sb->ctx->closetimeo); cfile->deferred_close_scheduled = true; @@ -1630,6 +1638,9 @@ cifs_find_fid_lock_conflict(struct cifs_fid_locks *fdlocks, __u64 offset, continue; if (conf_lock) *conf_lock = li; + trace_smb3_lock_conflict(cfile->fid.persistent_fid, + offset, length, type, + li->offset, li->length, li->type, li->pid); return true; } return false; @@ -1711,7 +1722,7 @@ cifs_lock_add(struct cifsFileInfo *cfile, struct cifsLockInfo *lock) */ static int cifs_lock_add_if(struct cifsFileInfo *cfile, struct cifsLockInfo *lock, - bool wait) + bool wait, unsigned int xid) { struct cifsLockInfo *conf_lock; struct cifsInodeInfo *cinode = CIFS_I(d_inode(cfile->dentry)); @@ -1726,7 +1737,13 @@ try_again: lock->type, lock->flags, &conf_lock, CIFS_LOCK_OP); if (!exist && cinode->can_cache_brlcks) { + struct cifs_tcon *tcon = tlink_tcon(cfile->tlink); + list_add_tail(&lock->llist, &cfile->llist->locks); + trace_smb3_lock_cached(xid, cfile->fid.persistent_fid, + tcon->tid, tcon->ses->Suid, + lock->offset, lock->length, + lock->type, 1, 0); up_write(&cinode->lock_sem); return rc; } @@ -2341,7 +2358,7 @@ cifs_setlk(struct file *file, struct file_lock *flock, __u32 type, if (!lock) return -ENOMEM; - rc = cifs_lock_add_if(cfile, lock, wait_flag); + rc = cifs_lock_add_if(cfile, lock, wait_flag, xid); if (rc < 0) { kfree(lock); return rc; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 509fcea28a42..a2105f4b54db 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4943,6 +4943,14 @@ receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry **mid, goto free_dw; server->total_read += rc; + if (le32_to_cpu(tr_hdr->OriginalMessageSize) < + server->vals->read_rsp_size) { + cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response (%zu)\n", + le32_to_cpu(tr_hdr->OriginalMessageSize), + server->vals->read_rsp_size); + rc = -EINVAL; + goto discard_data; + } len = le32_to_cpu(tr_hdr->OriginalMessageSize) - server->vals->read_rsp_size; dw->len = len; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 957aca2222b5..cd8b49722149 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -3043,7 +3043,8 @@ replay_again: } trace_smb3_posix_mkdir_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, - CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES); + CREATE_NOT_FILE, FILE_WRITE_ATTRIBUTES, + rsp->OplockLevel); SMB2_close(xid, tcon, rsp->PersistentFileId, rsp->VolatileFileId); @@ -3320,9 +3321,6 @@ replay_again: goto creat_exit; } else if (rsp == NULL) /* unlikely to happen, but safer to check */ goto creat_exit; - else - trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, - oparms->create_options, oparms->desired_access); atomic_inc(&tcon->num_remote_opens); oparms->fid->persistent_fid = rsp->PersistentFileId; @@ -3347,6 +3345,10 @@ replay_again: rc = smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch, oparms->fid->lease_key, oplock, buf, posix); + + trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, + oparms->create_options, oparms->desired_access, + *oplock); creat_exit: SMB2_open_free(&rqst); free_rsp_buf(resp_buftype, rsp); @@ -6272,6 +6274,11 @@ replay_again: smb2_set_replay(server, &rqst); } + trace_smb3_lock_enter(xid, persist_fid, tcon->tid, tcon->ses->Suid, + le64_to_cpu(buf[0].Offset), + le64_to_cpu(buf[0].Length), + le32_to_cpu(buf[0].Flags), num_lock, 0); + rc = cifs_send_recv(xid, tcon->ses, server, &rqst, &resp_buf_type, flags, &rsp_iov); @@ -6280,7 +6287,15 @@ replay_again: cifs_dbg(FYI, "Send error in smb2_lockv = %d\n", rc); cifs_stats_fail_inc(tcon, SMB2_LOCK_HE); trace_smb3_lock_err(xid, persist_fid, tcon->tid, - tcon->ses->Suid, rc); + tcon->ses->Suid, + le64_to_cpu(buf[0].Offset), + le64_to_cpu(buf[0].Length), + le32_to_cpu(buf[0].Flags), num_lock, rc); + } else { + trace_smb3_lock_done(xid, persist_fid, tcon->tid, tcon->ses->Suid, + le64_to_cpu(buf[0].Offset), + le64_to_cpu(buf[0].Length), + le32_to_cpu(buf[0].Flags), num_lock, 0); } if (is_replayable_error(rc) && diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index acfbb63086ea..b99ec5a417fa 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -670,9 +670,100 @@ DEFINE_EVENT(smb3_fd_err_class, smb3_##name, \ TP_ARGS(xid, fid, tid, sesid, rc)) DEFINE_SMB3_FD_ERR_EVENT(flush_err); -DEFINE_SMB3_FD_ERR_EVENT(lock_err); DEFINE_SMB3_FD_ERR_EVENT(close_err); +DECLARE_EVENT_CLASS(smb3_lock_class, + TP_PROTO(unsigned int xid, + __u64 fid, + __u32 tid, + __u64 sesid, + __u64 offset, + __u64 len, + __u32 flags, + __u32 num_lock, + int rc), + TP_ARGS(xid, fid, tid, sesid, offset, len, flags, num_lock, rc), + TP_STRUCT__entry( + __field(unsigned int, xid) + __field(__u64, fid) + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, offset) + __field(__u64, len) + __field(__u32, flags) + __field(__u32, num_lock) + __field(int, rc) + ), + TP_fast_assign( + __entry->xid = xid; + __entry->fid = fid; + __entry->tid = tid; + __entry->sesid = sesid; + __entry->offset = offset; + __entry->len = len; + __entry->flags = flags; + __entry->num_lock = num_lock; + __entry->rc = rc; + ), + TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx offset=0x%llx len=0x%llx flags=0x%x num_lock=%u rc=%d", + __entry->xid, __entry->sesid, __entry->tid, __entry->fid, + __entry->offset, __entry->len, __entry->flags, __entry->num_lock, + __entry->rc) +) + +#define DEFINE_SMB3_LOCK_EVENT(name) \ +DEFINE_EVENT(smb3_lock_class, smb3_##name, \ + TP_PROTO(unsigned int xid, \ + __u64 fid, \ + __u32 tid, \ + __u64 sesid, \ + __u64 offset, \ + __u64 len, \ + __u32 flags, \ + __u32 num_lock, \ + int rc), \ + TP_ARGS(xid, fid, tid, sesid, offset, len, flags, num_lock, rc)) + +DEFINE_SMB3_LOCK_EVENT(lock_enter); +DEFINE_SMB3_LOCK_EVENT(lock_done); +DEFINE_SMB3_LOCK_EVENT(lock_err); +DEFINE_SMB3_LOCK_EVENT(lock_cached); + +TRACE_EVENT(smb3_lock_conflict, + TP_PROTO(__u64 fid, + __u64 req_offset, + __u64 req_len, + __u8 req_type, + __u64 conf_offset, + __u64 conf_len, + __u16 conf_type, + __u32 conf_pid), + TP_ARGS(fid, req_offset, req_len, req_type, conf_offset, conf_len, conf_type, conf_pid), + TP_STRUCT__entry( + __field(__u64, fid) + __field(__u64, req_offset) + __field(__u64, req_len) + __field(__u8, req_type) + __field(__u64, conf_offset) + __field(__u64, conf_len) + __field(__u16, conf_type) + __field(__u32, conf_pid) + ), + TP_fast_assign( + __entry->fid = fid; + __entry->req_offset = req_offset; + __entry->req_len = req_len; + __entry->req_type = req_type; + __entry->conf_offset = conf_offset; + __entry->conf_len = conf_len; + __entry->conf_type = conf_type; + __entry->conf_pid = conf_pid; + ), + TP_printk("fid=0x%llx req=[0x%llx:0x%llx] type=0x%x conflicts with [0x%llx:0x%llx] type=0x%x pid=%u", + __entry->fid, __entry->req_offset, __entry->req_len, __entry->req_type, + __entry->conf_offset, __entry->conf_len, __entry->conf_type, __entry->conf_pid) +); + /* * For handle based query/set info calls */ @@ -1230,8 +1321,9 @@ DECLARE_EVENT_CLASS(smb3_open_done_class, __u32 tid, __u64 sesid, int create_options, - int desired_access), - TP_ARGS(xid, fid, tid, sesid, create_options, desired_access), + int desired_access, + __u8 oplock), + TP_ARGS(xid, fid, tid, sesid, create_options, desired_access, oplock), TP_STRUCT__entry( __field(unsigned int, xid) __field(__u64, fid) @@ -1239,6 +1331,7 @@ DECLARE_EVENT_CLASS(smb3_open_done_class, __field(__u64, sesid) __field(int, create_options) __field(int, desired_access) + __field(__u8, oplock) ), TP_fast_assign( __entry->xid = xid; @@ -1247,10 +1340,11 @@ DECLARE_EVENT_CLASS(smb3_open_done_class, __entry->sesid = sesid; __entry->create_options = create_options; __entry->desired_access = desired_access; + __entry->oplock = oplock; ), - TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx cr_opts=0x%x des_access=0x%x", + TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx cr_opts=0x%x des_access=0x%x oplock=0x%x", __entry->xid, __entry->sesid, __entry->tid, __entry->fid, - __entry->create_options, __entry->desired_access) + __entry->create_options, __entry->desired_access, __entry->oplock) ) #define DEFINE_SMB3_OPEN_DONE_EVENT(name) \ @@ -1260,12 +1354,64 @@ DEFINE_EVENT(smb3_open_done_class, smb3_##name, \ __u32 tid, \ __u64 sesid, \ int create_options, \ - int desired_access), \ - TP_ARGS(xid, fid, tid, sesid, create_options, desired_access)) + int desired_access, \ + __u8 oplock), \ + TP_ARGS(xid, fid, tid, sesid, create_options, desired_access, oplock)) DEFINE_SMB3_OPEN_DONE_EVENT(open_done); DEFINE_SMB3_OPEN_DONE_EVENT(posix_mkdir_done); +TRACE_EVENT(smb3_open_cached, + TP_PROTO(unsigned int xid, + __u32 tid, + __u64 sesid, + __u64 fid, + unsigned int oflags, + unsigned int cflags), + TP_ARGS(xid, tid, sesid, fid, oflags, cflags), + TP_STRUCT__entry( + __field(unsigned int, xid) + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, fid) + __field(unsigned int, oflags) + __field(unsigned int, cflags) + ), + TP_fast_assign( + __entry->xid = xid; + __entry->tid = tid; + __entry->sesid = sesid; + __entry->fid = fid; + __entry->oflags = oflags; + __entry->cflags = cflags; + ), + TP_printk("xid=%u sid=0x%llx tid=0x%x fid=0x%llx oflags=0x%x cflags=0x%x", + __entry->xid, __entry->sesid, __entry->tid, __entry->fid, + __entry->oflags, __entry->cflags) +); + +TRACE_EVENT(smb3_close_cached, + TP_PROTO(__u32 tid, + __u64 sesid, + __u64 fid, + unsigned long delay_jiffies), + TP_ARGS(tid, sesid, fid, delay_jiffies), + TP_STRUCT__entry( + __field(__u32, tid) + __field(__u64, sesid) + __field(__u64, fid) + __field(unsigned long, delay_jiffies) + ), + TP_fast_assign( + __entry->tid = tid; + __entry->sesid = sesid; + __entry->fid = fid; + __entry->delay_jiffies = delay_jiffies; + ), + TP_printk("sid=0x%llx tid=0x%x fid=0x%llx delay_jiffies=%lu", + __entry->sesid, __entry->tid, __entry->fid, __entry->delay_jiffies) +); + DECLARE_EVENT_CLASS(smb3_lease_done_class, TP_PROTO(__u32 lease_state, diff --git a/include/linux/dcache.h b/include/linux/dcache.h index f60819dcfebd..c5bd5a74baba 100644 --- a/include/linux/dcache.h +++ b/include/linux/dcache.h @@ -264,7 +264,7 @@ extern void d_invalidate(struct dentry *); extern struct dentry * d_make_root(struct inode *); extern void d_mark_tmpfile(struct file *, struct inode *); -void d_mark_tmpfile_name(struct file *file, const struct qstr *name); +int d_mark_tmpfile_name(struct file *file, const struct qstr *name); extern void d_tmpfile(struct file *, struct inode *); extern struct dentry *d_find_alias(struct inode *);