Skip to content

Commit

Permalink
Merge tag '6.11-rc-smb-client-fixes-part2' of git://git.samba.org/sfr…
Browse files Browse the repository at this point in the history
…ench/cifs-2.6

Pull more smb client updates from Steve French:

 - fix for potential null pointer use in init cifs

 - additional dynamic trace points to improve debugging of some common
   scenarios

 - two SMB1 fixes (one addressing reconnect with POSIX extensions, one a
   mount parsing error)

* tag '6.11-rc-smb-client-fixes-part2' of git://git.samba.org/sfrench/cifs-2.6:
  smb3: add dynamic trace point for session setup key expired failures
  smb3: add four dynamic tracepoints for copy_file_range and reflink
  smb3: add dynamic tracepoint for reflink errors
  cifs: mount with "unix" mount option for SMB1 incorrectly handled
  cifs: fix reconnect with SMB1 UNIX Extensions
  cifs: fix potential null pointer use in destroy_workqueue in init_cifs error path
  • Loading branch information
torvalds committed Jul 28, 2024
2 parents 6342649 + b6f6a7a commit 5437f30
Show file tree
Hide file tree
Showing 5 changed files with 203 additions and 7 deletions.
8 changes: 4 additions & 4 deletions fs/smb/client/cifsfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -1894,12 +1894,12 @@ init_cifs(void)
WQ_FREEZABLE|WQ_MEM_RECLAIM, 0);
if (!serverclose_wq) {
rc = -ENOMEM;
goto out_destroy_serverclose_wq;
goto out_destroy_deferredclose_wq;
}

rc = cifs_init_inodecache();
if (rc)
goto out_destroy_deferredclose_wq;
goto out_destroy_serverclose_wq;

rc = cifs_init_netfs();
if (rc)
Expand Down Expand Up @@ -1967,6 +1967,8 @@ init_cifs(void)
cifs_destroy_netfs();
out_destroy_inodecache:
cifs_destroy_inodecache();
out_destroy_serverclose_wq:
destroy_workqueue(serverclose_wq);
out_destroy_deferredclose_wq:
destroy_workqueue(deferredclose_wq);
out_destroy_cifsoplockd_wq:
Expand All @@ -1977,8 +1979,6 @@ init_cifs(void)
destroy_workqueue(decrypt_wq);
out_destroy_cifsiod_wq:
destroy_workqueue(cifsiod_wq);
out_destroy_serverclose_wq:
destroy_workqueue(serverclose_wq);
out_clean_proc:
cifs_proc_clean();
return rc;
Expand Down
24 changes: 23 additions & 1 deletion fs/smb/client/connect.c
Original file line number Diff line number Diff line change
Expand Up @@ -2614,6 +2614,13 @@ cifs_get_tcon(struct cifs_ses *ses, struct smb3_fs_context *ctx)
cifs_dbg(VFS, "Server does not support mounting with posix SMB3.11 extensions\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else if (ses->server->vals->protocol_id == SMB10_PROT_ID)
if (cap_unix(ses))
cifs_dbg(FYI, "Unix Extensions requested on SMB1 mount\n");
else {
cifs_dbg(VFS, "SMB1 Unix Extensions not supported by server\n");
rc = -EOPNOTSUPP;
goto out_fail;
} else {
cifs_dbg(VFS,
"Check vers= mount option. SMB3.11 disabled but required for POSIX extensions\n");
Expand Down Expand Up @@ -3686,6 +3693,7 @@ int cifs_mount(struct cifs_sb_info *cifs_sb, struct smb3_fs_context *ctx)
}
#endif

#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/*
* Issue a TREE_CONNECT request.
*/
Expand Down Expand Up @@ -3807,11 +3815,25 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses,
else
tcon->Flags = 0;
cifs_dbg(FYI, "Tcon flags: 0x%x\n", tcon->Flags);
}

/*
* reset_cifs_unix_caps calls QFSInfo which requires
* need_reconnect to be false, but we would not need to call
* reset_caps if this were not a reconnect case so must check
* need_reconnect flag here. The caller will also clear
* need_reconnect when tcon was successful but needed to be
* cleared earlier in the case of unix extensions reconnect
*/
if (tcon->need_reconnect && tcon->unix_ext) {
cifs_dbg(FYI, "resetting caps for %s\n", tcon->tree_name);
tcon->need_reconnect = false;
reset_cifs_unix_caps(xid, tcon, NULL, NULL);
}
}
cifs_buf_release(smb_buffer);
return rc;
}
#endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */

