summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2024-07-27 20:08:07 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2024-07-27 20:08:07 -0700
commit5437f30d3458ad36e83ab96088d490ebfee844d8 (patch)
tree61a6225ed26671fe2f66bbe96114d6b30dad2b1c
parent6342649c33d232c4e7ac690b98bcddaab10a4d8c (diff)
parentb6f6a7aa689f1c255e06fee3ca13c9f9e5c12780 (diff)
downloadlwn-5437f30d3458ad36e83ab96088d490ebfee844d8.tar.gz
lwn-5437f30d3458ad36e83ab96088d490ebfee844d8.zip
Merge tag '6.11-rc-smb-client-fixes-part2' of git://git.samba.org/sfrench/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
-rw-r--r--fs/smb/client/cifsfs.c8
-rw-r--r--fs/smb/client/connect.c24
-rw-r--r--fs/smb/client/smb2ops.c20
-rw-r--r--fs/smb/client/smb2pdu.c8
-rw-r--r--fs/smb/client/trace.h150
5 files changed, 203 insertions, 7 deletions
diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c
index c92937bed133..2c4b357d85e2 100644
--- a/fs/smb/client/cifsfs.c
+++ b/fs/smb/client/cifsfs.c
@@ -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)
@@ -1967,6 +1967,8 @@ out_destroy_netfs:
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:
@@ -1977,8 +1979,6 @@ out_destroy_decrypt_wq:
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;
diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c
index 7a16e12f5da8..d2307162a2de 100644
--- a/fs/smb/client/connect.c
+++ b/fs/smb/client/connect.c
@@ -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");
@@ -3686,6 +3693,7 @@ error:
}
#endif
+#ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY
/*
* Issue a TREE_CONNECT request.
*/
@@ -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)
{
diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c
index 7fe59235f090..322cabc69c6f 100644
--- a/fs/smb/client/smb2ops.c
+++ b/fs/smb/client/smb2ops.c
@@ -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);
@@ -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;
@@ -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);
@@ -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;
}
diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 9fc5b11c0b6c..9a06b5594669 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -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));
diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h
index 36d5295c2a6f..6b3bdfb97211 100644
--- a/fs/smb/client/trace.h
+++ b/fs/smb/client/trace.h
@@ -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,
@@ -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,