--- /dev/null
+From 66d45ca1350a3bb8d5f4db8879ccad3ed492337a Mon Sep 17 00:00:00 2001
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+Date: Fri, 17 Feb 2023 13:35:00 +1000
+Subject: cifs: Check the lease context if we actually got a lease
+
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+
+commit 66d45ca1350a3bb8d5f4db8879ccad3ed492337a upstream.
+
+Some servers may return that we got a lease in rsp->OplockLevel
+but then in the lease context contradict this and say we got no lease
+at all. Thus we need to check the context if we have a lease.
+Additionally, If we do not get a lease we need to make sure we close
+the handle before we return an error to the caller.
+
+Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Bharath SM <bharathsm@microsoft.com>
+Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cached_dir.c | 14 +++++++++-----
+ 1 file changed, 9 insertions(+), 5 deletions(-)
+
+--- a/fs/cifs/cached_dir.c
++++ b/fs/cifs/cached_dir.c
+@@ -221,8 +221,7 @@ int open_cached_dir(unsigned int xid, st
+ }
+ goto oshr_free;
+ }
+-
+- atomic_inc(&tcon->num_remote_opens);
++ cfid->is_open = true;
+
+ o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
+ oparms.fid->persistent_fid = o_rsp->PersistentFileId;
+@@ -239,7 +238,8 @@ int open_cached_dir(unsigned int xid, st
+ &oparms.fid->epoch,
+ oparms.fid->lease_key, &oplock,
+ NULL, NULL);
+-
++ if (!(oplock & SMB2_LEASE_READ_CACHING_HE))
++ goto oshr_free;
+ qi_rsp = (struct smb2_query_info_rsp *)rsp_iov[1].iov_base;
+ if (le32_to_cpu(qi_rsp->OutputBufferLength) < sizeof(struct smb2_file_all_info))
+ goto oshr_free;
+@@ -262,7 +262,6 @@ int open_cached_dir(unsigned int xid, st
+ cfid->dentry = dentry;
+ cfid->tcon = tcon;
+ cfid->time = jiffies;
+- cfid->is_open = true;
+ cfid->has_lease = true;
+
+ oshr_free:
+@@ -282,12 +281,17 @@ oshr_free:
+ }
+ spin_unlock(&cfids->cfid_list_lock);
+ if (rc) {
++ if (cfid->is_open)
++ SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
++ cfid->fid.volatile_fid);
+ free_cached_dir(cfid);
+ cfid = NULL;
+ }
+
+- if (rc == 0)
++ if (rc == 0) {
+ *ret_cfid = cfid;
++ atomic_inc(&tcon->num_remote_opens);
++ }
+
+ return rc;
+ }
--- /dev/null
+From 3891f6c7655a39065e44980f51ba46bb32be3133 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Wed, 1 Feb 2023 16:21:41 +0100
+Subject: cifs: don't try to use rdma offload on encrypted connections
+
+From: Stefan Metzmacher <metze@samba.org>
+
+commit 3891f6c7655a39065e44980f51ba46bb32be3133 upstream.
+
+The aim of using encryption on a connection is to keep
+the data confidential, so we must not use plaintext rdma offload
+for that data!
+
+It seems that current windows servers and ksmbd would allow
+this, but that's no reason to expose the users data in plaintext!
+And servers hopefully reject this in future.
+
+Note modern windows servers support signed or encrypted offload,
+see MS-SMB2 2.2.3.1.6 SMB2_RDMA_TRANSFORM_CAPABILITIES, but we don't
+support that yet.
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Cc: Steve French <smfrench@gmail.com>
+Cc: Tom Talpey <tom@talpey.com>
+Cc: Long Li <longli@microsoft.com>
+Cc: Namjae Jeon <linkinjeon@kernel.org>
+Cc: David Howells <dhowells@redhat.com>
+Cc: linux-cifs@vger.kernel.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2pdu.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -4081,6 +4081,10 @@ static inline bool smb3_use_rdma_offload
+ if (server->sign)
+ return false;
+
++ /* we don't support encrypted offload yet */
++ if (smb3_encryption_required(tcon))
++ return false;
++
+ /* offload also has its overhead, so only do it if desired */
+ if (io_parms->length < server->smbd_conn->rdma_readwrite_threshold)
+ return false;
--- /dev/null
+From d99e86ebde2d7b3a04190f8d14de5bf6814bf10f Mon Sep 17 00:00:00 2001
+From: Paulo Alcantara <pc@manguebit.com>
+Date: Thu, 16 Feb 2023 15:33:22 -0300
+Subject: cifs: fix mount on old smb servers
+
+From: Paulo Alcantara <pc@manguebit.com>
+
+commit d99e86ebde2d7b3a04190f8d14de5bf6814bf10f upstream.
+
+The client was sending rfc1002 session request packet with a wrong
+length field set, therefore failing to mount shares against old SMB
+servers over port 139.
+
+Fix this by calculating the correct length as specified in rfc1002.
+
+Fixes: d7173623bf0b ("cifs: use ALIGN() and round_up() macros")
+Cc: stable@vger.kernel.org
+Signed-off-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
+Reviewed-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/connect.c | 94 ++++++++++++++++++-----------------------------
+ 1 file changed, 35 insertions(+), 59 deletions(-)
+
+diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
+index b2a04b4e89a5..af49ae53aaf4 100644
+--- a/fs/cifs/connect.c
++++ b/fs/cifs/connect.c
+@@ -2843,72 +2843,48 @@ ip_rfc1001_connect(struct TCP_Server_Info *server)
+ * negprot - BB check reconnection in case where second
+ * sessinit is sent but no second negprot
+ */
+- struct rfc1002_session_packet *ses_init_buf;
+- unsigned int req_noscope_len;
+- struct smb_hdr *smb_buf;
++ struct rfc1002_session_packet req = {};
++ struct smb_hdr *smb_buf = (struct smb_hdr *)&req;
++ unsigned int len;
+
+- ses_init_buf = kzalloc(sizeof(struct rfc1002_session_packet),
+- GFP_KERNEL);
++ req.trailer.session_req.called_len = sizeof(req.trailer.session_req.called_name);
+
+- if (ses_init_buf) {
+- ses_init_buf->trailer.session_req.called_len = 32;
++ if (server->server_RFC1001_name[0] != 0)
++ rfc1002mangle(req.trailer.session_req.called_name,
++ server->server_RFC1001_name,
++ RFC1001_NAME_LEN_WITH_NULL);
++ else
++ rfc1002mangle(req.trailer.session_req.called_name,
++ DEFAULT_CIFS_CALLED_NAME,
++ RFC1001_NAME_LEN_WITH_NULL);
+
+- if (server->server_RFC1001_name[0] != 0)
+- rfc1002mangle(ses_init_buf->trailer.
+- session_req.called_name,
+- server->server_RFC1001_name,
+- RFC1001_NAME_LEN_WITH_NULL);
+- else
+- rfc1002mangle(ses_init_buf->trailer.
+- session_req.called_name,
+- DEFAULT_CIFS_CALLED_NAME,
+- RFC1001_NAME_LEN_WITH_NULL);
++ req.trailer.session_req.calling_len = sizeof(req.trailer.session_req.calling_name);
+
+- ses_init_buf->trailer.session_req.calling_len = 32;
++ /* calling name ends in null (byte 16) from old smb convention */
++ if (server->workstation_RFC1001_name[0] != 0)
++ rfc1002mangle(req.trailer.session_req.calling_name,
++ server->workstation_RFC1001_name,
++ RFC1001_NAME_LEN_WITH_NULL);
++ else
++ rfc1002mangle(req.trailer.session_req.calling_name,
++ "LINUX_CIFS_CLNT",
++ RFC1001_NAME_LEN_WITH_NULL);
+
+- /*
+- * calling name ends in null (byte 16) from old smb
+- * convention.
+- */
+- if (server->workstation_RFC1001_name[0] != 0)
+- rfc1002mangle(ses_init_buf->trailer.
+- session_req.calling_name,
+- server->workstation_RFC1001_name,
+- RFC1001_NAME_LEN_WITH_NULL);
+- else
+- rfc1002mangle(ses_init_buf->trailer.
+- session_req.calling_name,
+- "LINUX_CIFS_CLNT",
+- RFC1001_NAME_LEN_WITH_NULL);
+-
+- ses_init_buf->trailer.session_req.scope1 = 0;
+- ses_init_buf->trailer.session_req.scope2 = 0;
+- smb_buf = (struct smb_hdr *)ses_init_buf;
+-
+- /* sizeof RFC1002_SESSION_REQUEST with no scopes */
+- req_noscope_len = sizeof(struct rfc1002_session_packet) - 2;
+-
+- /* == cpu_to_be32(0x81000044) */
+- smb_buf->smb_buf_length =
+- cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | req_noscope_len);
+- rc = smb_send(server, smb_buf, 0x44);
+- kfree(ses_init_buf);
+- /*
+- * RFC1001 layer in at least one server
+- * requires very short break before negprot
+- * presumably because not expecting negprot
+- * to follow so fast. This is a simple
+- * solution that works without
+- * complicating the code and causes no
+- * significant slowing down on mount
+- * for everyone else
+- */
+- usleep_range(1000, 2000);
+- }
+ /*
+- * else the negprot may still work without this
+- * even though malloc failed
++ * As per rfc1002, @len must be the number of bytes that follows the
++ * length field of a rfc1002 session request payload.
++ */
++ len = sizeof(req) - offsetof(struct rfc1002_session_packet, trailer.session_req);
++
++ smb_buf->smb_buf_length = cpu_to_be32((RFC1002_SESSION_REQUEST << 24) | len);
++ rc = smb_send(server, smb_buf, len);
++ /*
++ * RFC1001 layer in at least one server requires very short break before
++ * negprot presumably because not expecting negprot to follow so fast.
++ * This is a simple solution that works without complicating the code
++ * and causes no significant slowing down on mount for everyone else
+ */
++ usleep_range(1000, 2000);
+
+ return rc;
+ }
+--
+2.39.2
+
--- /dev/null
+From d447e794a37288ec7a080aa1b044a8d9deebbab7 Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Wed, 11 Jan 2023 12:37:58 +0100
+Subject: cifs: Fix uninitialized memory read in smb3_qfs_tcon()
+
+From: Volker Lendecke <vl@samba.org>
+
+commit d447e794a37288ec7a080aa1b044a8d9deebbab7 upstream.
+
+oparms was not fully initialized
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Reviewed-by: Paulo Alcantara (SUSE) <pc@cjr.nz>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2ops.c | 13 +++++++------
+ 1 file changed, 7 insertions(+), 6 deletions(-)
+
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -729,12 +729,13 @@ smb3_qfs_tcon(const unsigned int xid, st
+ struct cifs_fid fid;
+ struct cached_fid *cfid = NULL;
+
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = open_cached_dir(xid, tcon, "", cifs_sb, false, &cfid);
+ if (rc == 0)
--- /dev/null
+From de036dcaca65cf94bf7ff09c571c077f02bc92b4 Mon Sep 17 00:00:00 2001
+From: Volker Lendecke <vl@samba.org>
+Date: Wed, 11 Jan 2023 12:37:58 +0100
+Subject: cifs: Fix uninitialized memory reads for oparms.mode
+
+From: Volker Lendecke <vl@samba.org>
+
+commit de036dcaca65cf94bf7ff09c571c077f02bc92b4 upstream.
+
+Use a struct assignment with implicit member initialization
+
+Signed-off-by: Volker Lendecke <vl@samba.org>
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cached_dir.c | 13 +--
+ fs/cifs/cifsacl.c | 34 ++++-----
+ fs/cifs/cifssmb.c | 17 ++--
+ fs/cifs/dir.c | 19 ++---
+ fs/cifs/file.c | 35 +++++----
+ fs/cifs/inode.c | 53 +++++++-------
+ fs/cifs/link.c | 66 +++++++++--------
+ fs/cifs/smb1ops.c | 72 ++++++++++---------
+ fs/cifs/smb2inode.c | 17 ++--
+ fs/cifs/smb2ops.c | 191 ++++++++++++++++++++++++++-------------------------
+ 10 files changed, 274 insertions(+), 243 deletions(-)
+
+--- a/fs/cifs/cached_dir.c
++++ b/fs/cifs/cached_dir.c
+@@ -181,12 +181,13 @@ int open_cached_dir(unsigned int xid, st
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- oparms.tcon = tcon;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE);
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.fid = pfid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_FILE),
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .fid = pfid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+--- a/fs/cifs/cifsacl.c
++++ b/fs/cifs/cifsacl.c
+@@ -1423,14 +1423,15 @@ static struct cifs_ntsd *get_cifs_acl_by
+ tcon = tlink_tcon(tlink);
+ xid = get_xid();
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = READ_CONTROL;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = READ_CONTROL,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .disposition = FILE_OPEN,
++ .path = path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (!rc) {
+@@ -1489,14 +1490,15 @@ int set_cifs_acl(struct cifs_ntsd *pnnts
+ else
+ access_flags = WRITE_DAC;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = access_flags;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = access_flags,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .disposition = FILE_OPEN,
++ .path = path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc) {
+--- a/fs/cifs/cifssmb.c
++++ b/fs/cifs/cifssmb.c
+@@ -5314,14 +5314,15 @@ CIFSSMBSetPathInfoFB(const unsigned int
+ struct cifs_fid fid;
+ int rc;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_WRITE;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = fileName;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_WRITE,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .disposition = FILE_OPEN,
++ .path = fileName,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc)
+--- a/fs/cifs/dir.c
++++ b/fs/cifs/dir.c
+@@ -295,15 +295,16 @@ static int cifs_do_create(struct inode *
+ if (!tcon->unix_ext && (mode & S_IWUGO) == 0)
+ create_options |= CREATE_OPTION_READONLY;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = desired_access;
+- oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- oparms.disposition = disposition;
+- oparms.path = full_path;
+- oparms.fid = fid;
+- oparms.reconnect = false;
+- oparms.mode = mode;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = desired_access,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .disposition = disposition,
++ .path = full_path,
++ .fid = fid,
++ .mode = mode,
++ };
+ rc = server->ops->open(xid, &oparms, oplock, buf);
+ if (rc) {
+ cifs_dbg(FYI, "cifs_create returned 0x%x\n", rc);
+--- a/fs/cifs/file.c
++++ b/fs/cifs/file.c
+@@ -260,14 +260,15 @@ static int cifs_nt_open(const char *full
+ if (f_flags & O_DIRECT)
+ create_options |= CREATE_NO_BUFFER;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = desired_access;
+- oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- oparms.disposition = disposition;
+- oparms.path = full_path;
+- oparms.fid = fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = desired_access,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .disposition = disposition,
++ .path = full_path,
++ .fid = fid,
++ };
+
+ rc = server->ops->open(xid, &oparms, oplock, buf);
+ if (rc)
+@@ -848,14 +849,16 @@ cifs_reopen_file(struct cifsFileInfo *cf
+ if (server->ops->get_lease_key)
+ server->ops->get_lease_key(inode, &cfile->fid);
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = desired_access;
+- oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- oparms.disposition = disposition;
+- oparms.path = full_path;
+- oparms.fid = &cfile->fid;
+- oparms.reconnect = true;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = desired_access,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .disposition = disposition,
++ .path = full_path,
++ .fid = &cfile->fid,
++ .reconnect = true,
++ };
+
+ /*
+ * Can not refresh inode by passing in file_info buf to be returned by
+--- a/fs/cifs/inode.c
++++ b/fs/cifs/inode.c
+@@ -508,14 +508,15 @@ cifs_sfu_type(struct cifs_fattr *fattr,
+ return PTR_ERR(tlink);
+ tcon = tlink_tcon(tlink);
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_READ;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_READ,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .path = path,
++ .fid = &fid,
++ };
+
+ if (tcon->ses->server->oplocks)
+ oplock = REQ_OPLOCK;
+@@ -1513,14 +1514,15 @@ cifs_rename_pending_delete(const char *f
+ goto out;
+ }
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = DELETE | FILE_WRITE_ATTRIBUTES;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = DELETE | FILE_WRITE_ATTRIBUTES,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc != 0)
+@@ -2107,15 +2109,16 @@ cifs_do_rename(const unsigned int xid, s
+ if (to_dentry->d_parent != from_dentry->d_parent)
+ goto do_rename_exit;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- /* open the file to be renamed -- we need DELETE perms */
+- oparms.desired_access = DELETE;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = from_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ /* open the file to be renamed -- we need DELETE perms */
++ .desired_access = DELETE,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .path = from_path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc == 0) {
+--- a/fs/cifs/link.c
++++ b/fs/cifs/link.c
+@@ -271,14 +271,15 @@ cifs_query_mf_symlink(unsigned int xid,
+ int buf_type = CIFS_NO_BUFFER;
+ FILE_ALL_INFO file_info;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_READ;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_READ,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .path = path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, &file_info);
+ if (rc)
+@@ -313,14 +314,15 @@ cifs_create_mf_symlink(unsigned int xid,
+ struct cifs_open_parms oparms;
+ struct cifs_io_parms io_parms = {0};
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_WRITE;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_CREATE;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_WRITE,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_CREATE,
++ .path = path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc)
+@@ -355,13 +357,14 @@ smb3_query_mf_symlink(unsigned int xid,
+ __u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
+ struct smb2_file_all_info *pfile_info = NULL;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_READ;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_READ,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .fid = &fid,
++ };
+
+ utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+ if (utf16_path == NULL)
+@@ -421,14 +424,15 @@ smb3_create_mf_symlink(unsigned int xid,
+ if (!utf16_path)
+ return -ENOMEM;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_WRITE;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_CREATE;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
+- oparms.mode = 0644;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_WRITE,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_CREATE,
++ .fid = &fid,
++ .mode = 0644,
++ };
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
+ NULL, NULL);
+--- a/fs/cifs/smb1ops.c
++++ b/fs/cifs/smb1ops.c
+@@ -576,14 +576,15 @@ static int cifs_query_path_info(const un
+ if (!(le32_to_cpu(fi.Attributes) & ATTR_REPARSE))
+ return 0;
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .disposition = FILE_OPEN,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ /* Need to check if this is a symbolic link or not */
+ tmprc = CIFS_open(xid, &oparms, &oplock, NULL);
+@@ -823,14 +824,15 @@ smb_set_file_info(struct inode *inode, c
+ goto out;
+ }
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = SYNCHRONIZE | FILE_WRITE_ATTRIBUTES,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR),
++ .disposition = FILE_OPEN,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ cifs_dbg(FYI, "calling SetFileInfo since SetPathInfo for times not supported by this server\n");
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+@@ -998,15 +1000,16 @@ cifs_query_symlink(const unsigned int xi
+ goto out;
+ }
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.create_options = cifs_create_options(cifs_sb,
+- OPEN_REPARSE_POINT);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .create_options = cifs_create_options(cifs_sb,
++ OPEN_REPARSE_POINT),
++ .disposition = FILE_OPEN,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ rc = CIFS_open(xid, &oparms, &oplock, NULL);
+ if (rc)
+@@ -1115,15 +1118,16 @@ cifs_make_node(unsigned int xid, struct
+
+ cifs_dbg(FYI, "sfu compat create special file\n");
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_WRITE;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
+- CREATE_OPTION_SPECIAL);
+- oparms.disposition = FILE_CREATE;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_WRITE,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
++ CREATE_OPTION_SPECIAL),
++ .disposition = FILE_CREATE,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ if (tcon->ses->server->oplocks)
+ oplock = REQ_OPLOCK;
+--- a/fs/cifs/smb2inode.c
++++ b/fs/cifs/smb2inode.c
+@@ -104,14 +104,15 @@ static int smb2_compound_op(const unsign
+ goto finished;
+ }
+
+- vars->oparms.tcon = tcon;
+- vars->oparms.desired_access = desired_access;
+- vars->oparms.disposition = create_disposition;
+- vars->oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- vars->oparms.fid = &fid;
+- vars->oparms.reconnect = false;
+- vars->oparms.mode = mode;
+- vars->oparms.cifs_sb = cifs_sb;
++ vars->oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = desired_access,
++ .disposition = create_disposition,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .fid = &fid,
++ .mode = mode,
++ .cifs_sb = cifs_sb,
++ };
+
+ rqst[num_rqst].rq_iov = &vars->open_iov[0];
+ rqst[num_rqst].rq_nvec = SMB2_CREATE_IOV_SIZE;
+--- a/fs/cifs/smb2ops.c
++++ b/fs/cifs/smb2ops.c
+@@ -772,12 +772,13 @@ smb2_qfs_tcon(const unsigned int xid, st
+ struct cifs_open_parms oparms;
+ struct cifs_fid fid;
+
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
+ NULL, NULL);
+@@ -817,12 +818,13 @@ smb2_is_path_accessible(const unsigned i
+ if (!utf16_path)
+ return -ENOMEM;
+
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
+ &err_iov, &err_buftype);
+@@ -1098,13 +1100,13 @@ smb2_set_ea(const unsigned int xid, stru
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- memset(&oparms, 0, sizeof(oparms));
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_WRITE_EA;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_WRITE_EA,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+@@ -1454,12 +1456,12 @@ smb2_ioctl_query_info(const unsigned int
+ rqst[0].rq_iov = &vars->open_iov[0];
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- memset(&oparms, 0, sizeof(oparms));
+- oparms.tcon = tcon;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .fid = &fid,
++ };
+
+ if (qi.flags & PASSTHRU_FSCTL) {
+ switch (qi.info_type & FSCTL_DEVICE_ACCESS_MASK) {
+@@ -2089,12 +2091,13 @@ smb3_notify(const unsigned int xid, stru
+ }
+
+ tcon = cifs_sb_master_tcon(cifs_sb);
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL, NULL,
+ NULL);
+@@ -2160,12 +2163,13 @@ smb2_query_dir_first(const unsigned int
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES | FILE_READ_DATA,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = fid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+@@ -2491,12 +2495,13 @@ smb2_query_info_compound(const unsigned
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- oparms.tcon = tcon;
+- oparms.desired_access = desired_access;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = desired_access,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+@@ -2624,12 +2629,13 @@ smb311_queryfs(const unsigned int xid, s
+ if (!tcon->posix_extensions)
+ return smb2_queryfs(xid, tcon, cifs_sb, buf);
+
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open(xid, &oparms, &srch_path, &oplock, NULL, NULL,
+ NULL, NULL);
+@@ -2917,13 +2923,13 @@ smb2_query_symlink(const unsigned int xi
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- memset(&oparms, 0, sizeof(oparms));
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, create_options);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, create_options),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+@@ -3057,13 +3063,13 @@ smb2_query_reparse_tag(const unsigned in
+ rqst[0].rq_iov = open_iov;
+ rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
+
+- memset(&oparms, 0, sizeof(oparms));
+- oparms.tcon = tcon;
+- oparms.desired_access = FILE_READ_ATTRIBUTES;
+- oparms.disposition = FILE_OPEN;
+- oparms.create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT);
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = FILE_READ_ATTRIBUTES,
++ .disposition = FILE_OPEN,
++ .create_options = cifs_create_options(cifs_sb, OPEN_REPARSE_POINT),
++ .fid = &fid,
++ };
+
+ rc = SMB2_open_init(tcon, server,
+ &rqst[0], &oplock, &oparms, utf16_path);
+@@ -3197,17 +3203,20 @@ get_smb2_acl_by_path(struct cifs_sb_info
+ return ERR_PTR(rc);
+ }
+
+- oparms.tcon = tcon;
+- oparms.desired_access = READ_CONTROL;
+- oparms.disposition = FILE_OPEN;
+- /*
+- * When querying an ACL, even if the file is a symlink we want to open
+- * the source not the target, and so the protocol requires that the
+- * client specify this flag when opening a reparse point
+- */
+- oparms.create_options = cifs_create_options(cifs_sb, 0) | OPEN_REPARSE_POINT;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = READ_CONTROL,
++ .disposition = FILE_OPEN,
++ /*
++ * When querying an ACL, even if the file is a symlink
++ * we want to open the source not the target, and so
++ * the protocol requires that the client specify this
++ * flag when opening a reparse point
++ */
++ .create_options = cifs_create_options(cifs_sb, 0) |
++ OPEN_REPARSE_POINT,
++ .fid = &fid,
++ };
+
+ if (info & SACL_SECINFO)
+ oparms.desired_access |= SYSTEM_SECURITY;
+@@ -3266,13 +3275,14 @@ set_smb2_acl(struct cifs_ntsd *pnntsd, _
+ return rc;
+ }
+
+- oparms.tcon = tcon;
+- oparms.desired_access = access_flags;
+- oparms.create_options = cifs_create_options(cifs_sb, 0);
+- oparms.disposition = FILE_OPEN;
+- oparms.path = path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .desired_access = access_flags,
++ .create_options = cifs_create_options(cifs_sb, 0),
++ .disposition = FILE_OPEN,
++ .path = path,
++ .fid = &fid,
++ };
+
+ rc = SMB2_open(xid, &oparms, utf16_path, &oplock, NULL, NULL,
+ NULL, NULL);
+@@ -5134,15 +5144,16 @@ smb2_make_node(unsigned int xid, struct
+
+ cifs_dbg(FYI, "sfu compat create special file\n");
+
+- oparms.tcon = tcon;
+- oparms.cifs_sb = cifs_sb;
+- oparms.desired_access = GENERIC_WRITE;
+- oparms.create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
+- CREATE_OPTION_SPECIAL);
+- oparms.disposition = FILE_CREATE;
+- oparms.path = full_path;
+- oparms.fid = &fid;
+- oparms.reconnect = false;
++ oparms = (struct cifs_open_parms) {
++ .tcon = tcon,
++ .cifs_sb = cifs_sb,
++ .desired_access = GENERIC_WRITE,
++ .create_options = cifs_create_options(cifs_sb, CREATE_NOT_DIR |
++ CREATE_OPTION_SPECIAL),
++ .disposition = FILE_CREATE,
++ .path = full_path,
++ .fid = &fid,
++ };
+
+ if (tcon->ses->server->oplocks)
+ oplock = REQ_OPLOCK;
--- /dev/null
+From d643a8a446fc46c06837d08a056f69da2ff16025 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Wed, 1 Feb 2023 16:21:39 +0100
+Subject: cifs: introduce cifs_io_parms in smb2_async_writev()
+
+From: Stefan Metzmacher <metze@samba.org>
+
+commit d643a8a446fc46c06837d08a056f69da2ff16025 upstream.
+
+This will simplify the following changes and makes it easy to get
+in passed in from the caller in future.
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Cc: Steve French <smfrench@gmail.com>
+Cc: Tom Talpey <tom@talpey.com>
+Cc: Long Li <longli@microsoft.com>
+Cc: Namjae Jeon <linkinjeon@kernel.org>
+Cc: David Howells <dhowells@redhat.com>
+Cc: linux-cifs@vger.kernel.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2pdu.c | 53 +++++++++++++++++++++++++++++++++++++++--------------
+ 1 file changed, 39 insertions(+), 14 deletions(-)
+
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -4504,10 +4504,27 @@ smb2_async_writev(struct cifs_writedata
+ struct kvec iov[1];
+ struct smb_rqst rqst = { };
+ unsigned int total_len;
++ struct cifs_io_parms _io_parms;
++ struct cifs_io_parms *io_parms = NULL;
+
+ if (!wdata->server)
+ server = wdata->server = cifs_pick_channel(tcon->ses);
+
++ /*
++ * in future we may get cifs_io_parms passed in from the caller,
++ * but for now we construct it here...
++ */
++ _io_parms = (struct cifs_io_parms) {
++ .tcon = tcon,
++ .server = server,
++ .offset = wdata->offset,
++ .length = wdata->bytes,
++ .persistent_fid = wdata->cfile->fid.persistent_fid,
++ .volatile_fid = wdata->cfile->fid.volatile_fid,
++ .pid = wdata->pid,
++ };
++ io_parms = &_io_parms;
++
+ rc = smb2_plain_req_init(SMB2_WRITE, tcon, server,
+ (void **) &req, &total_len);
+ if (rc)
+@@ -4517,26 +4534,31 @@ smb2_async_writev(struct cifs_writedata
+ flags |= CIFS_TRANSFORM_REQ;
+
+ shdr = (struct smb2_hdr *)req;
+- shdr->Id.SyncId.ProcessId = cpu_to_le32(wdata->cfile->pid);
++ shdr->Id.SyncId.ProcessId = cpu_to_le32(io_parms->pid);
+
+- req->PersistentFileId = wdata->cfile->fid.persistent_fid;
+- req->VolatileFileId = wdata->cfile->fid.volatile_fid;
++ req->PersistentFileId = io_parms->persistent_fid;
++ req->VolatileFileId = io_parms->volatile_fid;
+ req->WriteChannelInfoOffset = 0;
+ req->WriteChannelInfoLength = 0;
+ req->Channel = 0;
+- req->Offset = cpu_to_le64(wdata->offset);
++ req->Offset = cpu_to_le64(io_parms->offset);
+ req->DataOffset = cpu_to_le16(
+ offsetof(struct smb2_write_req, Buffer));
+ req->RemainingBytes = 0;
+
+- trace_smb3_write_enter(0 /* xid */, wdata->cfile->fid.persistent_fid,
+- tcon->tid, tcon->ses->Suid, wdata->offset, wdata->bytes);
++ trace_smb3_write_enter(0 /* xid */,
++ io_parms->persistent_fid,
++ io_parms->tcon->tid,
++ io_parms->tcon->ses->Suid,
++ io_parms->offset,
++ io_parms->length);
++
+ #ifdef CONFIG_CIFS_SMB_DIRECT
+ /*
+ * If we want to do a server RDMA read, fill in and append
+ * smbd_buffer_descriptor_v1 to the end of write request
+ */
+- if (server->rdma && !server->sign && wdata->bytes >=
++ if (server->rdma && !server->sign && io_parms->length >=
+ server->smbd_conn->rdma_readwrite_threshold) {
+
+ struct smbd_buffer_descriptor_v1 *v1;
+@@ -4590,14 +4612,14 @@ smb2_async_writev(struct cifs_writedata
+ }
+ #endif
+ cifs_dbg(FYI, "async write at %llu %u bytes\n",
+- wdata->offset, wdata->bytes);
++ io_parms->offset, io_parms->length);
+
+ #ifdef CONFIG_CIFS_SMB_DIRECT
+ /* For RDMA read, I/O size is in RemainingBytes not in Length */
+ if (!wdata->mr)
+- req->Length = cpu_to_le32(wdata->bytes);
++ req->Length = cpu_to_le32(io_parms->length);
+ #else
+- req->Length = cpu_to_le32(wdata->bytes);
++ req->Length = cpu_to_le32(io_parms->length);
+ #endif
+
+ if (wdata->credits.value > 0) {
+@@ -4605,7 +4627,7 @@ smb2_async_writev(struct cifs_writedata
+ SMB2_MAX_BUFFER_SIZE));
+ shdr->CreditRequest = cpu_to_le16(le16_to_cpu(shdr->CreditCharge) + 8);
+
+- rc = adjust_credits(server, &wdata->credits, wdata->bytes);
++ rc = adjust_credits(server, &wdata->credits, io_parms->length);
+ if (rc)
+ goto async_writev_out;
+
+@@ -4618,9 +4640,12 @@ smb2_async_writev(struct cifs_writedata
+
+ if (rc) {
+ trace_smb3_write_err(0 /* no xid */,
+- req->PersistentFileId,
+- tcon->tid, tcon->ses->Suid, wdata->offset,
+- wdata->bytes, rc);
++ io_parms->persistent_fid,
++ io_parms->tcon->tid,
++ io_parms->tcon->ses->Suid,
++ io_parms->offset,
++ io_parms->length,
++ rc);
+ kref_put(&wdata->refcount, release);
+ cifs_stats_fail_inc(tcon, SMB2_WRITE_HE);
+ }
--- /dev/null
+From 8e843bf38f7be0766642a91523cfa65f2b021a8a Mon Sep 17 00:00:00 2001
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+Date: Fri, 17 Feb 2023 13:35:01 +1000
+Subject: cifs: return a single-use cfid if we did not get a lease
+
+From: Ronnie Sahlberg <lsahlber@redhat.com>
+
+commit 8e843bf38f7be0766642a91523cfa65f2b021a8a upstream.
+
+If we did not get a lease we can still return a single use cfid to the caller.
+The cfid will not have has_lease set and will thus not be shared with any
+other concurrent users and will be freed immediately when the caller
+drops the handle.
+
+This avoids extra roundtrips for servers that do not support directory leases
+where they would first fail to get a cfid with a lease and then fallback
+to try a normal SMB2_open()
+
+Signed-off-by: Ronnie Sahlberg <lsahlber@redhat.com>
+Cc: stable@vger.kernel.org
+Reviewed-by: Bharath SM <bharathsm@microsoft.com>
+Reviewed-by: Paulo Alcantara (SUSE) <pc@manguebit.com>
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/cached_dir.c | 16 +++++++++++++---
+ 1 file changed, 13 insertions(+), 3 deletions(-)
+
+--- a/fs/cifs/cached_dir.c
++++ b/fs/cifs/cached_dir.c
+@@ -14,6 +14,7 @@
+
+ static struct cached_fid *init_cached_dir(const char *path);
+ static void free_cached_dir(struct cached_fid *cfid);
++static void smb2_close_cached_fid(struct kref *ref);
+
+ static struct cached_fid *find_or_create_cached_dir(struct cached_fids *cfids,
+ const char *path,
+@@ -221,6 +222,7 @@ int open_cached_dir(unsigned int xid, st
+ }
+ goto oshr_free;
+ }
++ cfid->tcon = tcon;
+ cfid->is_open = true;
+
+ o_rsp = (struct smb2_create_rsp *)rsp_iov[0].iov_base;
+@@ -233,7 +235,6 @@ int open_cached_dir(unsigned int xid, st
+ if (o_rsp->OplockLevel != SMB2_OPLOCK_LEVEL_LEASE)
+ goto oshr_free;
+
+-
+ smb2_parse_contexts(server, o_rsp,
+ &oparms.fid->epoch,
+ oparms.fid->lease_key, &oplock,
+@@ -260,7 +261,6 @@ int open_cached_dir(unsigned int xid, st
+ }
+ }
+ cfid->dentry = dentry;
+- cfid->tcon = tcon;
+ cfid->time = jiffies;
+ cfid->has_lease = true;
+
+@@ -271,7 +271,7 @@ oshr_free:
+ free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
+ free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
+ spin_lock(&cfids->cfid_list_lock);
+- if (!cfid->has_lease) {
++ if (rc && !cfid->has_lease) {
+ if (cfid->on_list) {
+ list_del(&cfid->entry);
+ cfid->on_list = false;
+@@ -280,6 +280,15 @@ oshr_free:
+ rc = -ENOENT;
+ }
+ spin_unlock(&cfids->cfid_list_lock);
++ if (!rc && !cfid->has_lease) {
++ /*
++ * We are guaranteed to have two references at this point.
++ * One for the caller and one for a potential lease.
++ * Release the Lease-ref so that the directory will be closed
++ * when the caller closes the cached handle.
++ */
++ kref_put(&cfid->refcount, smb2_close_cached_fid);
++ }
+ if (rc) {
+ if (cfid->is_open)
+ SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
+@@ -340,6 +349,7 @@ smb2_close_cached_fid(struct kref *ref)
+ if (cfid->is_open) {
+ SMB2_close(0, cfid->tcon, cfid->fid.persistent_fid,
+ cfid->fid.volatile_fid);
++ atomic_dec(&cfid->tcon->num_remote_opens);
+ }
+
+ free_cached_dir(cfid);
--- /dev/null
+From a6559cc1d35d3eeafb0296aca347b2f745a28a74 Mon Sep 17 00:00:00 2001
+From: Stefan Metzmacher <metze@samba.org>
+Date: Wed, 1 Feb 2023 16:21:40 +0100
+Subject: cifs: split out smb3_use_rdma_offload() helper
+
+From: Stefan Metzmacher <metze@samba.org>
+
+commit a6559cc1d35d3eeafb0296aca347b2f745a28a74 upstream.
+
+We should have the logic to decide if we want rdma offload
+in a single spot in order to advance it in future.
+
+Signed-off-by: Stefan Metzmacher <metze@samba.org>
+Cc: Steve French <smfrench@gmail.com>
+Cc: Tom Talpey <tom@talpey.com>
+Cc: Long Li <longli@microsoft.com>
+Cc: Namjae Jeon <linkinjeon@kernel.org>
+Cc: David Howells <dhowells@redhat.com>
+Cc: linux-cifs@vger.kernel.org
+Cc: stable@vger.kernel.org
+Signed-off-by: Steve French <stfrench@microsoft.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ fs/cifs/smb2pdu.c | 34 ++++++++++++++++++++++++++++------
+ 1 file changed, 28 insertions(+), 6 deletions(-)
+
+--- a/fs/cifs/smb2pdu.c
++++ b/fs/cifs/smb2pdu.c
+@@ -4063,6 +4063,32 @@ SMB2_flush(const unsigned int xid, struc
+ return rc;
+ }
+
++#ifdef CONFIG_CIFS_SMB_DIRECT
++static inline bool smb3_use_rdma_offload(struct cifs_io_parms *io_parms)
++{
++ struct TCP_Server_Info *server = io_parms->server;
++ struct cifs_tcon *tcon = io_parms->tcon;
++
++ /* we can only offload if we're connected */
++ if (!server || !tcon)
++ return false;
++
++ /* we can only offload on an rdma connection */
++ if (!server->rdma || !server->smbd_conn)
++ return false;
++
++ /* we don't support signed offload yet */
++ if (server->sign)
++ return false;
++
++ /* offload also has its overhead, so only do it if desired */
++ if (io_parms->length < server->smbd_conn->rdma_readwrite_threshold)
++ return false;
++
++ return true;
++}
++#endif /* CONFIG_CIFS_SMB_DIRECT */
++
+ /*
+ * To form a chain of read requests, any read requests after the first should
+ * have the end_of_chain boolean set to true.
+@@ -4106,9 +4132,7 @@ smb2_new_read_req(void **buf, unsigned i
+ * If we want to do a RDMA write, fill in and append
+ * smbd_buffer_descriptor_v1 to the end of read request
+ */
+- if (server->rdma && rdata && !server->sign &&
+- rdata->bytes >= server->smbd_conn->rdma_readwrite_threshold) {
+-
++ if (smb3_use_rdma_offload(io_parms)) {
+ struct smbd_buffer_descriptor_v1 *v1;
+ bool need_invalidate = server->dialect == SMB30_PROT_ID;
+
+@@ -4558,9 +4582,7 @@ smb2_async_writev(struct cifs_writedata
+ * If we want to do a server RDMA read, fill in and append
+ * smbd_buffer_descriptor_v1 to the end of write request
+ */
+- if (server->rdma && !server->sign && io_parms->length >=
+- server->smbd_conn->rdma_readwrite_threshold) {
+-
++ if (smb3_use_rdma_offload(io_parms)) {
+ struct smbd_buffer_descriptor_v1 *v1;
+ bool need_invalidate = server->dialect == SMB30_PROT_ID;
+
--- /dev/null
+From f2d3155e2a6bac44d16f04415a321e8707d895c6 Mon Sep 17 00:00:00 2001
+From: Nico Boehr <nrb@linux.ibm.com>
+Date: Fri, 27 Jan 2023 15:05:32 +0100
+Subject: KVM: s390: disable migration mode when dirty tracking is disabled
+
+From: Nico Boehr <nrb@linux.ibm.com>
+
+commit f2d3155e2a6bac44d16f04415a321e8707d895c6 upstream.
+
+Migration mode is a VM attribute which enables tracking of changes in
+storage attributes (PGSTE). It assumes dirty tracking is enabled on all
+memslots to keep a dirty bitmap of pages with changed storage attributes.
+
+When enabling migration mode, we currently check that dirty tracking is
+enabled for all memslots. However, userspace can disable dirty tracking
+without disabling migration mode.
+
+Since migration mode is pointless with dirty tracking disabled, disable
+migration mode whenever userspace disables dirty tracking on any slot.
+
+Also update the documentation to clarify that dirty tracking must be
+enabled when enabling migration mode, which is already enforced by the
+code in kvm_s390_vm_start_migration().
+
+Also highlight in the documentation for KVM_S390_GET_CMMA_BITS that it
+can now fail with -EINVAL when dirty tracking is disabled while
+migration mode is on. Move all the error codes to a table so this stays
+readable.
+
+To disable migration mode, slots_lock should be held, which is taken
+in kvm_set_memory_region() and thus held in
+kvm_arch_prepare_memory_region().
+
+Restructure the prepare code a bit so all the sanity checking is done
+before disabling migration mode. This ensures migration mode isn't
+disabled when some sanity check fails.
+
+Cc: stable@vger.kernel.org
+Fixes: 190df4a212a7 ("KVM: s390: CMMA tracking, ESSA emulation, migration mode")
+Signed-off-by: Nico Boehr <nrb@linux.ibm.com>
+Reviewed-by: Janosch Frank <frankja@linux.ibm.com>
+Reviewed-by: Claudio Imbrenda <imbrenda@linux.ibm.com>
+Link: https://lore.kernel.org/r/20230127140532.230651-2-nrb@linux.ibm.com
+Message-Id: <20230127140532.230651-2-nrb@linux.ibm.com>
+[frankja@linux.ibm.com: fixed commit message typo, moved api.rst error table upwards]
+Signed-off-by: Janosch Frank <frankja@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ Documentation/virt/kvm/api.rst | 18 ++++++++-----
+ Documentation/virt/kvm/devices/vm.rst | 4 ++
+ arch/s390/kvm/kvm-s390.c | 47 +++++++++++++++++++++++-----------
+ 3 files changed, 48 insertions(+), 21 deletions(-)
+
+--- a/Documentation/virt/kvm/api.rst
++++ b/Documentation/virt/kvm/api.rst
+@@ -4483,6 +4483,18 @@ not holding a previously reported uncorr
+ :Parameters: struct kvm_s390_cmma_log (in, out)
+ :Returns: 0 on success, a negative value on error
+
++Errors:
++
++ ====== =============================================================
++ ENOMEM not enough memory can be allocated to complete the task
++ ENXIO if CMMA is not enabled
++ EINVAL if KVM_S390_CMMA_PEEK is not set but migration mode was not enabled
++ EINVAL if KVM_S390_CMMA_PEEK is not set but dirty tracking has been
++ disabled (and thus migration mode was automatically disabled)
++ EFAULT if the userspace address is invalid or if no page table is
++ present for the addresses (e.g. when using hugepages).
++ ====== =============================================================
++
+ This ioctl is used to get the values of the CMMA bits on the s390
+ architecture. It is meant to be used in two scenarios:
+
+@@ -4563,12 +4575,6 @@ mask is unused.
+
+ values points to the userspace buffer where the result will be stored.
+
+-This ioctl can fail with -ENOMEM if not enough memory can be allocated to
+-complete the task, with -ENXIO if CMMA is not enabled, with -EINVAL if
+-KVM_S390_CMMA_PEEK is not set but migration mode was not enabled, with
+--EFAULT if the userspace address is invalid or if no page table is
+-present for the addresses (e.g. when using hugepages).
+-
+ 4.108 KVM_S390_SET_CMMA_BITS
+ ----------------------------
+
+--- a/Documentation/virt/kvm/devices/vm.rst
++++ b/Documentation/virt/kvm/devices/vm.rst
+@@ -302,6 +302,10 @@ Allows userspace to start migration mode
+ Setting this attribute when migration mode is already active will have
+ no effects.
+
++Dirty tracking must be enabled on all memslots, else -EINVAL is returned. When
++dirty tracking is disabled on any memslot, migration mode is automatically
++stopped.
++
+ :Parameters: none
+ :Returns: -ENOMEM if there is not enough free memory to start migration mode;
+ -EINVAL if the state of the VM is invalid (e.g. no memory defined);
+--- a/arch/s390/kvm/kvm-s390.c
++++ b/arch/s390/kvm/kvm-s390.c
+@@ -5579,23 +5579,40 @@ int kvm_arch_prepare_memory_region(struc
+ if (kvm_s390_pv_get_handle(kvm))
+ return -EINVAL;
+
+- if (change == KVM_MR_DELETE || change == KVM_MR_FLAGS_ONLY)
+- return 0;
+-
+- /* A few sanity checks. We can have memory slots which have to be
+- located/ended at a segment boundary (1MB). The memory in userland is
+- ok to be fragmented into various different vmas. It is okay to mmap()
+- and munmap() stuff in this slot after doing this call at any time */
+-
+- if (new->userspace_addr & 0xffffful)
+- return -EINVAL;
++ if (change != KVM_MR_DELETE && change != KVM_MR_FLAGS_ONLY) {
++ /*
++ * A few sanity checks. We can have memory slots which have to be
++ * located/ended at a segment boundary (1MB). The memory in userland is
++ * ok to be fragmented into various different vmas. It is okay to mmap()
++ * and munmap() stuff in this slot after doing this call at any time
++ */
++
++ if (new->userspace_addr & 0xffffful)
++ return -EINVAL;
++
++ size = new->npages * PAGE_SIZE;
++ if (size & 0xffffful)
++ return -EINVAL;
++
++ if ((new->base_gfn * PAGE_SIZE) + size > kvm->arch.mem_limit)
++ return -EINVAL;
++ }
+
+- size = new->npages * PAGE_SIZE;
+- if (size & 0xffffful)
+- return -EINVAL;
++ if (!kvm->arch.migration_mode)
++ return 0;
+
+- if ((new->base_gfn * PAGE_SIZE) + size > kvm->arch.mem_limit)
+- return -EINVAL;
++ /*
++ * Turn off migration mode when:
++ * - userspace creates a new memslot with dirty logging off,
++ * - userspace modifies an existing memslot (MOVE or FLAGS_ONLY) and
++ * dirty logging is turned off.
++ * Migration mode expects dirty page logging being enabled to store
++ * its dirty bitmap.
++ */
++ if (change != KVM_MR_DELETE &&
++ !(new->flags & KVM_MEM_LOG_DIRTY_PAGES))
++ WARN(kvm_s390_vm_stop_migration(kvm),
++ "Failed to stop migration mode");
+
+ return 0;
+ }
--- /dev/null
+From e9c9cb90e76ffaabcc7ca8f275d9e82195fd6367 Mon Sep 17 00:00:00 2001
+From: Ilya Leoshkevich <iii@linux.ibm.com>
+Date: Mon, 23 Jan 2023 22:50:32 +0100
+Subject: s390: discard .interp section
+
+From: Ilya Leoshkevich <iii@linux.ibm.com>
+
+commit e9c9cb90e76ffaabcc7ca8f275d9e82195fd6367 upstream.
+
+When debugging vmlinux with QEMU + GDB, the following GDB error may
+occur:
+
+ (gdb) c
+ Continuing.
+ Warning:
+ Cannot insert breakpoint -1.
+ Cannot access memory at address 0xffffffffffff95c0
+
+ Command aborted.
+ (gdb)
+
+The reason is that, when .interp section is present, GDB tries to
+locate the file specified in it in memory and put a number of
+breakpoints there (see enable_break() function in gdb/solib-svr4.c).
+Sometimes GDB finds a bogus location that matches its heuristics,
+fails to set a breakpoint and stops. This makes further debugging
+impossible.
+
+The .interp section contains misleading information anyway (vmlinux
+does not need ld.so), so fix by discarding it.
+
+Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
+Cc: <stable@vger.kernel.org>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/vmlinux.lds.S | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/s390/kernel/vmlinux.lds.S
++++ b/arch/s390/kernel/vmlinux.lds.S
+@@ -228,5 +228,6 @@ SECTIONS
+ DISCARDS
+ /DISCARD/ : {
+ *(.eh_frame)
++ *(.interp)
+ }
+ }
--- /dev/null
+From 8c42dd78df148c90e48efff204cce38743906a79 Mon Sep 17 00:00:00 2001
+From: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
+Date: Mon, 27 Feb 2023 20:03:00 +0100
+Subject: s390/extmem: return correct segment type in __segment_load()
+
+From: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
+
+commit 8c42dd78df148c90e48efff204cce38743906a79 upstream.
+
+Commit f05f62d04271f ("s390/vmem: get rid of memory segment list")
+reshuffled the call to vmem_add_mapping() in __segment_load(), which now
+overwrites rc after it was set to contain the segment type code.
+
+As result, __segment_load() will now always return 0 on success, which
+corresponds to the segment type code SEG_TYPE_SW, i.e. a writeable
+segment. This results in a kernel crash when loading a read-only segment
+as dcssblk block device, and trying to write to it.
+
+Instead of reshuffling code again, make sure to return the segment type
+on success, and also describe this rather delicate and unexpected logic
+in the function comment. Also initialize new segtype variable with
+invalid value, to prevent possible future confusion.
+
+Fixes: f05f62d04271 ("s390/vmem: get rid of memory segment list")
+Cc: <stable@vger.kernel.org> # 5.9+
+Signed-off-by: Gerald Schaefer <gerald.schaefer@linux.ibm.com>
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/mm/extmem.c | 12 +++++++-----
+ 1 file changed, 7 insertions(+), 5 deletions(-)
+
+--- a/arch/s390/mm/extmem.c
++++ b/arch/s390/mm/extmem.c
+@@ -289,15 +289,17 @@ segment_overlaps_others (struct dcss_seg
+
+ /*
+ * real segment loading function, called from segment_load
++ * Must return either an error code < 0, or the segment type code >= 0
+ */
+ static int
+ __segment_load (char *name, int do_nonshared, unsigned long *addr, unsigned long *end)
+ {
+ unsigned long start_addr, end_addr, dummy;
+ struct dcss_segment *seg;
+- int rc, diag_cc;
++ int rc, diag_cc, segtype;
+
+ start_addr = end_addr = 0;
++ segtype = -1;
+ seg = kmalloc(sizeof(*seg), GFP_KERNEL | GFP_DMA);
+ if (seg == NULL) {
+ rc = -ENOMEM;
+@@ -326,9 +328,9 @@ __segment_load (char *name, int do_nonsh
+ seg->res_name[8] = '\0';
+ strlcat(seg->res_name, " (DCSS)", sizeof(seg->res_name));
+ seg->res->name = seg->res_name;
+- rc = seg->vm_segtype;
+- if (rc == SEG_TYPE_SC ||
+- ((rc == SEG_TYPE_SR || rc == SEG_TYPE_ER) && !do_nonshared))
++ segtype = seg->vm_segtype;
++ if (segtype == SEG_TYPE_SC ||
++ ((segtype == SEG_TYPE_SR || segtype == SEG_TYPE_ER) && !do_nonshared))
+ seg->res->flags |= IORESOURCE_READONLY;
+
+ /* Check for overlapping resources before adding the mapping. */
+@@ -386,7 +388,7 @@ __segment_load (char *name, int do_nonsh
+ out_free:
+ kfree(seg);
+ out:
+- return rc;
++ return rc < 0 ? rc : segtype;
+ }
+
+ /*
--- /dev/null
+From cd57953936f2213dfaccce10d20f396956222c7d Mon Sep 17 00:00:00 2001
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Wed, 1 Mar 2023 17:58:06 +0100
+Subject: s390/kprobes: fix current_kprobe never cleared after kprobes reenter
+
+From: Vasily Gorbik <gor@linux.ibm.com>
+
+commit cd57953936f2213dfaccce10d20f396956222c7d upstream.
+
+Recent test_kprobe_missed kprobes kunit test uncovers the following
+problem. Once kprobe is triggered from another kprobe (kprobe reenter),
+all future kprobes on this cpu are considered as kprobe reenter, thus
+pre_handler and post_handler are not being called and kprobes are counted
+as "missed".
+
+Commit b9599798f953 ("[S390] kprobes: activation and deactivation")
+introduced a simpler scheme for kprobes (de)activation and status
+tracking by using push_kprobe/pop_kprobe, which supposed to work for
+both initial kprobe entry as well as kprobe reentry and helps to avoid
+handling those two cases differently. The problem is that a sequence of
+calls in case of kprobes reenter:
+push_kprobe() <- NULL (current_kprobe)
+push_kprobe() <- kprobe1 (current_kprobe)
+pop_kprobe() -> kprobe1 (current_kprobe)
+pop_kprobe() -> kprobe1 (current_kprobe)
+leaves "kprobe1" as "current_kprobe" on this cpu, instead of setting it
+to NULL. In fact push_kprobe/pop_kprobe can only store a single state
+(there is just one prev_kprobe in kprobe_ctlblk). Which is a hack but
+sufficient, there is no need to have another prev_kprobe just to store
+NULL. To make a simple and backportable fix simply reset "prev_kprobe"
+when kprobe is poped from this "stack". No need to worry about
+"kprobe_status" in this case, because its value is only checked when
+current_kprobe != NULL.
+
+Cc: stable@vger.kernel.org
+Fixes: b9599798f953 ("[S390] kprobes: activation and deactivation")
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/kprobes.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/arch/s390/kernel/kprobes.c
++++ b/arch/s390/kernel/kprobes.c
+@@ -279,6 +279,7 @@ static void pop_kprobe(struct kprobe_ctl
+ {
+ __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
+ kcb->kprobe_status = kcb->prev_kprobe.status;
++ kcb->prev_kprobe.kp = NULL;
+ }
+ NOKPROBE_SYMBOL(pop_kprobe);
+
--- /dev/null
+From 42e19e6f04984088b6f9f0507c4c89a8152d9730 Mon Sep 17 00:00:00 2001
+From: Vasily Gorbik <gor@linux.ibm.com>
+Date: Wed, 1 Mar 2023 02:23:08 +0100
+Subject: s390/kprobes: fix irq mask clobbering on kprobe reenter from post_handler
+
+From: Vasily Gorbik <gor@linux.ibm.com>
+
+commit 42e19e6f04984088b6f9f0507c4c89a8152d9730 upstream.
+
+Recent test_kprobe_missed kprobes kunit test uncovers the following error
+(reported when CONFIG_DEBUG_ATOMIC_SLEEP is enabled):
+
+BUG: sleeping function called from invalid context at kernel/locking/mutex.c:580
+in_atomic(): 0, irqs_disabled(): 1, non_block: 0, pid: 662, name: kunit_try_catch
+preempt_count: 0, expected: 0
+RCU nest depth: 0, expected: 0
+no locks held by kunit_try_catch/662.
+irq event stamp: 280
+hardirqs last enabled at (279): [<00000003e60a3d42>] __do_pgm_check+0x17a/0x1c0
+hardirqs last disabled at (280): [<00000003e3bd774a>] kprobe_exceptions_notify+0x27a/0x318
+softirqs last enabled at (0): [<00000003e3c5c890>] copy_process+0x14a8/0x4c80
+softirqs last disabled at (0): [<0000000000000000>] 0x0
+CPU: 46 PID: 662 Comm: kunit_try_catch Tainted: G N 6.2.0-173644-g44c18d77f0c0 #2
+Hardware name: IBM 3931 A01 704 (LPAR)
+Call Trace:
+ [<00000003e60a3a00>] dump_stack_lvl+0x120/0x198
+ [<00000003e3d02e82>] __might_resched+0x60a/0x668
+ [<00000003e60b9908>] __mutex_lock+0xc0/0x14e0
+ [<00000003e60bad5a>] mutex_lock_nested+0x32/0x40
+ [<00000003e3f7b460>] unregister_kprobe+0x30/0xd8
+ [<00000003e51b2602>] test_kprobe_missed+0xf2/0x268
+ [<00000003e51b5406>] kunit_try_run_case+0x10e/0x290
+ [<00000003e51b7dfa>] kunit_generic_run_threadfn_adapter+0x62/0xb8
+ [<00000003e3ce30f8>] kthread+0x2d0/0x398
+ [<00000003e3b96afa>] __ret_from_fork+0x8a/0xe8
+ [<00000003e60ccada>] ret_from_fork+0xa/0x40
+
+The reason for this error report is that kprobes handling code failed
+to restore irqs.
+
+The problem is that when kprobe is triggered from another kprobe
+post_handler current sequence of enable_singlestep / disable_singlestep
+is the following:
+enable_singlestep <- original kprobe (saves kprobe_saved_imask)
+enable_singlestep <- kprobe triggered from post_handler (clobbers kprobe_saved_imask)
+disable_singlestep <- kprobe triggered from post_handler (restores kprobe_saved_imask)
+disable_singlestep <- original kprobe (restores wrong clobbered kprobe_saved_imask)
+
+There is just one kprobe_ctlblk per cpu and both calls saves and
+loads irq mask to kprobe_saved_imask. To fix the problem simply move
+resume_execution (which calls disable_singlestep) before calling
+post_handler. This also fixes the problem that post_handler is called
+with pt_regs which were not yet adjusted after single-stepping.
+
+Cc: stable@vger.kernel.org
+Fixes: 4ba069b802c2 ("[S390] add kprobes support.")
+Reviewed-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
+Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ arch/s390/kernel/kprobes.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/s390/kernel/kprobes.c
++++ b/arch/s390/kernel/kprobes.c
+@@ -433,12 +433,11 @@ static int post_kprobe_handler(struct pt
+ if (!p)
+ return 0;
+
++ resume_execution(p, regs);
+ if (kcb->kprobe_status != KPROBE_REENTER && p->post_handler) {
+ kcb->kprobe_status = KPROBE_HIT_SSDONE;
+ p->post_handler(p, regs, 0);
+ }
+-
+- resume_execution(p, regs);
+ pop_kprobe(kcb);
+ preempt_enable_no_resched();
+
--- /dev/null
+From fb428a2005fc1260d18b989cc5199f281617f44d Mon Sep 17 00:00:00 2001
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Date: Tue, 14 Feb 2023 09:50:16 +0900
+Subject: scsi: mpi3mr: Fix issues in mpi3mr_get_all_tgt_info()
+
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+
+commit fb428a2005fc1260d18b989cc5199f281617f44d upstream.
+
+The function mpi3mr_get_all_tgt_info() has four issues:
+
+1) It calculates valid entry length in alltgt_info assuming the header part
+ of the struct mpi3mr_device_map_info would equal to sizeof(u32). The
+ correct size is sizeof(u64).
+
+2) When it calculates the valid entry length kern_entrylen, it excludes one
+ entry by subtracting 1 from num_devices.
+
+3) It copies num_device by calling memcpy(). Substitution is enough.
+
+4) It does not specify the calculated length to sg_copy_from_buffer().
+ Instead, it specifies the payload length which is larger than the
+ alltgt_info size. It causes "BUG: KASAN: slab-out-of-bounds".
+
+Fix the issues by using the correct header size, removing the subtraction
+from num_devices, replacing the memcpy() with substitution and specifying
+the correct length to sg_copy_from_buffer().
+
+Link: https://lore.kernel.org/r/20230214005019.1897251-2-shinichiro.kawasaki@wdc.com
+Cc: stable@vger.kernel.org
+Fixes: f5e6d5a34376 ("scsi: mpi3mr: Add support for driver commands")
+Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Acked-by: Sathya Prakash Veerichetty <sathya.prakash@broadcom.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/mpi3mr/mpi3mr_app.c | 15 ++++++++-------
+ 1 file changed, 8 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
+index 9baac224b213..72054e3a26cb 100644
+--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
++++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
+@@ -312,7 +312,7 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ num_devices++;
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+- if ((job->request_payload.payload_len == sizeof(u32)) ||
++ if ((job->request_payload.payload_len <= sizeof(u64)) ||
+ list_empty(&mrioc->tgtdev_list)) {
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+@@ -320,14 +320,14 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ return 0;
+ }
+
+- kern_entrylen = (num_devices - 1) * sizeof(*devmap_info);
+- size = sizeof(*alltgt_info) + kern_entrylen;
++ kern_entrylen = num_devices * sizeof(*devmap_info);
++ size = sizeof(u64) + kern_entrylen;
+ alltgt_info = kzalloc(size, GFP_KERNEL);
+ if (!alltgt_info)
+ return -ENOMEM;
+
+ devmap_info = alltgt_info->dmi;
+- memset((u8 *)devmap_info, 0xFF, (kern_entrylen + sizeof(*devmap_info)));
++ memset((u8 *)devmap_info, 0xFF, kern_entrylen);
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+ list_for_each_entry(tgtdev, &mrioc->tgtdev_list, list) {
+ if (i < num_devices) {
+@@ -344,9 +344,10 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ num_devices = i;
+ spin_unlock_irqrestore(&mrioc->tgtdev_lock, flags);
+
+- memcpy(&alltgt_info->num_devices, &num_devices, sizeof(num_devices));
++ alltgt_info->num_devices = num_devices;
+
+- usr_entrylen = (job->request_payload.payload_len - sizeof(u32)) / sizeof(*devmap_info);
++ usr_entrylen = (job->request_payload.payload_len - sizeof(u64)) /
++ sizeof(*devmap_info);
+ usr_entrylen *= sizeof(*devmap_info);
+ min_entrylen = min(usr_entrylen, kern_entrylen);
+ if (min_entrylen && (!memcpy(&alltgt_info->dmi, devmap_info, min_entrylen))) {
+@@ -358,7 +359,7 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+- alltgt_info, job->request_payload.payload_len);
++ alltgt_info, (min_entrylen + sizeof(u64)));
+ rval = 0;
+ out:
+ kfree(alltgt_info);
+--
+2.39.2
+
--- /dev/null
+From e39ea831ebad4ab15c4748cb62a397a8abcca36e Mon Sep 17 00:00:00 2001
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Date: Tue, 14 Feb 2023 09:50:19 +0900
+Subject: scsi: mpi3mr: Fix missing mrioc->evtack_cmds initialization
+
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+
+commit e39ea831ebad4ab15c4748cb62a397a8abcca36e upstream.
+
+Commit c1af985d27da ("scsi: mpi3mr: Add Event acknowledgment logic")
+introduced an array mrioc->evtack_cmds but initialization of the array
+elements was missed. They are just zero cleared. The function
+mpi3mr_complete_evt_ack() refers host_tag field of the elements. Due to the
+zero value of the host_tag field, the function calls clear_bit() for
+mrico->evtack_cmds_bitmap with wrong bit index. This results in memory
+access to invalid address and "BUG: KASAN: use-after-free". This BUG was
+observed at eHBA-9600 firmware update to version 8.3.1.0. To fix it, add
+the missing initialization of mrioc->evtack_cmds.
+
+Link: https://lore.kernel.org/r/20230214005019.1897251-5-shinichiro.kawasaki@wdc.com
+Cc: stable@vger.kernel.org
+Fixes: c1af985d27da ("scsi: mpi3mr: Add Event acknowledgment logic")
+Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Reviewed-by: Damien Le Moal <damien.lemoal@opensource.wdc.com>
+Acked-by: Sathya Prakash Veerichetty <sathya.prakash@broadcom.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/mpi3mr/mpi3mr_os.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/drivers/scsi/mpi3mr/mpi3mr_os.c
++++ b/drivers/scsi/mpi3mr/mpi3mr_os.c
+@@ -4952,6 +4952,10 @@ mpi3mr_probe(struct pci_dev *pdev, const
+ mpi3mr_init_drv_cmd(&mrioc->dev_rmhs_cmds[i],
+ MPI3MR_HOSTTAG_DEVRMCMD_MIN + i);
+
++ for (i = 0; i < MPI3MR_NUM_EVTACKCMD; i++)
++ mpi3mr_init_drv_cmd(&mrioc->evtack_cmds[i],
++ MPI3MR_HOSTTAG_EVTACKCMD_MIN + i);
++
+ if (pdev->revision)
+ mrioc->enable_segqueue = true;
+
--- /dev/null
+From eeb270aee3e085411399f129fc14fa04bd6d83cf Mon Sep 17 00:00:00 2001
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Date: Tue, 14 Feb 2023 09:50:17 +0900
+Subject: scsi: mpi3mr: Remove unnecessary memcpy() to alltgt_info->dmi
+
+From: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+
+commit eeb270aee3e085411399f129fc14fa04bd6d83cf upstream.
+
+In the function mpi3mr_get_all_tgt_info(), devmap_info points to
+alltgt_info->dmi then there is no need to memcpy() data from devmap_info to
+alltgt_info->dmi. Remove the unnecessary memcpy(). This also allows to
+remove the local variable 'rval' and the goto label 'out'.
+
+Link: https://lore.kernel.org/r/20230214005019.1897251-3-shinichiro.kawasaki@wdc.com
+Cc: stable@vger.kernel.org
+Fixes: f5e6d5a34376 ("scsi: mpi3mr: Add support for driver commands")
+Signed-off-by: Shin'ichiro Kawasaki <shinichiro.kawasaki@wdc.com>
+Acked-by: Sathya Prakash Veerichetty <sathya.prakash@broadcom.com>
+Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/scsi/mpi3mr/mpi3mr_app.c | 13 ++-----------
+ 1 file changed, 2 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/scsi/mpi3mr/mpi3mr_app.c b/drivers/scsi/mpi3mr/mpi3mr_app.c
+index 72054e3a26cb..bff637702397 100644
+--- a/drivers/scsi/mpi3mr/mpi3mr_app.c
++++ b/drivers/scsi/mpi3mr/mpi3mr_app.c
+@@ -293,7 +293,6 @@ static long mpi3mr_bsg_pel_enable(struct mpi3mr_ioc *mrioc,
+ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ struct bsg_job *job)
+ {
+- long rval = -EINVAL;
+ u16 num_devices = 0, i = 0, size;
+ unsigned long flags;
+ struct mpi3mr_tgt_dev *tgtdev;
+@@ -304,7 +303,7 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ if (job->request_payload.payload_len < sizeof(u32)) {
+ dprint_bsg_err(mrioc, "%s: invalid size argument\n",
+ __func__);
+- return rval;
++ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&mrioc->tgtdev_lock, flags);
+@@ -350,20 +349,12 @@ static long mpi3mr_get_all_tgt_info(struct mpi3mr_ioc *mrioc,
+ sizeof(*devmap_info);
+ usr_entrylen *= sizeof(*devmap_info);
+ min_entrylen = min(usr_entrylen, kern_entrylen);
+- if (min_entrylen && (!memcpy(&alltgt_info->dmi, devmap_info, min_entrylen))) {
+- dprint_bsg_err(mrioc, "%s:%d: device map info copy failed\n",
+- __func__, __LINE__);
+- rval = -EFAULT;
+- goto out;
+- }
+
+ sg_copy_from_buffer(job->request_payload.sg_list,
+ job->request_payload.sg_cnt,
+ alltgt_info, (min_entrylen + sizeof(u64)));
+- rval = 0;
+-out:
+ kfree(alltgt_info);
+- return rval;
++ return 0;
+ }
+ /**
+ * mpi3mr_get_change_count - Get topology change count
+--
+2.39.2
+
io_uring-rsrc-disallow-multi-source-reg-buffers.patch
io_uring-remove-msg_nosignal-from-recvmsg.patch
io_uring-fix-fget-leak-when-fs-don-t-support-nowait-buffered-read.patch
+s390-extmem-return-correct-segment-type-in-__segment_load.patch
+s390-discard-.interp-section.patch
+s390-kprobes-fix-irq-mask-clobbering-on-kprobe-reenter-from-post_handler.patch
+s390-kprobes-fix-current_kprobe-never-cleared-after-kprobes-reenter.patch
+kvm-s390-disable-migration-mode-when-dirty-tracking-is-disabled.patch
+cifs-fix-uninitialized-memory-read-in-smb3_qfs_tcon.patch
+cifs-fix-uninitialized-memory-reads-for-oparms.mode.patch
+cifs-fix-mount-on-old-smb-servers.patch
+cifs-introduce-cifs_io_parms-in-smb2_async_writev.patch
+cifs-split-out-smb3_use_rdma_offload-helper.patch
+cifs-don-t-try-to-use-rdma-offload-on-encrypted-connections.patch
+cifs-check-the-lease-context-if-we-actually-got-a-lease.patch
+cifs-return-a-single-use-cfid-if-we-did-not-get-a-lease.patch
+scsi-mpi3mr-fix-missing-mrioc-evtack_cmds-initialization.patch
+scsi-mpi3mr-fix-issues-in-mpi3mr_get_all_tgt_info.patch
+scsi-mpi3mr-remove-unnecessary-memcpy-to-alltgt_info-dmi.patch