static void delayed_free(struct rcu_head *p)
{
Expand Down
20 changes: 19 additions & 1 deletion fs/smb/client/smb2ops.c
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,10 @@ smb2_copychunk_range(const unsigned int xid,

tcon = tlink_tcon(trgtfile->tlink);

trace_smb3_copychunk_enter(xid, srcfile->fid.volatile_fid,
trgtfile->fid.volatile_fid, tcon->tid,
tcon->ses->Suid, src_off, dest_off, len);

while (len > 0) {
pcchunk->SourceOffset = cpu_to_le64(src_off);
pcchunk->TargetOffset = cpu_to_le64(dest_off);
Expand Down Expand Up @@ -1863,6 +1867,9 @@ smb2_copychunk_range(const unsigned int xid,
le32_to_cpu(retbuf->ChunksWritten),
le32_to_cpu(retbuf->ChunkBytesWritten),
bytes_written);
trace_smb3_copychunk_done(xid, srcfile->fid.volatile_fid,
trgtfile->fid.volatile_fid, tcon->tid,
tcon->ses->Suid, src_off, dest_off, len);
} else if (rc == -EINVAL) {
if (ret_data_len != sizeof(struct copychunk_ioctl_rsp))
goto cchunk_out;
Expand Down Expand Up @@ -2046,7 +2053,9 @@ smb2_duplicate_extents(const unsigned int xid,
dup_ext_buf.ByteCount = cpu_to_le64(len);
cifs_dbg(FYI, "Duplicate extents: src off %lld dst off %lld len %lld\n",
src_off, dest_off, len);

trace_smb3_clone_enter(xid, srcfile->fid.volatile_fid,
trgtfile->fid.volatile_fid, tcon->tid,
tcon->ses->Suid, src_off, dest_off, len);
inode = d_inode(trgtfile->dentry);
if (inode->i_size < dest_off + len) {
rc = smb2_set_file_size(xid, tcon, trgtfile, dest_off + len, false);
Expand Down Expand Up @@ -2075,6 +2084,15 @@ smb2_duplicate_extents(const unsigned int xid,
cifs_dbg(FYI, "Non-zero response length in duplicate extents\n");

duplicate_extents_out:
if (rc)
trace_smb3_clone_err(xid, srcfile->fid.volatile_fid,
trgtfile->fid.volatile_fid,
tcon->tid, tcon->ses->Suid, src_off,
dest_off, len, rc);
else
trace_smb3_clone_done(xid, srcfile->fid.volatile_fid,
trgtfile->fid.volatile_fid, tcon->tid,
tcon->ses->Suid, src_off, dest_off, len);
return rc;
}

Expand Down
8 changes: 7 additions & 1 deletion fs/smb/client/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1562,8 +1562,14 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data)
cifs_small_buf_release(sess_data->iov[0].iov_base);
if (rc == 0)
sess_data->ses->expired_pwd = false;
else if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED))
else if ((rc == -EACCES) || (rc == -EKEYEXPIRED) || (rc == -EKEYREVOKED)) {
if (sess_data->ses->expired_pwd == false)
trace_smb3_key_expired(sess_data->server->hostname,
sess_data->ses->user_name,
sess_data->server->conn_id,
&sess_data->server->dstaddr, rc);
sess_data->ses->expired_pwd = true;
}

memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec));

Expand Down
150 changes: 150 additions & 0 deletions fs/smb/client/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,116 @@ DEFINE_SMB3_OTHER_ERR_EVENT(query_dir_err);
DEFINE_SMB3_OTHER_ERR_EVENT(zero_err);
DEFINE_SMB3_OTHER_ERR_EVENT(falloc_err);

/*
* For logging errors in reflink and copy_range ops e.g. smb2_copychunk_range
* and smb2_duplicate_extents
*/
DECLARE_EVENT_CLASS(smb3_copy_range_err_class,
TP_PROTO(unsigned int xid,
__u64 src_fid,
__u64 target_fid,
__u32 tid,
__u64 sesid,
__u64 src_offset,
__u64 target_offset,
__u32 len,
int rc),
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len, rc),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u64, src_fid)
__field(__u64, target_fid)
__field(__u32, tid)
__field(__u64, sesid)
__field(__u64, src_offset)
__field(__u64, target_offset)
__field(__u32, len)
__field(int, rc)
),
TP_fast_assign(
__entry->xid = xid;
__entry->src_fid = src_fid;
__entry->target_fid = target_fid;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->src_offset = src_offset;
__entry->target_offset = target_offset;
__entry->len = len;
__entry->rc = rc;
),
TP_printk("\txid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x rc=%d",
__entry->xid, __entry->sesid, __entry->tid, __entry->target_fid,
__entry->src_offset, __entry->target_fid, __entry->target_offset, __entry->len, __entry->rc)
)

