From 171cceab65b87153d165ffb86c7bd218facb3e51 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 16:53:18 +0100
Subject: [PATCH 1/6] cifs: Add required includes to cifsfs.h

struct file and a few others are referenced in prototypes.

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/cifsfs.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 71fe0a0a7992..23391162391e 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -9,6 +9,9 @@
 #ifndef _CIFSFS_H
 #define _CIFSFS_H
 
+#include <linux/dcache.h>
+#include <linux/fs.h>
+
 #include <linux/hash.h>
 
 #define ROOT_I 2
-- 
2.30.2


From ab37ec994a2d6f5e98760b85c3cb31582676e322 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 16:54:50 +0100
Subject: [PATCH 2/6] cifs: Add struct smb2_compound_op

Infrastructure to make handling of open/<op>/close easier

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/Makefile       |   1 +
 fs/cifs/smb2compound.c | 200 +++++++++++++++++++++++++++++++++++++++++
 fs/cifs/smb2compound.h |  33 +++++++
 3 files changed, 234 insertions(+)
 create mode 100644 fs/cifs/smb2compound.c
 create mode 100644 fs/cifs/smb2compound.h

diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile
index 304a7f6cc13a..ece58d2e3712 100644
--- a/fs/cifs/Makefile
+++ b/fs/cifs/Makefile
@@ -10,6 +10,7 @@ cifs-y := trace.o cifsfs.o cifs_debug.o connect.o dir.o file.o \
 	  cached_dir.o cifs_unicode.o nterr.o cifsencrypt.o \
 	  readdir.o ioctl.o sess.o export.o unc.o winucase.o \
 	  smb2ops.o smb2maperror.o smb2transport.o \
+	  smb2compound.o \
 	  smb2misc.o smb2pdu.o smb2inode.o smb2file.o cifsacl.o fs_context.o \
 	  dns_resolve.o cifs_spnego_negtokeninit.asn1.o asn1.o
 
diff --git a/fs/cifs/smb2compound.c b/fs/cifs/smb2compound.c
new file mode 100644
index 000000000000..ef64db12cb44
--- /dev/null
+++ b/fs/cifs/smb2compound.c
@@ -0,0 +1,200 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ *  Copyright (c) 2023, Volker Lendecke <vl@samba.org>
+ */
+
+#include "cifsfs.h"
+#include "cifsglob.h"
+#include "cifsproto.h"
+#include "smb2pdu.h"
+#include "smb2proto.h"
+#include "smb2compound.h"
+
+struct smb2_compound_op *smb2_compound_op_init(bool openclose,
+					       int num_ops,
+					       int *num_rqst_iovs,
+					       int *op_idx)
+{
+	int num_rqst = num_ops;
+	int num_rqst_iov = 0;
+	struct smb_rqst *rqst;
+	struct kvec *rqst_iov;
+	struct smb2_compound_op *op;
+	int i;
+
+	if (openclose) {
+		num_rqst += 2;
+		num_rqst_iov += SMB2_CREATE_IOV_SIZE + 1; /* open+close */
+	}
+
+	for (i = 0; i < num_ops; i++)
+		num_rqst_iov += num_rqst_iovs[i];
+
+	/*
+	 * For now use a simple approach of multiple allocs. As a
+	 * valid optimization allocate all sub-structures of "op" from
+	 * one kzalloc.
+	 */
+
+	op = kzalloc(sizeof(*op), GFP_KERNEL);
+	if (!op)
+		return NULL;
+
+	op->num_rqst = num_rqst;
+
+	op->rqst = kcalloc(num_rqst, sizeof(*op->rqst), GFP_KERNEL);
+	if (!op->rqst)
+		goto nomem;
+
+	op->rqst_iov = kcalloc(num_rqst_iov, sizeof(*op->rqst_iov), GFP_KERNEL);
+	if (!op->rqst_iov)
+		goto nomem;
+
+	op->resp_buftype = kcalloc(num_rqst,
+				   sizeof(*op->resp_buftype),
+				   GFP_KERNEL);
+	if (!op->resp_buftype)
+		goto nomem;
+
+	op->rsp_iov = kcalloc(num_rqst, sizeof(*op->rsp_iov), GFP_KERNEL);
+	if (!op->rsp_iov)
+		goto nomem;
+
+	/*
+	 * Fill all op->rqst->rqst_iov structures
+	 */
+
+	rqst = op->rqst;
+	rqst_iov = op->rqst_iov;
+
+	if (openclose) {
+		/* open request */
+		rqst->rq_iov = rqst_iov;
+		rqst->rq_nvec = SMB2_CREATE_IOV_SIZE;
+		rqst_iov += SMB2_CREATE_IOV_SIZE;
+		rqst++;
+	}
+
+	for (i = 0; i < num_ops; i++) {
+		rqst->rq_iov = rqst_iov;
+		rqst->rq_nvec = num_rqst_iovs[i];
+		rqst_iov += num_rqst_iovs[i];
+		rqst++;
+	}
+
+	if (openclose) {
+		/* close request */
+		rqst->rq_iov = rqst_iov;
+		rqst->rq_nvec = 1;
+		rqst_iov += 1;
+		rqst++;
+	}
+
+	if (op_idx)
+		*op_idx = openclose ? 1 : 0;
+
+	return op;
+nomem:
+	smb2_compound_op_free(op);
+	return NULL;
+}
+
+void smb2_compound_op_free(struct smb2_compound_op *op)
+{
+	for (int i = 0; i < op->num_rqst; i++) {
+		struct smb_rqst *rqst = &op->rqst[i];
+		struct smb2_hdr *hdr = rqst->rq_iov[0].iov_base;
+
+		switch (hdr->Command) {
+		case SMB2_CREATE:
+			SMB2_open_free(rqst);
+			break;
+		case SMB2_QUERY_INFO:
+			SMB2_query_info_free(rqst);
+			break;
+		case SMB2_SET_INFO:
+			SMB2_set_info_free(rqst);
+			break;
+		case SMB2_IOCTL:
+			SMB2_ioctl_free(rqst);
+			break;
+		case SMB2_CLOSE:
+			SMB2_close_free(rqst);
+			break;
+		}
+	}
+
+	if (op->rsp_iov && op->resp_buftype) {
+		for (int i = 0; i < op->num_rqst; i++)
+			free_rsp_buf(op->resp_buftype[i],
+				     op->rsp_iov[i].iov_base);
+	}
+
+	kfree(op->rsp_iov);
+	kfree(op->resp_buftype);
+	kfree(op->rqst_iov);
+	kfree(op->rqst);
+	kfree(op);
+}
+
+int smb2_compound_openclose(struct smb2_compound_op *op,
+			    struct cifs_sb_info *cifs_sb,
+			    struct cifs_tcon *tcon,
+			    struct TCP_Server_Info *server,
+			    __u8 *oplock, struct cifs_open_parms *oparms,
+			    const char *path)
+{
+	__le16 *utf16_path = NULL;
+	u8 none_oplock = SMB2_OPLOCK_LEVEL_NONE;
+	int rc;
+
+	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+
+	if (!oplock)
+		oplock = &none_oplock;
+
+	oparms->fid = &op->fid;
+
+	rc = SMB2_open_init(tcon, server, &op->rqst[0], oplock, oparms,
+			    utf16_path);
+
+	kfree(utf16_path);
+
+	if (rc)
+		return rc;
+
+	rc = SMB2_close_init(tcon, server, &op->rqst[op->num_rqst-1],
+			     COMPOUND_FID, COMPOUND_FID, false);
+	return rc;
+}
+
+static void smb2_compound_set_related(struct cifs_tcon *tcon,
+			       struct smb2_compound_op *op)
+{
+	smb2_set_next_command(tcon, &op->rqst[0]);
+
+	for (int i = 1; i < op->num_rqst; i++) {
+		smb2_set_next_command(tcon, &op->rqst[i]);
+		smb2_set_related(&op->rqst[i]);
+	}
+}
+
+int smb2_compound_send_recv(const unsigned int xid,
+			    struct cifs_tcon *tcon,
+			    struct cifs_ses *ses,
+			    struct TCP_Server_Info *server,
+			    struct smb2_compound_op *op)
+{
+	int flags = CIFS_CP_CREATE_CLOSE_OP;
+
+	if (smb3_encryption_required(tcon))
+		flags |= CIFS_TRANSFORM_REQ;
+
+	smb2_compound_set_related(tcon, op);
+
+	return compound_send_recv(xid, ses, server, flags,
+				  op->num_rqst, op->rqst,
+				  op->resp_buftype, op->rsp_iov);
+}
diff --git a/fs/cifs/smb2compound.h b/fs/cifs/smb2compound.h
new file mode 100644
index 000000000000..0a4116ef32ba
--- /dev/null
+++ b/fs/cifs/smb2compound.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: LGPL-2.1 */
+/*
+ *  Copyright (c) 2023, Volker Lendecke <vl@samba.org>
+ */
+
+struct smb2_compound_op {
+	struct cifs_fid fid;
+	int num_rqst;
+	struct smb_rqst *rqst;
+	struct kvec *rqst_iov;
+	int *resp_buftype;
+	struct kvec *rsp_iov;
+};
+
+struct smb2_compound_op *smb2_compound_op_init(bool openclose,
+					       int num_ops,
+					       int *num_rqst_iovs,
+					       int *op_idx);
+
+void smb2_compound_op_free(struct smb2_compound_op *op);
+
+int smb2_compound_openclose(struct smb2_compound_op *op,
+			    struct cifs_sb_info *cifs_sb,
+			    struct cifs_tcon *tcon,
+			    struct TCP_Server_Info *server,
+			    __u8 *oplock, struct cifs_open_parms *oparms,
+			    const char *path);
+
+int smb2_compound_send_recv(const unsigned int xid,
+			    struct cifs_tcon *tcon,
+			    struct cifs_ses *ses,
+			    struct TCP_Server_Info *server,
+			    struct smb2_compound_op *op);
-- 
2.30.2


From a6deeaeddba1be71d8feca93579bbd128db682c3 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 16:25:07 +0100
Subject: [PATCH 3/6] cifs: Use smb2_compound_op in smb2_query_info_compound

Remove special-case code

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/smb2ops.c | 120 +++++++++++++---------------------------------
 1 file changed, 33 insertions(+), 87 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index 6dfb865ee9d7..bf539c9d2cf8 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -28,6 +28,7 @@
 #include "fscache.h"
 #include "fs_context.h"
 #include "cached_dir.h"
+#include "smb2compound.h"
 
 /* Change credits for different ops and return the total number of credits */
 static int
@@ -2460,32 +2461,16 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 {
 	struct cifs_ses *ses = tcon->ses;
 	struct TCP_Server_Info *server = cifs_pick_channel(ses);
-	int flags = CIFS_CP_CREATE_CLOSE_OP;
-	struct smb_rqst rqst[3];
-	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec qi_iov[1];
-	struct kvec close_iov[1];
-	u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
-	struct cifs_open_parms oparms;
-	struct cifs_fid fid;
+	__u64 persistent_fid = COMPOUND_FID;
+	__u64 volatile_fid = COMPOUND_FID;
+	struct smb2_compound_op *op = NULL;
+	int num_qi_iov = 1;
+	int op_idx = 0;
 	int rc;
-	__le16 *utf16_path;
 	struct cached_fid *cfid = NULL;
 
 	if (!path)
 		path = "";
-	utf16_path = cifs_convert_path_to_utf16(path, cifs_sb);
-	if (!utf16_path)
-		return -ENOMEM;
-
-	if (smb3_encryption_required(tcon))
-		flags |= CIFS_TRANSFORM_REQ;
-
-	memset(rqst, 0, sizeof(rqst));
-	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
 
 	/*
 	 * We can only call this for things we know are directories.
@@ -2494,73 +2479,38 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 		open_cached_dir(xid, tcon, path, cifs_sb, false,
 				&cfid); /* cfid null if open dir failed */
 
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
-	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
-	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);
-	if (rc)
+	op = smb2_compound_op_init(!cfid, 1, &num_qi_iov, &op_idx);
+	if (!op) {
+		rc = -ENOMEM;
 		goto qic_exit;
-	smb2_set_next_command(tcon, &rqst[0]);
-
-	memset(&qi_iov, 0, sizeof(qi_iov));
-	rqst[1].rq_iov = qi_iov;
-	rqst[1].rq_nvec = 1;
+	}
 
 	if (cfid) {
-		rc = SMB2_query_info_init(tcon, server,
-					  &rqst[1],
-					  cfid->fid.persistent_fid,
-					  cfid->fid.volatile_fid,
-					  class, type, 0,
-					  output_len, 0,
-					  NULL);
+		persistent_fid = cfid->fid.persistent_fid;
+		volatile_fid = cfid->fid.volatile_fid;
 	} else {
-		rc = SMB2_query_info_init(tcon, server,
-					  &rqst[1],
-					  COMPOUND_FID,
-					  COMPOUND_FID,
-					  class, type, 0,
-					  output_len, 0,
-					  NULL);
-	}
-	if (rc)
-		goto qic_exit;
-	if (!cfid) {
-		smb2_set_next_command(tcon, &rqst[1]);
-		smb2_set_related(&rqst[1]);
-	}
-
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
-	rqst[2].rq_nvec = 1;
+		struct cifs_open_parms oparms = {
+			.tcon = tcon,
+			.desired_access = desired_access,
+			.disposition = FILE_OPEN,
+			.create_options = cifs_create_options(cifs_sb, 0),
+		};
+		rc = smb2_compound_openclose(op, cifs_sb, tcon, server, NULL,
+					     &oparms, path);
+		if (rc)
+			goto qic_exit;
+	};
 
-	rc = SMB2_close_init(tcon, server,
-			     &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
+	rc = SMB2_query_info_init(tcon, server, &op->rqst[op_idx],
+				  persistent_fid, volatile_fid,
+				  class, type, 0,
+				  output_len, 0,
+				  NULL);
 	if (rc)
 		goto qic_exit;
-	smb2_set_related(&rqst[2]);
 
-	if (cfid) {
-		rc = compound_send_recv(xid, ses, server,
-					flags, 1, &rqst[1],
-					&resp_buftype[1], &rsp_iov[1]);
-	} else {
-		rc = compound_send_recv(xid, ses, server,
-					flags, 3, rqst,
-					resp_buftype, rsp_iov);
-	}
+	rc = smb2_compound_send_recv(xid, tcon, ses, server, op);
 	if (rc) {
-		free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
 		if (rc == -EREMCHG) {
 			tcon->need_reconnect = true;
 			pr_warn_once("server share %s deleted\n",
@@ -2568,16 +2518,12 @@ smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tcon,
 		}
 		goto qic_exit;
 	}
-	*rsp = rsp_iov[1];
-	*buftype = resp_buftype[1];
+	*rsp = op->rsp_iov[1];
+	*buftype = op->resp_buftype[1];
+	op->resp_buftype[1] = CIFS_NO_BUFFER; /* don't free here */
 
  qic_exit:
-	kfree(utf16_path);
-	SMB2_open_free(&rqst[0]);
-	SMB2_query_info_free(&rqst[1]);
-	SMB2_close_free(&rqst[2]);
-	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
-	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
+	smb2_compound_op_free(op);
 	if (cfid)
 		close_cached_dir(cfid);
 	return rc;
-- 
2.30.2


From c22a9bffca9b804d838bd176785d4c886b0938d4 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 17:50:59 +0100
Subject: [PATCH 4/6] cifs: Use smb2_compound_op in smb2_unlink()

Reduce use of smb2_compound_op()

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/smb2glob.h  |  1 -
 fs/cifs/smb2inode.c | 54 +++++++++++++++++++++++++++++++++------------
 2 files changed, 40 insertions(+), 15 deletions(-)

diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index 82e916ad167c..d9e7c122eee5 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -29,7 +29,6 @@
 #define SMB2_OP_QUERY_DIR 4
 #define SMB2_OP_MKDIR 5
 #define SMB2_OP_RENAME 6
-#define SMB2_OP_DELETE 7
 #define SMB2_OP_HARDLINK 8
 #define SMB2_OP_SET_EOF 9
 #define SMB2_OP_RMDIR 10
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index 8dd3791b5c53..d1529ade2e58 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -25,6 +25,7 @@
 #include "smb2proto.h"
 #include "cached_dir.h"
 #include "smb2status.h"
+#include "smb2compound.h"
 
 static void
 free_set_inf_compound(struct smb_rqst *rqst)
@@ -199,9 +200,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 		num_rqst++;
 		trace_smb3_posix_query_info_compound_enter(xid, ses->Suid, tcon->tid, full_path);
 		break;
-	case SMB2_OP_DELETE:
-		trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, full_path);
-		break;
 	case SMB2_OP_MKDIR:
 		/*
 		 * Directories are created through parameters in the
@@ -473,14 +471,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 		else
 			trace_smb3_posix_query_info_compound_done(xid, ses->Suid, tcon->tid);
 		break;
-	case SMB2_OP_DELETE:
-		if (rc)
-			trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
-		else
-			trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
-		if (rqst[1].rq_iov)
-			SMB2_close_free(&rqst[1]);
-		break;
 	case SMB2_OP_MKDIR:
 		if (rc)
 			trace_smb3_mkdir_err(xid,  ses->Suid, tcon->tid, rc);
@@ -748,9 +738,45 @@ int
 smb2_unlink(const unsigned int xid, struct cifs_tcon *tcon, const char *name,
 	    struct cifs_sb_info *cifs_sb)
 {
-	return smb2_compound_op(xid, tcon, cifs_sb, name, DELETE, FILE_OPEN,
-				CREATE_DELETE_ON_CLOSE | OPEN_REPARSE_POINT,
-				ACL_NO_MODE, NULL, SMB2_OP_DELETE, NULL, NULL, NULL, NULL, NULL);
+	struct cifs_ses *ses = tcon->ses;
+	struct TCP_Server_Info *server = cifs_pick_channel(ses);
+	struct cifs_open_parms oparms = {
+		.tcon = tcon,
+		.desired_access = DELETE,
+		.disposition = FILE_OPEN,
+		.create_options = cifs_create_options(cifs_sb,
+						      CREATE_DELETE_ON_CLOSE |
+						      OPEN_REPARSE_POINT),
+		.mode = ACL_NO_MODE,
+		.cifs_sb = cifs_sb,
+	};
+	struct smb2_compound_op *op = NULL;
+	int rc;
+
+	trace_smb3_delete_enter(xid, ses->Suid, tcon->tid, name);
+
+	op = smb2_compound_op_init(true, 0, NULL, NULL);
+	if (!op) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = smb2_compound_openclose(op, cifs_sb, tcon, server, NULL, &oparms,
+				     name);
+	if (rc)
+		goto fail;
+
+	rc = smb2_compound_send_recv(xid, tcon, ses, server, op);
+
+fail:
+	smb2_compound_op_free(op);
+
+	if (rc)
+		trace_smb3_delete_err(xid,  ses->Suid, tcon->tid, rc);
+	else
+		trace_smb3_delete_done(xid, ses->Suid, tcon->tid);
+
+	return rc;
 }
 
 static int
-- 
2.30.2


From 71c8b6024ad6438712e0a0ab35710fa6ea7bc3f2 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 19:02:36 +0100
Subject: [PATCH 5/6] cifs: Use smb2_compound_op in smb2_set_path_size()

Avoid boilerplate code

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/smb2glob.h  |   1 -
 fs/cifs/smb2inode.c | 101 ++++++++++++++++++++++++--------------------
 2 files changed, 55 insertions(+), 47 deletions(-)

diff --git a/fs/cifs/smb2glob.h b/fs/cifs/smb2glob.h
index d9e7c122eee5..897c16c4ea69 100644
--- a/fs/cifs/smb2glob.h
+++ b/fs/cifs/smb2glob.h
@@ -30,7 +30,6 @@
 #define SMB2_OP_MKDIR 5
 #define SMB2_OP_RENAME 6
 #define SMB2_OP_HARDLINK 8
-#define SMB2_OP_SET_EOF 9
 #define SMB2_OP_RMDIR 10
 #define SMB2_OP_POSIX_QUERY_INFO 11
 
diff --git a/fs/cifs/smb2inode.c b/fs/cifs/smb2inode.c
index d1529ade2e58..787d17d0c6db 100644
--- a/fs/cifs/smb2inode.c
+++ b/fs/cifs/smb2inode.c
@@ -225,41 +225,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 		smb2_set_related(&rqst[num_rqst++]);
 		trace_smb3_rmdir_enter(xid, ses->Suid, tcon->tid, full_path);
 		break;
-	case SMB2_OP_SET_EOF:
-		rqst[num_rqst].rq_iov = &vars->si_iov[0];
-		rqst[num_rqst].rq_nvec = 1;
-
-		size[0] = 8; /* sizeof __le64 */
-		data[0] = ptr;
-
-		if (cfile) {
-			rc = SMB2_set_info_init(tcon, server,
-						&rqst[num_rqst],
-						cfile->fid.persistent_fid,
-						cfile->fid.volatile_fid,
-						current->tgid,
-						FILE_END_OF_FILE_INFORMATION,
-						SMB2_O_INFO_FILE, 0,
-						data, size);
-		} else {
-			rc = SMB2_set_info_init(tcon, server,
-						&rqst[num_rqst],
-						COMPOUND_FID,
-						COMPOUND_FID,
-						current->tgid,
-						FILE_END_OF_FILE_INFORMATION,
-						SMB2_O_INFO_FILE, 0,
-						data, size);
-			if (!rc) {
-				smb2_set_next_command(tcon, &rqst[num_rqst]);
-				smb2_set_related(&rqst[num_rqst]);
-			}
-		}
-		if (rc)
-			goto finished;
-		num_rqst++;
-		trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
-		break;
 	case SMB2_OP_SET_INFO:
 		rqst[num_rqst].rq_iov = &vars->si_iov[0];
 		rqst[num_rqst].rq_nvec = 1;
@@ -500,13 +465,6 @@ static int smb2_compound_op(const unsigned int xid, struct cifs_tcon *tcon,
 			trace_smb3_rmdir_done(xid, ses->Suid, tcon->tid);
 		free_set_inf_compound(rqst);
 		break;
-	case SMB2_OP_SET_EOF:
-		if (rc)
-			trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
-		else
-			trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
-		free_set_inf_compound(rqst);
-		break;
 	case SMB2_OP_SET_INFO:
 		if (rc)
 			trace_smb3_set_info_compound_err(xid,  ses->Suid,
@@ -830,13 +788,64 @@ smb2_set_path_size(const unsigned int xid, struct cifs_tcon *tcon,
 		   const char *full_path, __u64 size,
 		   struct cifs_sb_info *cifs_sb, bool set_alloc)
 {
+	struct cifs_ses *ses = tcon->ses;
+	struct TCP_Server_Info *server = cifs_pick_channel(ses);
+	__u64 persistent_fid = COMPOUND_FID;
+	__u64 volatile_fid = COMPOUND_FID;
+	struct smb2_compound_op *op = NULL;
+	int num_si_iov = 1;
+	int op_idx = 0;
+	int rc;
+	struct cifsFileInfo *cfile = NULL;
 	__le64 eof = cpu_to_le64(size);
-	struct cifsFileInfo *cfile;
+
+	unsigned int sizes = sizeof(eof);
+	void *data = &eof;
+
+	trace_smb3_set_eof_enter(xid, ses->Suid, tcon->tid, full_path);
 
 	cifs_get_writable_path(tcon, full_path, FIND_WR_ANY, &cfile);
-	return smb2_compound_op(xid, tcon, cifs_sb, full_path,
-				FILE_WRITE_DATA, FILE_OPEN, 0, ACL_NO_MODE,
-				&eof, SMB2_OP_SET_EOF, cfile, NULL, NULL, NULL, NULL);
+
+	op = smb2_compound_op_init(!cfile, 1, &num_si_iov, &op_idx);
+	if (!op) {
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	if (cfile) {
+		persistent_fid = cfile->fid.persistent_fid;
+		volatile_fid = cfile->fid.volatile_fid;
+	} else {
+		struct cifs_open_parms oparms = {
+			.tcon = tcon,
+			.desired_access = FILE_WRITE_DATA,
+			.disposition = FILE_OPEN,
+			.create_options = cifs_create_options(cifs_sb, 0),
+			.mode = ACL_NO_MODE,
+		};
+		rc = smb2_compound_openclose(op, cifs_sb, tcon, server, NULL,
+					     &oparms, full_path);
+		if (rc)
+			goto fail;
+	}
+
+	rc = SMB2_set_info_init(tcon, server, &op->rqst[op_idx],
+				persistent_fid, volatile_fid,
+				current->tgid, FILE_END_OF_FILE_INFORMATION,
+				SMB2_O_INFO_FILE, 0, &data, &sizes);
+	if (!rc)
+		goto fail;
+
+	rc = smb2_compound_send_recv(xid, tcon, ses, server, op);
+fail:
+	smb2_compound_op_free(op);
+
+	if (rc)
+		trace_smb3_set_eof_err(xid,  ses->Suid, tcon->tid, rc);
+	else
+		trace_smb3_set_eof_done(xid, ses->Suid, tcon->tid);
+
+	return rc;
 }
 
 int
-- 
2.30.2


From 35f02f7d37624e37f33eb53a4071c156a8d422a8 Mon Sep 17 00:00:00 2001
From: Volker Lendecke <vl@samba.org>
Date: Sun, 19 Mar 2023 19:22:23 +0100
Subject: [PATCH 6/6] cifs: Use smb2_compound_op in smb2_query_symlink()

Avoid boilerplate code

Signed-off-by: Volker Lendecke <vl@samba.org>
---
 fs/cifs/smb2ops.c | 83 +++++++++--------------------------------------
 1 file changed, 16 insertions(+), 67 deletions(-)

diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index bf539c9d2cf8..43b59b33d308 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -2832,20 +2832,14 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 		   struct cifs_sb_info *cifs_sb, const char *full_path,
 		   char **target_path, bool is_reparse_point)
 {
+	struct cifs_ses *ses = tcon->ses;
+	struct TCP_Server_Info *server = cifs_pick_channel(ses);
+	struct smb2_compound_op *op = NULL;
+	int num_ioctl_iov = SMB2_IOCTL_IOV_SIZE;
+	int op_idx = 0;
 	int rc;
-	__le16 *utf16_path = NULL;
-	__u8 oplock = SMB2_OPLOCK_LEVEL_NONE;
 	struct cifs_open_parms oparms;
-	struct cifs_fid fid;
 	struct kvec err_iov = {NULL, 0};
-	struct TCP_Server_Info *server = cifs_pick_channel(tcon->ses);
-	int flags = CIFS_CP_CREATE_CLOSE_OP;
-	struct smb_rqst rqst[3];
-	int resp_buftype[3];
-	struct kvec rsp_iov[3];
-	struct kvec open_iov[SMB2_CREATE_IOV_SIZE];
-	struct kvec io_iov[SMB2_IOCTL_IOV_SIZE];
-	struct kvec close_iov[1];
 	struct smb2_create_rsp *create_rsp;
 	struct smb2_ioctl_rsp *ioctl_rsp;
 	struct reparse_data_buffer *reparse_buf;
@@ -2856,75 +2850,37 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 
 	*target_path = NULL;
 
-	if (smb3_encryption_required(tcon))
-		flags |= CIFS_TRANSFORM_REQ;
-
-	memset(rqst, 0, sizeof(rqst));
-	resp_buftype[0] = resp_buftype[1] = resp_buftype[2] = CIFS_NO_BUFFER;
-	memset(rsp_iov, 0, sizeof(rsp_iov));
-
-	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-	if (!utf16_path)
+	op = smb2_compound_op_init(true, 1, &num_ioctl_iov, &op_idx);
+	if (!op)
 		return -ENOMEM;
 
-	/* Open */
-	memset(&open_iov, 0, sizeof(open_iov));
-	rqst[0].rq_iov = open_iov;
-	rqst[0].rq_nvec = SMB2_CREATE_IOV_SIZE;
-
 	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);
+	rc = smb2_compound_openclose(op, cifs_sb, tcon, server, NULL,
+				     &oparms, full_path);
 	if (rc)
 		goto querty_exit;
-	smb2_set_next_command(tcon, &rqst[0]);
-
-
-	/* IOCTL */
-	memset(&io_iov, 0, sizeof(io_iov));
-	rqst[1].rq_iov = io_iov;
-	rqst[1].rq_nvec = SMB2_IOCTL_IOV_SIZE;
 
 	rc = SMB2_ioctl_init(tcon, server,
-			     &rqst[1], fid.persistent_fid,
-			     fid.volatile_fid, FSCTL_GET_REPARSE_POINT, NULL, 0,
+			     &op->rqst[op_idx], COMPOUND_FID,
+			     COMPOUND_FID, FSCTL_GET_REPARSE_POINT, NULL, 0,
 			     CIFSMaxBufSize -
 			     MAX_SMB2_CREATE_RESPONSE_SIZE -
 			     MAX_SMB2_CLOSE_RESPONSE_SIZE);
 	if (rc)
 		goto querty_exit;
 
-	smb2_set_next_command(tcon, &rqst[1]);
-	smb2_set_related(&rqst[1]);
-
-
-	/* Close */
-	memset(&close_iov, 0, sizeof(close_iov));
-	rqst[2].rq_iov = close_iov;
-	rqst[2].rq_nvec = 1;
-
-	rc = SMB2_close_init(tcon, server,
-			     &rqst[2], COMPOUND_FID, COMPOUND_FID, false);
-	if (rc)
-		goto querty_exit;
-
-	smb2_set_related(&rqst[2]);
-
-	rc = compound_send_recv(xid, tcon->ses, server,
-				flags, 3, rqst,
-				resp_buftype, rsp_iov);
+	rc = smb2_compound_send_recv(xid, tcon, ses, server, op);
 
-	create_rsp = rsp_iov[0].iov_base;
+	create_rsp = op->rsp_iov[0].iov_base;
 	if (create_rsp && create_rsp->hdr.Status)
-		err_iov = rsp_iov[0];
-	ioctl_rsp = rsp_iov[1].iov_base;
+		err_iov = op->rsp_iov[0];
+	ioctl_rsp = op->rsp_iov[1].iov_base;
 
 	/*
 	 * Open was successful and we got an ioctl response.
@@ -2938,7 +2894,7 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 		plen = le32_to_cpu(ioctl_rsp->OutputCount);
 
 		if (plen + le32_to_cpu(ioctl_rsp->OutputOffset) >
-		    rsp_iov[1].iov_len) {
+		    op->rsp_iov[1].iov_len) {
 			cifs_tcon_dbg(VFS, "srv returned invalid ioctl len: %d\n",
 				 plen);
 			rc = -EIO;
@@ -2959,13 +2915,6 @@ smb2_query_symlink(const unsigned int xid, struct cifs_tcon *tcon,
 
  querty_exit:
 	cifs_dbg(FYI, "query symlink rc %d\n", rc);
-	kfree(utf16_path);
-	SMB2_open_free(&rqst[0]);
-	SMB2_ioctl_free(&rqst[1]);
-	SMB2_close_free(&rqst[2]);
-	free_rsp_buf(resp_buftype[0], rsp_iov[0].iov_base);
-	free_rsp_buf(resp_buftype[1], rsp_iov[1].iov_base);
-	free_rsp_buf(resp_buftype[2], rsp_iov[2].iov_base);
 	return rc;
 }
 
-- 
2.30.2

