Commit 5437f30d authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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
parents 6342649c b6f6a7aa
Loading
Loading
Loading
Loading
+4 −4
Original line number Diff line number Diff line
@@ -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 @@ 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:
@@ -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;
+23 −1
Original line number Diff line number Diff line
@@ -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 @@ 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.
 */
@@ -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)
{
+19 −1
Original line number Diff line number Diff line
@@ -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;
}

+7 −1
Original line number Diff line number Diff line
@@ -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));

+150 −0
Original line number Diff line number Diff line
@@ -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,