#define DEFINE_SMB3_COPY_RANGE_ERR_EVENT(name) \
DEFINE_EVENT(smb3_copy_range_err_class, smb3_##name, \
TP_PROTO(unsigned int xid, \
__u64 src_fid, \
__u64 target_fid, \
__u32 tid, \
__u64 sesid, \
__u64 src_offset, \
__u64 target_offset, \
__u32 len, \
int rc), \
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len, rc))

DEFINE_SMB3_COPY_RANGE_ERR_EVENT(clone_err);
/* TODO: Add SMB3_COPY_RANGE_ERR_EVENT(copychunk_err) */

DECLARE_EVENT_CLASS(smb3_copy_range_done_class,
TP_PROTO(unsigned int xid,
__u64 src_fid,
__u64 target_fid,
__u32 tid,
__u64 sesid,
__u64 src_offset,
__u64 target_offset,
__u32 len),
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len),
TP_STRUCT__entry(
__field(unsigned int, xid)
__field(__u64, src_fid)
__field(__u64, target_fid)
__field(__u32, tid)
__field(__u64, sesid)
__field(__u64, src_offset)
__field(__u64, target_offset)
__field(__u32, len)
),
TP_fast_assign(
__entry->xid = xid;
__entry->src_fid = src_fid;
__entry->target_fid = target_fid;
__entry->tid = tid;
__entry->sesid = sesid;
__entry->src_offset = src_offset;
__entry->target_offset = target_offset;
__entry->len = len;
),
TP_printk("\txid=%u sid=0x%llx tid=0x%x source fid=0x%llx source offset=0x%llx target fid=0x%llx target offset=0x%llx len=0x%x",
__entry->xid, __entry->sesid, __entry->tid, __entry->target_fid,
__entry->src_offset, __entry->target_fid, __entry->target_offset, __entry->len)
)

#define DEFINE_SMB3_COPY_RANGE_DONE_EVENT(name) \
DEFINE_EVENT(smb3_copy_range_done_class, smb3_##name, \
TP_PROTO(unsigned int xid, \
__u64 src_fid, \
__u64 target_fid, \
__u32 tid, \
__u64 sesid, \
__u64 src_offset, \
__u64 target_offset, \
__u32 len), \
TP_ARGS(xid, src_fid, target_fid, tid, sesid, src_offset, target_offset, len))

DEFINE_SMB3_COPY_RANGE_DONE_EVENT(copychunk_enter);
DEFINE_SMB3_COPY_RANGE_DONE_EVENT(clone_enter);
DEFINE_SMB3_COPY_RANGE_DONE_EVENT(copychunk_done);
DEFINE_SMB3_COPY_RANGE_DONE_EVENT(clone_done);


/* For logging successful read or write */
DECLARE_EVENT_CLASS(smb3_rw_done_class,
Expand Down Expand Up @@ -1171,6 +1281,46 @@ DEFINE_EVENT(smb3_connect_err_class, smb3_##name, \

DEFINE_SMB3_CONNECT_ERR_EVENT(connect_err);

DECLARE_EVENT_CLASS(smb3_sess_setup_err_class,
TP_PROTO(char *hostname, char *username, __u64 conn_id,
const struct __kernel_sockaddr_storage *dst_addr, int rc),
TP_ARGS(hostname, username, conn_id, dst_addr, rc),
TP_STRUCT__entry(
__string(hostname, hostname)
__string(username, username)
__field(__u64, conn_id)
__array(__u8, dst_addr, sizeof(struct sockaddr_storage))
__field(int, rc)
),
TP_fast_assign(
struct sockaddr_storage *pss = NULL;

__entry->conn_id = conn_id;
__entry->rc = rc;
pss = (struct sockaddr_storage *)__entry->dst_addr;
*pss = *dst_addr;
__assign_str(hostname);
__assign_str(username);
),
TP_printk("rc=%d user=%s conn_id=0x%llx server=%s addr=%pISpsfc",
__entry->rc,
__get_str(username),
__entry->conn_id,
__get_str(hostname),
__entry->dst_addr)
)

#define DEFINE_SMB3_SES_SETUP_ERR_EVENT(name) \
DEFINE_EVENT(smb3_sess_setup_err_class, smb3_##name, \
TP_PROTO(char *hostname, \
char *username, \
__u64 conn_id, \
const struct __kernel_sockaddr_storage *addr, \
int rc), \
TP_ARGS(hostname, username, conn_id, addr, rc))

DEFINE_SMB3_SES_SETUP_ERR_EVENT(key_expired);

DECLARE_EVENT_CLASS(smb3_reconnect_class,
TP_PROTO(__u64 currmid,
__u64 conn_id,
Expand Down

0 comments on commit 5437f30

Please sign in to comment.