Linux network filesystem support library
 help / color / mirror / Atom feed
From: David Howells <dhowells@redhat.com>
To: Steve French <sfrench@samba.org>
Cc: David Howells <dhowells@redhat.com>,
	Paulo Alcantara <pc@manguebit.org>,
	Shyam Prasad N <sprasad@microsoft.com>,
	Tom Talpey <tom@talpey.com>, Stefan Metzmacher <metze@samba.org>,
	Mina Almasry <almasrymina@google.com>,
	linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org,
	netfs@lists.linux.dev, linux-fsdevel@vger.kernel.org
Subject: [RFC PATCH 35/36] cifs: [WIP] Convert SMB2 Posix Mkdir request
Date: Tue, 19 May 2026 11:21:53 +0100	[thread overview]
Message-ID: <20260519102158.592165-36-dhowells@redhat.com> (raw)
In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com>

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Steve French <sfrench@samba.org>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
 fs/smb/client/smb2pdu.c | 247 ++++++++++++++++++++++------------------
 1 file changed, 139 insertions(+), 108 deletions(-)

diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c
index 6747886024c4..3eeaf027115c 100644
--- a/fs/smb/client/smb2pdu.c
+++ b/fs/smb/client/smb2pdu.c
@@ -2470,15 +2470,8 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon)
 	return rc;
 }
 
-static struct create_posix *
-create_posix_buf(umode_t mode)
+static void fill_posix_buf(struct create_posix *buf, umode_t mode)
 {
-	struct create_posix *buf;
-
-	buf = kzalloc_obj(struct create_posix);
-	if (!buf)
-		return NULL;
-
 	buf->ccontext.DataOffset =
 		cpu_to_le16(offsetof(struct create_posix, Mode));
 	buf->ccontext.DataLength = cpu_to_le32(4);
@@ -2505,20 +2498,25 @@ create_posix_buf(umode_t mode)
 	buf->Name[15] = 0x7C;
 	buf->Mode = cpu_to_le32(mode);
 	cifs_dbg(FYI, "mode on posix create 0%o\n", mode);
-	return buf;
 }
 
 static int
 add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode)
 {
+	struct create_posix *buf;
 	unsigned int num = *num_iovec;
 
-	iov[num].iov_base = create_posix_buf(mode);
 	if (mode == ACL_NO_MODE)
 		cifs_dbg(FYI, "%s: no mode\n", __func__);
-	if (iov[num].iov_base == NULL)
+
+	buf = kzalloc_obj(struct create_posix);
+	if (!buf)
 		return -ENOMEM;
-	iov[num].iov_len = sizeof(struct create_posix);
+
+	fill_posix_buf(buf, mode);
+
+	iov[num].iov_base = buf;
+	iov[num].iov_len  = sizeof(struct create_posix);
 	*num_iovec = num + 1;
 	return 0;
 }
@@ -2986,73 +2984,141 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len,
 	return 0;
 }
 
+struct smb2_create_layout {
+	const struct nls_table *cp;
+	u16		offset;		/* Running offset for assembly */
+	u16		path_len;	/* Length of utf16 path (or 0) */
+	u16		treename_len;	/* Length of DFS prefix (or 0) */
+	u16		name_len;	/* Total name length */
+	u16		name_offset;	/* Offset in message of name */
+	u16		contexts_offset; /* Offset in message contexts */
+	u16		contexts_len;	/* Length of contexts (or 0) */
+	u16		posix_offset;	/* Offset in message of posix context */
+	u8		name_pad;	/* Amount of name padding needed */
+};
+
+static int smb311_posix_mkdir_layout(struct cifs_tcon *tcon,
+				     struct smb2_create_layout *lay)
+{
+	size_t offset = lay->offset;
+	size_t tmp;
+	bool has_contexts = false;
+
+	/* [MS-SMB2] 2.2.13 NameOffset: If SMB2_FLAGS_DFS_OPERATIONS
+	 * is set in the Flags field of the SMB2 header, the file name
+	 * includes a prefix that will be processed during DFS name
+	 * normalization as specified in section 3.3.5.9. Otherwise,
+	 * the file name is relative to the share that is identified
+	 * by the TreeId in the SMB2 header.
+	 */
+	lay->name_offset = offset;
+	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
+		const char *treename = tcon->tree_name;
+		int treename_len;
+
+		/* skip leading "\\" */
+		if (!(treename[0] == '\\' && treename[1] == '\\'))
+			return -EINVAL;
+
+		treename_len = cifs_size_strtoUTF16(treename + 2, INT_MAX, lay->cp);
+
+		lay->treename_len = treename_len;
+		lay->name_len = treename_len;
+		if (lay->path_len)
+			lay->name_len += 2 + lay->path_len;
+	} else {
+		lay->name_len = lay->path_len;
+	}
+
+	offset += lay->name_len;
+	tmp = offset;
+	offset = ALIGN8(offset);
+	lay->name_pad = offset - tmp;
+	lay->contexts_offset = offset;
+
+	if (tcon->posix_extensions) {
+		/* resource #3: posix buf */
+		offset += sizeof(struct create_posix);
+		has_contexts = true;
+	}
+
+	if (has_contexts)
+		lay->contexts_len = offset - lay->contexts_offset;
+	else
+		lay->contexts_offset = 0;
+
+	lay->offset = offset;
+	return 0;
+}
+
 int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 			       umode_t mode, struct cifs_tcon *tcon,
 			       const char *full_path,
 			       struct cifs_sb_info *cifs_sb)
 {
-	struct smb_rqst rqst;
+	struct TCP_Server_Info *server;
 	struct smb2_create_req *req;
 	struct smb2_create_rsp *rsp = NULL;
+	struct smb_message *smb = NULL;
 	struct cifs_ses *ses = tcon->ses;
-	struct kvec iov[3]; /* make sure at least one for each open context */
-	struct kvec rsp_iov = {NULL, 0};
-	int resp_buftype;
-	int uni_path_len;
-	__le16 *copy_path = NULL;
-	int copy_size;
-	int rc = 0;
-	unsigned int n_iov = 2;
-	__u32 file_attributes = 0;
-	char *pc_buf = NULL;
-	int flags = 0;
-	unsigned int total_len;
 	__le16 *utf16_path = NULL;
 	struct TCP_Server_Info *server;
-	int retries = 0, cur_sleep = 0;
+	int retries = 0, cur_sleep = 0, path_len;
+
+	if (!ses) {
+		rc = smb_EIO(smb_eio_trace_null_pointers);
+
+	/* resource #1: path allocation */
+	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
+	if (!utf16_path)
+		return -ENOMEM;
+	path_len = UniStrlen(utf16_path);
 
 replay_again:
 	/* reinitialize for possible replay */
-	pc_buf = NULL;
 	flags = 0;
-	n_iov = 2;
 	server = cifs_pick_channel(ses);
 
 	cifs_dbg(FYI, "mkdir\n");
 
-	/* resource #1: path allocation */
-	utf16_path = cifs_convert_path_to_utf16(full_path, cifs_sb);
-	if (!utf16_path)
-		return -ENOMEM;
-
-	if (!ses || !server) {
-		rc = smb_EIO(smb_eio_trace_null_pointers);
+	if (!server) {
+		rc = -EIO;
 		goto err_free_path;
 	}
 
+	struct smb2_create_layout layout = {
+		.offset		= sizeof(struct smb2_create_req),
+		.path_len	= path_len,
+		.cp		= cifs_sb->local_nls,
+	};
+	rc = smb311_posix_mkdir_layout(tcon, &layout);
+	if (rc < 0)
+		goto err_free_path;
+
 	/* resource #2: request */
-	rc = smb2_plain_req_init(SMB2_CREATE, tcon, server,
-				 (void **) &req, &total_len);
-	if (rc)
+	rc = -ENOMEM;
+	smb = smb2_create_request(SMB2_CREATE, server, tcon,
+				  sizeof(*req), layout.offset, 0,
+				  SMB2_REQ_DYNAMIC);
+	if (!smb)
 		goto err_free_path;
 
 
 	if (smb3_encryption_required(tcon))
 		flags |= CIFS_TRANSFORM_REQ;
 
-	req->ImpersonationLevel = IL_IMPERSONATION;
-	req->DesiredAccess = cpu_to_le32(FILE_WRITE_ATTRIBUTES);
+	req->ImpersonationLevel	= IL_IMPERSONATION;
+	req->DesiredAccess	= cpu_to_le32(FILE_WRITE_ATTRIBUTES);
 	/* File attributes ignored on open (used in create though) */
-	req->FileAttributes = cpu_to_le32(file_attributes);
-	req->ShareAccess = FILE_SHARE_ALL_LE;
-	req->CreateDisposition = cpu_to_le32(FILE_CREATE);
-	req->CreateOptions = cpu_to_le32(CREATE_NOT_FILE);
-
-	iov[0].iov_base = (char *)req;
-	/* -1 since last byte is buf[0] which is sent below (path) */
-	iov[0].iov_len = total_len;
-
-	req->NameOffset = cpu_to_le16(sizeof(struct smb2_create_req));
+	req->FileAttributes	= cpu_to_le32(file_attributes);
+	req->ShareAccess	= FILE_SHARE_ALL_LE;
+	req->CreateDisposition	= cpu_to_le32(FILE_CREATE);
+	req->CreateOptions	= cpu_to_le32(CREATE_NOT_FILE);
+	req->NameOffset		= cpu_to_le16(layout.name_offset);
+	req->NameLength		= cpu_to_le16(layout.name_len);
+	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+	req->CreateContextsOffset = cpu_to_le32(layout.contexts_offset);
+	req->CreateContextsLength = cpu_to_le32(layout.contexts_len);
 
 	/* [MS-SMB2] 2.2.13 NameOffset:
 	 * If SMB2_FLAGS_DFS_OPERATIONS is set in the Flags field of
@@ -3062,61 +3128,32 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	 * the share that is identified by the TreeId in the SMB2
 	 * header.
 	 */
+	__le16 *name = smb->request + layout.name_offset;
+
 	if (tcon->share_flags & SHI1005_FLAGS_DFS) {
-		int name_len;
+		int tmp;
 
 		req->hdr.Flags |= SMB2_FLAGS_DFS_OPERATIONS;
-		rc = alloc_path_with_tree_prefix(&copy_path, &copy_size,
-						 &name_len,
-						 tcon->tree_name, utf16_path);
-		if (rc)
-			goto err_free_req;
 
-		req->NameLength = cpu_to_le16(name_len * 2);
-		uni_path_len = copy_size;
-		/* free before overwriting resource */
-		kfree(utf16_path);
-		utf16_path = copy_path;
-	} else {
-		uni_path_len = (2 * UniStrnlen((wchar_t *)utf16_path, PATH_MAX)) + 2;
-		/* MUST set path len (NameLength) to 0 opening root of share */
-		req->NameLength = cpu_to_le16(uni_path_len - 2);
-		if (uni_path_len % 8 != 0) {
-			copy_size = roundup(uni_path_len, 8);
-			copy_path = kzalloc(copy_size, GFP_KERNEL);
-			if (!copy_path) {
-				rc = -ENOMEM;
-				goto err_free_req;
-			}
-			memcpy((char *)copy_path, (const char *)utf16_path,
-			       uni_path_len);
-			uni_path_len = copy_size;
-			/* free before overwriting resource */
-			kfree(utf16_path);
-			utf16_path = copy_path;
+		tmp = cifs_strtoUTF16(name, tcon->tree_name + 2, INT_MAX,
+				      layout.cp);
+		WARN_ON(tmp != layout.treename_len);
+		name += tmp;
+		if (layout.path_len) {
+			*name++ = cpu_to_le16('\\');
+			memcpy(name, utf16_path, layout.path_len);
 		}
+	} else {
+		memcpy(name, utf16_path, layout.path_len);
 	}
 
-	iov[1].iov_len = uni_path_len;
-	iov[1].iov_base = utf16_path;
-	req->RequestedOplockLevel = SMB2_OPLOCK_LEVEL_NONE;
+	if (layout.name_pad)
+		memset(smb->request + layout.name_offset + layout.name_len,
+		       0, layout.name_pad);
 
-	if (tcon->posix_extensions) {
+	if (tcon->posix_extensions)
 		/* resource #3: posix buf */
-		rc = add_posix_context(iov, &n_iov, mode);
-		if (rc)
-			goto err_free_req;
-		req->CreateContextsOffset = cpu_to_le32(
-			sizeof(struct smb2_create_req) +
-			iov[1].iov_len);
-		le32_add_cpu(&req->CreateContextsLength, iov[n_iov-1].iov_len);
-		pc_buf = iov[n_iov-1].iov_base;
-	}
-
-
-	memset(&rqst, 0, sizeof(struct smb_rqst));
-	rqst.rq_iov = iov;
-	rqst.rq_nvec = n_iov;
+		fill_posix_buf(smb->request + layout.posix_offset, mode);
 
 	/* no need to inc num_remote_opens because we close it just below */
 	trace_smb3_posix_mkdir_enter(xid, tcon->tid, ses->Suid, full_path, CREATE_NOT_FILE,
@@ -3126,18 +3163,17 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 		/* Back-off before retry */
 		if (cur_sleep)
 			msleep(cur_sleep);
-		smb2_set_replay(server, &rqst);
+		smb2_set_replay(server, smb);
 	}
 
 	/* resource #4: response buffer */
-	rc = cifs_send_recv(xid, ses, server,
-			    &rqst, &resp_buftype, flags, &rsp_iov);
+	rc = smb_send_recv_messages(xid, ses, server, smb, flags);
 	if (rc) {
 		cifs_stats_fail_inc(tcon, SMB2_CREATE_HE);
 		trace_smb3_posix_mkdir_err(xid, tcon->tid, ses->Suid,
 					   CREATE_NOT_FILE,
 					   FILE_WRITE_ATTRIBUTES, rc);
-		goto err_free_rsp_buf;
+		goto err_free_req;
 	}
 
 	/*
@@ -3145,10 +3181,9 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 	 * adding check below is slightly safer long term (and quiets Coverity
 	 * warning)
 	 */
-	rsp = (struct smb2_create_rsp *)rsp_iov.iov_base;
+	rsp = (struct smb2_create_rsp *)smb->response;
 	if (rsp == NULL) {
 		rc = smb_EIO(smb_eio_trace_mkdir_no_rsp);
-		kfree(pc_buf);
 		goto err_free_req;
 	}
 
@@ -3160,18 +3195,14 @@ int smb311_posix_mkdir(const unsigned int xid, struct inode *inode,
 
 	/* Eventually save off posix specific response info and timestamps */
 
-err_free_rsp_buf:
-	free_rsp_buf(resp_buftype, rsp_iov.iov_base);
-	kfree(pc_buf);
 err_free_req:
-	cifs_small_buf_release(req);
+	smb_put_messages(smb);
 err_free_path:
-	kfree(utf16_path);
-
 	if (is_replayable_error(rc) &&
 	    smb2_should_replay(tcon, &retries, &cur_sleep))
 		goto replay_again;
 
+	kfree(utf16_path);
 	return rc;
 }
 


  parent reply	other threads:[~2026-05-19 10:25 UTC|newest]

Thread overview: 34+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260519102158.592165-1-dhowells@redhat.com>
2026-05-19 10:21 ` [RFC PATCH 01/36] net: Perform special handling for a splice from a bvecq David Howells
2026-05-19 10:21 ` [RFC PATCH 02/36] netfs: Add a facility to splice TCP receive buffers into " David Howells
2026-05-19 10:21 ` [RFC PATCH 03/36] netfs: Add some TCP receive queue helpers David Howells
2026-05-19 10:21 ` [RFC PATCH 04/36] cifs, nls: Provide unicode size determination func David Howells
2026-05-19 10:21 ` [RFC PATCH 05/36] cifs: Introduce an ALIGN8() macro David Howells
2026-05-19 10:21 ` [RFC PATCH 06/36] cifs: Rename mid_q_entry to smb_message David Howells
2026-05-19 10:21 ` [RFC PATCH 07/36] cifs: Add "Has dynamic part" flag form SMB2/3 StructureSize LSB David Howells
2026-05-19 10:21 ` [RFC PATCH 09/36] cifs: Institute message managing struct David Howells
2026-05-19 10:21 ` [RFC PATCH 10/36] cifs: Split crypt_message() into encrypt and decrypt variants David Howells
2026-05-19 10:21 ` [RFC PATCH 11/36] cifs: Add new AEAD alloc and setup routines that draw from an iterator David Howells
2026-05-19 10:21 ` [RFC PATCH 12/36] cifs: [WIP] Rewrite base Rx to put data off the socket into a bvecq David Howells
2026-05-19 10:21 ` [RFC PATCH 13/36] cifs: Remove validate_t2() David Howells
2026-05-19 10:21 ` [RFC PATCH 14/36] cifs: Remove cifs_io_subrequest::got_bytes David Howells
2026-05-19 10:21 ` [RFC PATCH 15/36] cifs: Pass smb_message to cifs_verify_signature() David Howells
2026-05-19 10:21 ` [RFC PATCH 16/36] cifs: Rewrite base TCP transmission David Howells
2026-05-19 10:36   ` Stefan Metzmacher
2026-05-19 10:21 ` [RFC PATCH 17/36] cifs: Don't use corking David Howells
2026-05-19 10:21 ` [RFC PATCH 20/36] cifs: Pass smb_message structs down into the transport layer David Howells
2026-05-19 10:21 ` [RFC PATCH 21/36] cifs: Add a tracepoint to trace the smb_message refcount David Howells
2026-05-19 10:21 ` [RFC PATCH 22/36] cifs: Trace smb1/2_copy_to_prepped_buffers() David Howells
2026-05-19 10:21 ` [RFC PATCH 23/36] cifs: Clean up mid->callback_data and kill off mid->creator David Howells
2026-05-19 10:21 ` [RFC PATCH 24/36] cifs: Add netmem allocation functions David Howells
2026-05-19 10:21 ` [RFC PATCH 25/36] cifs: Add more pieces to smb_message David Howells
2026-05-19 10:21 ` [RFC PATCH 26/36] cifs: Convert SMB2 Negotiate Protocol request David Howells
2026-05-19 10:21 ` [RFC PATCH 27/36] cifs: Convert SMB2 Session Setup request David Howells
2026-05-19 10:21 ` [RFC PATCH 28/36] cifs: Convert SMB2 Logoff request David Howells
2026-05-19 10:21 ` [RFC PATCH 29/36] cifs: Convert SMB2 Tree Connect request David Howells
2026-05-19 10:21 ` [RFC PATCH 30/36] cifs: Convert SMB2 Tree Disconnect request David Howells
2026-05-19 10:21 ` [RFC PATCH 31/36] cifs: Convert SMB2 Read request David Howells
2026-05-19 10:21 ` [RFC PATCH 32/36] cifs: Convert SMB2 Write request David Howells
2026-05-19 10:21 ` [RFC PATCH 33/36] cifs: [WIP] Don't copy new-style smb_messages to a set of pages David Howells
2026-05-19 10:21 ` [RFC PATCH 34/36] cifs: [WIP] Rearrange Create request subfuncs David Howells
2026-05-19 10:21 ` David Howells [this message]
2026-05-19 10:21 ` [RFC PATCH 36/36] cifs: [WIP] Convert SMB2 Open request David Howells

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260519102158.592165-36-dhowells@redhat.com \
    --to=dhowells@redhat.com \
    --cc=almasrymina@google.com \
    --cc=linux-cifs@vger.kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=metze@samba.org \
    --cc=netfs@lists.linux.dev \
    --cc=pc@manguebit.org \
    --cc=sfrench@samba.org \
    --cc=sprasad@microsoft.com \
    --cc=tom@talpey.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox