From nobody Thu Dec 18 12:31:40 2025 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 05FE92D542A for ; Wed, 6 Aug 2025 20:39:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754512800; cv=none; b=GAUzWtRrk6mNutZwXOtC1xk7BXXXjwpKg5kog+JVhlN2KVCwMGjtBKS4D7ajEydiZNOdCdxIWlS4BSBgz8ZsirKZIWCFidB9bcRulzADzUBli3Zrz33X7tzzxN/1PvV+DbXjn0ecN0wSzXacErxp+YnWvEj/tg+0/fl8fC5ObnM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1754512800; c=relaxed/simple; bh=Gghf6k/fnry+2WFWCe6fJYxjAU0qFTZeucHXPfX09aw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=T+SlXZ/j1vwB9Jzuvhq4DnoTM8NPDDF6oYQQobXRfnlOaNXejV7BdeBUg14f6yY9TCAFEwxbdWf0e4WnZoeI3sCfrhrwQaik/i68ovjlYbb3GRgcB/Q5SZKdmqGcyTpgOAu9O4K3pKiNPrBWDY7NzLpax0BSmF691mj3MBvhHQk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com; spf=pass smtp.mailfrom=redhat.com; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b=HavLCzNI; arc=none smtp.client-ip=170.10.129.124 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=redhat.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=redhat.com header.i=@redhat.com header.b="HavLCzNI" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1754512796; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=dmhepafm0TOsow0EGo0RSETMNdoSQ3DnpqhK9FsEIx8=; b=HavLCzNIOwku0ZC+QSUyioqve82+esIzz4d+Inom7WkHjtx/+FE5nrDTjZC+zwr4ky+4lO kF/agCScuZJSYdagbxfiGUBVDWPDySkp6WAbWLg7XZ7LcwMGaph18QHqQLJPMc/69S80J2 xGk9fi00IM63KUvr1k2mG/uq6Red8a4= Received: from mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-635-sBmFLl4uNSSSd-fvQyqKsg-1; Wed, 06 Aug 2025 16:39:52 -0400 X-MC-Unique: sBmFLl4uNSSSd-fvQyqKsg-1 X-Mimecast-MFC-AGG-ID: sBmFLl4uNSSSd-fvQyqKsg_1754512784 Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 5DCDF180035B; Wed, 6 Aug 2025 20:39:44 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.42.28.17]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id CDE681956086; Wed, 6 Aug 2025 20:39:40 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Wang Zhaolong , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, netfs@lists.linux.dev, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 31/31] cifs: Convert SMB2 Open request Date: Wed, 6 Aug 2025 21:36:52 +0100 Message-ID: <20250806203705.2560493-32-dhowells@redhat.com> In-Reply-To: <20250806203705.2560493-1-dhowells@redhat.com> References: <20250806203705.2560493-1-dhowells@redhat.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 Content-Type: text/plain; charset="utf-8" Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: Shyam Prasad N cc: Tom Talpey cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org --- fs/smb/client/cached_dir.c | 41 +- fs/smb/client/cifsglob.h | 5 +- fs/smb/client/smb2inode.c | 6 +- fs/smb/client/smb2ops.c | 34 +- fs/smb/client/smb2pdu.c | 877 +++++++++++++++---------------------- fs/smb/client/smb2proto.h | 29 +- 6 files changed, 399 insertions(+), 593 deletions(-) diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index 368e870624da..e4534f6b31da 100644 --- a/fs/smb/client/cached_dir.c +++ b/fs/smb/client/cached_dir.c @@ -141,9 +141,7 @@ int open_cached_dir(unsigned int xid, struct cifs_tcon = *tcon, struct cifs_open_parms oparms; struct smb2_create_rsp *o_rsp =3D NULL; struct smb2_query_info_rsp *qi_rsp =3D NULL; - int resp_buftype[2]; - struct smb_rqst rqst[2]; - struct kvec rsp_iov[2]; + struct smb_message *smb; struct kvec open_iov[SMB2_CREATE_IOV_SIZE]; struct kvec qi_iov[1]; int rc, flags =3D 0; @@ -260,29 +258,20 @@ int open_cached_dir(unsigned int xid, struct cifs_tco= n *tcon, =20 server->ops->new_lease_key(pfid); =20 - memset(rqst, 0, sizeof(rqst)); - resp_buftype[0] =3D resp_buftype[1] =3D CIFS_NO_BUFFER; - memset(rsp_iov, 0, sizeof(rsp_iov)); - /* Open */ - memset(&open_iov, 0, sizeof(open_iov)); - rqst[0].rq_iov =3D open_iov; - rqst[0].rq_nvec =3D SMB2_CREATE_IOV_SIZE; - oparms =3D (struct cifs_open_parms) { - .tcon =3D tcon, - .path =3D path, - .create_options =3D cifs_create_options(cifs_sb, CREATE_NOT_FILE), - .desired_access =3D FILE_READ_DATA | FILE_READ_ATTRIBUTES | - FILE_READ_EA, - .disposition =3D FILE_OPEN, - .fid =3D pfid, - .lease_flags =3D lease_flags, - .replay =3D !!(retries), + .tcon =3D tcon, + .path =3D path, + .create_options =3D cifs_create_options(cifs_sb, CREATE_NOT_FILE), + .desired_access =3D FILE_READ_DATA | FILE_READ_ATTRIBUTES | + FILE_READ_EA, + .disposition =3D FILE_OPEN, + .fid =3D pfid, + .lease_flags =3D lease_flags, + .replay =3D !!(retries), }; =20 - rc =3D SMB2_open_init(tcon, server, - &rqst[0], &oplock, &oparms, utf16_path); + smb =3D SMB2_open_init(tcon, server, &oplock, &oparms, utf16_path); if (rc) goto oshr_free; smb2_set_next_command(tcon, &rqst[0]); @@ -336,10 +325,10 @@ int open_cached_dir(unsigned int xid, struct cifs_tco= n *tcon, goto oshr_free; } =20 - rc =3D smb2_parse_contexts(server, rsp_iov, - &oparms.fid->epoch, - oparms.fid->lease_key, - &oplock, NULL, NULL); + rc =3D smb2_parse_create_response(server, rsp_iov, + &oparms.fid->epoch, + oparms.fid->lease_key, + &oplock, NULL, NULL); if (rc) { spin_unlock(&cfids->cfid_list_lock); goto oshr_free; diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 0cc71f504c68..b96c45f57c2b 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -554,8 +554,9 @@ struct smb_version_operations { /* set oplock level for the inode */ void (*set_oplock_level)(struct cifsInodeInfo *cinode, __u32 oplock, __u1= 6 epoch, bool *purge_cache); - /* create lease context buffer for CREATE request */ - char * (*create_lease_buf)(u8 *lease_key, u8 oplock, u8 *parent_lease_key= , __le32 le_flags); + /* Fill in a lease context buffer for CREATE request */ + void (*fill_lease_buf)(struct smb_message *smb, const u8 *lease_key, u8 o= plock, + const u8 *parent_lease_key, __le32 le_flags); /* parse lease context buffer and return oplock/epoch info */ __u8 (*parse_lease_buf)(void *buf, __u16 *epoch, char *lkey); ssize_t (*copychunk_range)(const unsigned int, diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 2a3e46b8e15a..c5041fa94779 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -663,9 +663,9 @@ static int smb2_compound_op(const unsigned int xid, str= uct cifs_tcon *tcon, idata->fi.DeletePending =3D 0; idata->fi.Directory =3D !!(le32_to_cpu(create_rsp->FileAttributes) & ATT= R_DIRECTORY); =20 - /* smb2_parse_contexts() fills idata->fi.IndexNumber */ - rc =3D smb2_parse_contexts(server, &rsp_iov[0], &oparms->fid->epoch, - oparms->fid->lease_key, &oplock, &idata->fi, NULL); + /* smb2_parse_create_response() fills idata->fi.IndexNumber */ + rc =3D smb2_parse_create_response(server, &rsp_iov[0], &oparms->fid->epo= ch, + oparms->fid->lease_key, &oplock, &idata->fi, NULL); if (rc) cifs_dbg(VFS, "rc: %d parsing context of compound op\n", rc); } diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 9db383ec22e8..7c30475054b8 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4086,14 +4086,11 @@ map_oplock_to_lease(u8 oplock) return 0; } =20 -static char * -smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le= 32 flags) +static void +smb2_fill_lease_buf(struct smb_message *smb, const u8 *lease_key, u8 oploc= k, + const u8 *parent_lease_key, __le32 flags) { - struct create_lease *buf; - - buf =3D kzalloc(sizeof(struct create_lease), GFP_KERNEL); - if (!buf) - return NULL; + struct create_lease *buf =3D cifs_begin_extension(smb); =20 memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE); buf->lcontext.LeaseState =3D map_oplock_to_lease(oplock); @@ -4109,17 +4106,14 @@ smb2_create_lease_buf(u8 *lease_key, u8 oplock, u8 = *parent_lease_key, __le32 fla buf->Name[1] =3D 'q'; buf->Name[2] =3D 'L'; buf->Name[3] =3D 's'; - return (char *)buf; + cifs_end_extension(smb, sizeof(*buf)); } =20 -static char * -smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *parent_lease_key, __le= 32 flags) +static void +smb3_fill_lease_buf(struct smb_message *smb, const u8 *lease_key, u8 oploc= k, + const u8 *parent_lease_key, __le32 flags) { - struct create_lease_v2 *buf; - - buf =3D kzalloc(sizeof(struct create_lease_v2), GFP_KERNEL); - if (!buf) - return NULL; + struct create_lease_v2 *buf =3D cifs_begin_extension(smb); =20 memcpy(&buf->lcontext.LeaseKey, lease_key, SMB2_LEASE_KEY_SIZE); buf->lcontext.LeaseState =3D map_oplock_to_lease(oplock); @@ -4138,7 +4132,7 @@ smb3_create_lease_buf(u8 *lease_key, u8 oplock, u8 *p= arent_lease_key, __le32 fla buf->Name[1] =3D 'q'; buf->Name[2] =3D 'L'; buf->Name[3] =3D 's'; - return (char *)buf; + cifs_end_extension(smb, sizeof(*buf)); } =20 static __u8 @@ -5263,7 +5257,7 @@ struct smb_version_operations smb20_operations =3D { .calc_signature =3D smb2_calc_signature, .is_read_op =3D smb2_is_read_op, .set_oplock_level =3D smb2_set_oplock_level, - .create_lease_buf =3D smb2_create_lease_buf, + .fill_lease_buf =3D smb2_fill_lease_buf, .parse_lease_buf =3D smb2_parse_lease_buf, .copychunk_range =3D smb2_copychunk_range, .wp_retry_size =3D smb2_wp_retry_size, @@ -5366,7 +5360,7 @@ struct smb_version_operations smb21_operations =3D { .calc_signature =3D smb2_calc_signature, .is_read_op =3D smb21_is_read_op, .set_oplock_level =3D smb21_set_oplock_level, - .create_lease_buf =3D smb2_create_lease_buf, + .fill_lease_buf =3D smb2_fill_lease_buf, .parse_lease_buf =3D smb2_parse_lease_buf, .copychunk_range =3D smb2_copychunk_range, .wp_retry_size =3D smb2_wp_retry_size, @@ -5476,7 +5470,7 @@ struct smb_version_operations smb30_operations =3D { .set_integrity =3D smb3_set_integrity, .is_read_op =3D smb21_is_read_op, .set_oplock_level =3D smb3_set_oplock_level, - .create_lease_buf =3D smb3_create_lease_buf, + .fill_lease_buf =3D smb3_fill_lease_buf, .parse_lease_buf =3D smb3_parse_lease_buf, .copychunk_range =3D smb2_copychunk_range, .duplicate_extents =3D smb2_duplicate_extents, @@ -5592,7 +5586,7 @@ struct smb_version_operations smb311_operations =3D { .set_integrity =3D smb3_set_integrity, .is_read_op =3D smb21_is_read_op, .set_oplock_level =3D smb3_set_oplock_level, - .create_lease_buf =3D smb3_create_lease_buf, + .fill_lease_buf =3D smb3_fill_lease_buf, .parse_lease_buf =3D smb3_parse_lease_buf, .copychunk_range =3D smb2_copychunk_range, .duplicate_extents =3D smb2_duplicate_extents, diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 9fc55b315474..e9827aeab43f 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2387,298 +2387,179 @@ SMB2_tdis(const unsigned int xid, struct cifs_tco= n *tcon) return rc; } =20 - -static void fill_posix_buf(struct create_posix *buf, umode_t mode) +/* + * Begin a create context record. This fills in the chain pointer on the + * previous record if there was one. + */ +static void *cifs_begin_ccontext(struct smb_message *smb) { - buf->ccontext.DataOffset =3D - cpu_to_le16(offsetof(struct create_posix, Mode)); - buf->ccontext.DataLength =3D cpu_to_le32(4); - buf->ccontext.NameOffset =3D - cpu_to_le16(offsetof(struct create_posix, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(16); + struct create_context_hdr *ccontext =3D cifs_begin_extension(smb); =20 - /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ - buf->Name[0] =3D 0x93; - buf->Name[1] =3D 0xAD; - buf->Name[2] =3D 0x25; - buf->Name[3] =3D 0x50; - buf->Name[4] =3D 0x9C; - buf->Name[5] =3D 0xB4; - buf->Name[6] =3D 0x11; - buf->Name[7] =3D 0xE7; - buf->Name[8] =3D 0xB4; - buf->Name[9] =3D 0x23; - buf->Name[10] =3D 0x83; - buf->Name[11] =3D 0xDE; - buf->Name[12] =3D 0x96; - buf->Name[13] =3D 0x8B; - buf->Name[14] =3D 0xCD; - buf->Name[15] =3D 0x7C; - buf->Mode =3D cpu_to_le32(mode); - cifs_dbg(FYI, "mode on posix create 0%o\n", mode); + if (smb->latest_record) { + struct create_context_hdr *latest =3D smb->request + smb->latest_record; + + latest->Next =3D cpu_to_le32(smb->offset - smb->latest_record); + } + smb->latest_record =3D smb->offset; + return ccontext; } =20 -static int -add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) +#define CREATE_CONTEXT_HDR(ptr, name, data, namelen) { \ + .NameOffset =3D cpu_to_le16(offsetof(ptr, name)), \ + .NameLength =3D cpu_to_le16(namelen), \ + .DataOffset =3D cpu_to_le16(offsetof(ptr, data)), \ + .DataLength =3D cpu_to_le32(sizeof_field(ptr, data)), \ + } + +static void fill_posix_context(struct smb_message *smb, umode_t mode) { - struct create_posix *buf; - unsigned int num =3D *num_iovec; + struct create_posix *buf =3D cifs_begin_ccontext(smb); =20 if (mode =3D=3D ACL_NO_MODE) cifs_dbg(FYI, "%s: no mode\n", __func__); =20 - buf =3D kzalloc(sizeof(struct create_posix), GFP_KERNEL); - if (!buf) - return -ENOMEM; - - fill_posix_buf(buf, mode); - - iov[num].iov_base =3D buf; - iov[num].iov_len =3D sizeof(struct create_posix); - *num_iovec =3D num + 1; - return 0; + *buf =3D (struct create_posix){ + .ccontext =3D CREATE_CONTEXT_HDR(struct create_posix, Name, Mode, 16), + /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ + .Name =3D { + 0x93, 0xAD, 0x25, 0x50, 0x9C, 0xB4, 0x11, 0xE7, + 0xB4, 0x23, 0x83, 0xDE, 0x96, 0x8B, 0xCD, 0x7C + }, + .Mode =3D cpu_to_le32(mode), + }; + cifs_dbg(FYI, "mode on posix create 0%o\n", mode); + cifs_end_extension(smb, sizeof(*buf)); } =20 -static struct create_durable * -create_durable_buf(void) +static void fill_lease_context(struct TCP_Server_Info *server, + struct smb2_create_req *req, + struct smb_message *smb, + u8 *lease_key, + __u8 *oplock, + u8 *parent_lease_key, + __le32 flags) { - struct create_durable *buf; - - buf =3D kzalloc(sizeof(struct create_durable), GFP_KERNEL); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (struct create_durable, Data)); - buf->ccontext.DataLength =3D cpu_to_le32(16); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (struct create_durable, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); - /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */ - buf->Name[0] =3D 'D'; - buf->Name[1] =3D 'H'; - buf->Name[2] =3D 'n'; - buf->Name[3] =3D 'Q'; - return buf; + req->RequestedOplockLevel =3D SMB2_OPLOCK_LEVEL_LEASE; + server->ops->fill_lease_buf(smb, lease_key, *oplock, + parent_lease_key, flags); } =20 -static struct create_durable * -create_reconnect_durable_buf(struct cifs_fid *fid) +static void fill_durable_v1_context(struct smb_message *smb) { - struct create_durable *buf; + struct create_durable *buf =3D cifs_begin_ccontext(smb); =20 - buf =3D kzalloc(sizeof(struct create_durable), GFP_KERNEL); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (struct create_durable, Data)); - buf->ccontext.DataLength =3D cpu_to_le32(16); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (struct create_durable, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); - buf->Data.Fid.PersistentFileId =3D fid->persistent_fid; - buf->Data.Fid.VolatileFileId =3D fid->volatile_fid; - /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT is "DHnC" */ - buf->Name[0] =3D 'D'; - buf->Name[1] =3D 'H'; - buf->Name[2] =3D 'n'; - buf->Name[3] =3D 'C'; - return buf; + *buf =3D (struct create_durable){ + .ccontext =3D CREATE_CONTEXT_HDR(struct create_durable, Name, Data, 4), + /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DHnQ" */ + .Name =3D {'D', 'H', 'n', 'Q' }, + }; + cifs_end_extension(smb, sizeof(*buf)); } =20 -static int -add_lease_context(struct TCP_Server_Info *server, - struct smb2_create_req *req, - struct kvec *iov, - unsigned int *num_iovec, - u8 *lease_key, - __u8 *oplock, - u8 *parent_lease_key, - __le32 flags) +static void fill_reconnect_durable_context(struct smb_message *smb, + struct cifs_open_parms *oparms) { - unsigned int num =3D *num_iovec; + struct create_durable *buf =3D cifs_begin_ccontext(smb); + struct cifs_fid *fid =3D oparms->fid; =20 - iov[num].iov_base =3D server->ops->create_lease_buf(lease_key, *oplock, - parent_lease_key, flags); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D server->vals->create_lease_size; - req->RequestedOplockLevel =3D SMB2_OPLOCK_LEVEL_LEASE; - *num_iovec =3D num + 1; - return 0; + /* indicate that we don't need to relock the file */ + oparms->reconnect =3D false; + + *buf =3D (struct create_durable){ + .ccontext =3D CREATE_CONTEXT_HDR(struct create_durable, Name, Data, 4), + /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT is "DHnC" */ + .Name =3D {'D', 'H', 'n', 'C' }, + .Data.Fid.PersistentFileId =3D fid->persistent_fid, + .Data.Fid.VolatileFileId =3D fid->volatile_fid, + }; + cifs_end_extension(smb, sizeof(*buf)); } =20 -static struct create_durable_v2 * -create_durable_v2_buf(struct cifs_open_parms *oparms) +static void fill_durable_v2_context(struct smb_message *smb, + struct cifs_open_parms *oparms) { - struct cifs_fid *pfid =3D oparms->fid; - struct create_durable_v2 *buf; + struct create_durable_v2 *buf =3D cifs_begin_ccontext(smb); + struct cifs_fid *fid =3D oparms->fid; =20 - buf =3D kzalloc(sizeof(struct create_durable_v2), GFP_KERNEL); - if (!buf) - return NULL; + *buf =3D (struct create_durable_v2){ + .ccontext =3D CREATE_CONTEXT_HDR(struct create_durable_v2, Name, dcontex= t, 4), + /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ + .Name =3D {'D', 'H', '2', 'Q' }, =20 - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (struct create_durable_v2, dcontext)); - buf->ccontext.DataLength =3D cpu_to_le32(sizeof(struct durable_context_v2= )); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (struct create_durable_v2, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); - - /* - * NB: Handle timeout defaults to 0, which allows server to choose - * (most servers default to 120 seconds) and most clients default to 0. - * This can be overridden at mount ("handletimeout=3D") if the user wants - * a different persistent (or resilient) handle timeout for all opens - * on a particular SMB3 mount. - */ - buf->dcontext.Timeout =3D cpu_to_le32(oparms->tcon->handle_timeout); - buf->dcontext.Flags =3D cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); + /* + * NB: Handle timeout defaults to 0, which allows server to + * choose (most servers default to 120 seconds) and most + * clients default to 0. This can be overridden at mount + * ("handletimeout=3D") if the user wants a different persistent + * (or resilient) handle timeout for all opens on a particular + * SMB3 mount. + */ + .dcontext.Timeout =3D cpu_to_le32(oparms->tcon->handle_timeout), + .dcontext.Flags =3D cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT), + }; =20 /* for replay, we should not overwrite the existing create guid */ if (!oparms->replay) { generate_random_uuid(buf->dcontext.CreateGuid); - memcpy(pfid->create_guid, buf->dcontext.CreateGuid, 16); - } else - memcpy(buf->dcontext.CreateGuid, pfid->create_guid, 16); - - /* SMB2_CREATE_DURABLE_HANDLE_REQUEST is "DH2Q" */ - buf->Name[0] =3D 'D'; - buf->Name[1] =3D 'H'; - buf->Name[2] =3D '2'; - buf->Name[3] =3D 'Q'; - return buf; -} - -static struct create_durable_handle_reconnect_v2 * -create_reconnect_durable_v2_buf(struct cifs_fid *fid) -{ - struct create_durable_handle_reconnect_v2 *buf; - - buf =3D kzalloc(sizeof(struct create_durable_handle_reconnect_v2), - GFP_KERNEL); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D - cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2, - dcontext)); - buf->ccontext.DataLength =3D - cpu_to_le32(sizeof(struct durable_reconnect_context_v2)); - buf->ccontext.NameOffset =3D - cpu_to_le16(offsetof(struct create_durable_handle_reconnect_v2, - Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); - - buf->dcontext.Fid.PersistentFileId =3D fid->persistent_fid; - buf->dcontext.Fid.VolatileFileId =3D fid->volatile_fid; - buf->dcontext.Flags =3D cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT); - memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16); - - /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */ - buf->Name[0] =3D 'D'; - buf->Name[1] =3D 'H'; - buf->Name[2] =3D '2'; - buf->Name[3] =3D 'C'; - return buf; -} - -static int -add_durable_v2_context(struct kvec *iov, unsigned int *num_iovec, - struct cifs_open_parms *oparms) -{ - unsigned int num =3D *num_iovec; + memcpy(fid->create_guid, buf->dcontext.CreateGuid, 16); + } else { + memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16); + } =20 - iov[num].iov_base =3D create_durable_v2_buf(oparms); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct create_durable_v2); - *num_iovec =3D num + 1; - return 0; + cifs_end_extension(smb, sizeof(*buf)); } =20 -static int -add_durable_reconnect_v2_context(struct kvec *iov, unsigned int *num_iovec, - struct cifs_open_parms *oparms) +static void fill_durable_reconnect_v2_context(struct smb_message *smb, + struct cifs_open_parms *oparms) { - unsigned int num =3D *num_iovec; + struct create_durable_handle_reconnect_v2 *buf =3D cifs_begin_ccontext(sm= b); + struct cifs_fid *fid =3D oparms->fid; =20 /* indicate that we don't need to relock the file */ oparms->reconnect =3D false; =20 - iov[num].iov_base =3D create_reconnect_durable_v2_buf(oparms->fid); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct create_durable_handle_reconnect_v2); - *num_iovec =3D num + 1; - return 0; + *buf =3D (struct create_durable_handle_reconnect_v2){ + .ccontext =3D CREATE_CONTEXT_HDR(struct create_durable_handle_reconnect_= v2, + Name, dcontext, 4), + /* SMB2_CREATE_DURABLE_HANDLE_RECONNECT_V2 is "DH2C" */ + .Name =3D {'D', 'H', '2', 'C' }, + .dcontext.Fid.PersistentFileId =3D fid->persistent_fid, + .dcontext.Fid.VolatileFileId =3D fid->volatile_fid, + .dcontext.Flags =3D cpu_to_le32(SMB2_DHANDLE_FLAG_PERSISTENT), + }; + + memcpy(buf->dcontext.CreateGuid, fid->create_guid, 16); + cifs_end_extension(smb, sizeof(*buf)); } =20 -static int -add_durable_context(struct kvec *iov, unsigned int *num_iovec, - struct cifs_open_parms *oparms, bool use_persistent) +static void +fill_durable_context(struct smb_message *smb, + struct cifs_open_parms *oparms, bool use_persistent) { - unsigned int num =3D *num_iovec; - if (use_persistent) { if (oparms->reconnect) - return add_durable_reconnect_v2_context(iov, num_iovec, - oparms); - else - return add_durable_v2_context(iov, num_iovec, oparms); + return fill_durable_reconnect_v2_context(smb, oparms); + return fill_durable_v2_context(smb, oparms); } =20 - if (oparms->reconnect) { - iov[num].iov_base =3D create_reconnect_durable_buf(oparms->fid); - /* indicate that we don't need to relock the file */ - oparms->reconnect =3D false; - } else - iov[num].iov_base =3D create_durable_buf(); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct create_durable); - *num_iovec =3D num + 1; - return 0; + if (oparms->reconnect) + return fill_reconnect_durable_context(smb, oparms); + return fill_durable_v1_context(smb); } =20 /* See MS-SMB2 2.2.13.2.7 */ -static struct crt_twarp_ctxt * -create_twarp_buf(__u64 timewarp) +static void fill_twarp_context(struct smb_message *smb, __u64 timewarp) { - struct crt_twarp_ctxt *buf; - - buf =3D kzalloc(sizeof(struct crt_twarp_ctxt), GFP_KERNEL); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (struct crt_twarp_ctxt, Timestamp)); - buf->ccontext.DataLength =3D cpu_to_le32(8); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (struct crt_twarp_ctxt, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); - /* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */ - buf->Name[0] =3D 'T'; - buf->Name[1] =3D 'W'; - buf->Name[2] =3D 'r'; - buf->Name[3] =3D 'p'; - buf->Timestamp =3D cpu_to_le64(timewarp); - return buf; -} + struct crt_twarp_ctxt *buf =3D cifs_begin_ccontext(smb); =20 -/* See MS-SMB2 2.2.13.2.7 */ -static int -add_twarp_context(struct kvec *iov, unsigned int *num_iovec, __u64 timewar= p) -{ - unsigned int num =3D *num_iovec; + *buf =3D (struct crt_twarp_ctxt){ + .ccontext =3D CREATE_CONTEXT_HDR(struct crt_twarp_ctxt, Name, Timestamp,= 4), + /* SMB2_CREATE_TIMEWARP_TOKEN is "TWrp" */ + .Name =3D {'T', 'W', 'r', 'p' }, + .Timestamp =3D cpu_to_le64(timewarp), + }; =20 - iov[num].iov_base =3D create_twarp_buf(timewarp); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct crt_twarp_ctxt); - *num_iovec =3D num + 1; - return 0; + cifs_end_extension(smb, sizeof(*buf)); } =20 /* See http://technet.microsoft.com/en-us/library/hh509017(v=3Dws.10).aspx= */ @@ -2706,26 +2587,21 @@ static void setup_owner_group_sids(char *buf) } =20 /* See MS-SMB2 2.2.13.2.2 and MS-DTYP 2.4.6 */ -static struct crt_sd_ctxt * -create_sd_buf(umode_t mode, bool set_owner, unsigned int *len) +static void fill_sd_context(struct smb_message *smb, umode_t mode, bool se= t_owner) { - struct crt_sd_ctxt *buf; + struct crt_sd_ctxt *buf =3D cifs_begin_extension(smb); __u8 *ptr, *aclptr; unsigned int acelen, acl_size, ace_count; unsigned int owner_offset =3D 0; unsigned int group_offset =3D 0; + unsigned int len; struct smb3_acl acl =3D {}; =20 - *len =3D ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4)= ); + len =3D ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4)); =20 - if (set_owner) { + if (set_owner) /* sizeof(struct owner_group_sids) is already multiple of 8 so no need t= o round */ - *len +=3D sizeof(struct owner_group_sids); - } - - buf =3D kzalloc(*len, GFP_KERNEL); - if (buf =3D=3D NULL) - return buf; + len +=3D sizeof(struct owner_group_sids); =20 ptr =3D (__u8 *)&buf[1]; if (set_owner) { @@ -2791,33 +2667,15 @@ create_sd_buf(umode_t mode, bool set_owner, unsigne= d int *len) memcpy(aclptr, &acl, sizeof(struct smb3_acl)); =20 buf->ccontext.DataLength =3D cpu_to_le32(ptr - (__u8 *)&buf->sd); - *len =3D ALIGN8((unsigned int)(ptr - (__u8 *)buf)); - - return buf; -} - -static int -add_sd_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode, bo= ol set_owner) -{ - unsigned int num =3D *num_iovec; - unsigned int len =3D 0; - - iov[num].iov_base =3D create_sd_buf(mode, set_owner, &len); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D len; - *num_iovec =3D num + 1; - return 0; + len =3D ALIGN8((unsigned int)(ptr - (__u8 *)buf)); + cifs_end_extension(smb, len); + cifs_pad_to_8(smb); } =20 -static struct crt_query_id_ctxt * -create_query_id_buf(void) +/* See MS-SMB2 2.2.13.2.9 */ +static void fill_query_id_context(struct smb_message *smb) { - struct crt_query_id_ctxt *buf; - - buf =3D kzalloc(sizeof(struct crt_query_id_ctxt), GFP_KERNEL); - if (!buf) - return NULL; + struct crt_query_id_ctxt *buf =3D cifs_begin_extension(smb); =20 buf->ccontext.DataOffset =3D cpu_to_le16(0); buf->ccontext.DataLength =3D cpu_to_le32(0); @@ -2829,78 +2687,19 @@ create_query_id_buf(void) buf->Name[1] =3D 'F'; buf->Name[2] =3D 'i'; buf->Name[3] =3D 'd'; - return buf; -} - -/* See MS-SMB2 2.2.13.2.9 */ -static int -add_query_id_context(struct kvec *iov, unsigned int *num_iovec) -{ - unsigned int num =3D *num_iovec; - - iov[num].iov_base =3D create_query_id_buf(); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct crt_query_id_ctxt); - *num_iovec =3D num + 1; - return 0; + cifs_end_extension(smb, sizeof(*buf)); } =20 -static void add_ea_context(struct cifs_open_parms *oparms, - struct kvec *rq_iov, unsigned int *num_iovs) +static void fill_ea_context(struct smb_message *smb, const struct cifs_ope= n_parms *oparms) { - struct kvec *iov =3D oparms->ea_cctx; + const struct kvec *iov =3D oparms->ea_cctx; =20 if (iov && iov->iov_base && iov->iov_len) { - rq_iov[(*num_iovs)++] =3D *iov; - memset(iov, 0, sizeof(*iov)); - } -} - -static int -alloc_path_with_tree_prefix(__le16 **out_path, int *out_size, int *out_len, - const char *treename, const __le16 *path) -{ - int treename_len, path_len; - struct nls_table *cp; - const __le16 sep[] =3D {cpu_to_le16('\\'), cpu_to_le16(0x0000)}; + void *p =3D cifs_begin_extension(smb); =20 - /* - * skip leading "\\" - */ - treename_len =3D strlen(treename); - if (treename_len < 2 || !(treename[0] =3D=3D '\\' && treename[1] =3D=3D '= \\')) - return -EINVAL; - - treename +=3D 2; - treename_len -=3D 2; - - path_len =3D UniStrnlen((wchar_t *)path, PATH_MAX); - - /* make room for one path separator only if @path isn't empty */ - *out_len =3D treename_len + (path[0] ? 1 : 0) + path_len; - - /* - * final path needs to be 8-byte aligned as specified in - * MS-SMB2 2.2.13 SMB2 CREATE Request. - */ - *out_size =3D ALIGN8(*out_len * sizeof(__le16)); - *out_path =3D kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL); - if (!*out_path) - return -ENOMEM; - - cp =3D load_nls_default(); - cifs_strtoUTF16(*out_path, treename, treename_len, cp); - - /* Do not append the separator if the path is empty */ - if (path[0] !=3D cpu_to_le16(0x0000)) { - UniStrcat((wchar_t *)*out_path, (wchar_t *)sep); - UniStrcat((wchar_t *)*out_path, (wchar_t *)path); + memcpy(p, iov->iov_base, iov->iov_len); + cifs_end_extension(smb, iov->iov_len); } - - unload_nls(cp); - - return 0; } =20 struct smb2_create_layout { @@ -2912,7 +2711,6 @@ struct smb2_create_layout { 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 */ }; =20 @@ -2920,8 +2718,6 @@ static int smb311_posix_mkdir_layout(struct cifs_tcon= *tcon, struct smb2_create_layout *lay) { size_t offset =3D lay->offset; - size_t tmp; - bool has_contexts =3D false; =20 /* [MS-SMB2] 2.2.13 NameOffset: If SMB2_FLAGS_DFS_OPERATIONS * is set in the Flags field of the SMB2 header, the file name @@ -2950,22 +2746,17 @@ static int smb311_posix_mkdir_layout(struct cifs_tc= on *tcon, } =20 offset +=3D lay->name_len; - tmp =3D offset; - offset =3D ALIGN8(offset); - lay->name_pad =3D offset - tmp; + offset =3D ALIGN(offset, 8); lay->contexts_offset =3D offset; =20 - if (tcon->posix_extensions) { + if (tcon->posix_extensions) /* resource #3: posix buf */ offset +=3D sizeof(struct create_posix); - has_contexts =3D true; - } =20 - if (has_contexts) - lay->contexts_len =3D offset - lay->contexts_offset; + if (offset =3D=3D lay->contexts_offset) + lay->contexts_offset =3D 0; /* None */ else - lay->contexts_offset =3D 0; - + lay->contexts_len =3D offset - lay->contexts_offset; lay->offset =3D offset; return 0; } @@ -3065,13 +2856,12 @@ int smb311_posix_mkdir(const unsigned int xid, stru= ct inode *inode, memcpy(name, utf16_path, layout.path_len); } =20 - if (layout.name_pad) - memset(smb->request + layout.name_offset + layout.name_len, - 0, layout.name_pad); + smb->offset =3D layout.name_offset + layout.name_len; + cifs_pad_to_8(smb); =20 if (tcon->posix_extensions) /* resource #3: posix buf */ - fill_posix_buf(smb->request + layout.posix_offset, mode); + fill_posix_context(smb, mode); =20 /* 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, @@ -3119,81 +2909,185 @@ int smb311_posix_mkdir(const unsigned int xid, str= uct inode *inode, return rc; } =20 -int -SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, - struct smb_rqst *rqst, __u8 *oplock, - struct cifs_open_parms *oparms, __le16 *path) +/* + * Calculate the request size and layout for an "open" (i.e. Create) reque= st. + */ +static int smb2_lay_out_open(const struct cifs_tcon *tcon, + const struct TCP_Server_Info *server, + __u8 oplock, + const struct cifs_open_parms *oparms, + struct smb2_create_layout *lay) +{ + size_t offset =3D lay->offset, csize, tmp; + + /* [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 =3D offset; + if (tcon->share_flags & SHI1005_FLAGS_DFS) { + const char *treename =3D tcon->tree_name; + int treename_len; + + /* skip leading "\\" */ + if (!(treename[0] =3D=3D '\\' && treename[1] =3D=3D '\\')) + return -EINVAL; + + treename_len =3D cifs_size_strtoUTF16(treename + 2, INT_MAX, lay->cp); + + lay->treename_len =3D treename_len; + lay->name_len =3D treename_len; + if (lay->path_len) + lay->name_len +=3D 2 + lay->path_len; + } else { + lay->name_len =3D lay->path_len; + } + + offset +=3D lay->name_len; + tmp =3D offset; + offset =3D round_up(offset, 8); + lay->name_pad =3D offset - tmp; + lay->contexts_offset =3D offset; + + /* TODO: This bit of code is very suspicious. */ + if (!(server->capabilities & SMB2_GLOBAL_CAP_LEASING) || + oplock =3D=3D SMB2_OPLOCK_LEVEL_NONE) + ; + else if (!(server->capabilities & SMB2_GLOBAL_CAP_DIRECTORY_LEASING) && + (oparms->create_options & CREATE_NOT_FILE)) + ; /* no srv lease support */ + else + offset =3D ALIGN(offset, 8) + server->vals->create_lease_size; + + if (oplock =3D=3D SMB2_OPLOCK_LEVEL_BATCH) { + if (!tcon->use_persistent) + csize =3D sizeof(struct create_durable); + else if (oparms->reconnect) + csize =3D sizeof(struct create_durable_handle_reconnect_v2); + else + csize =3D sizeof(struct create_durable_v2); + offset =3D ALIGN(offset, 8) + csize; + } + + if (tcon->posix_extensions) + offset =3D ALIGN(offset, 8) + sizeof(struct create_posix); + if (tcon->snapshot_time) + offset =3D ALIGN(offset, 8) + sizeof(struct crt_twarp_ctxt); + + if (oparms->disposition !=3D FILE_OPEN && oparms->cifs_sb) { + bool set_mode; + bool set_owner; + + set_mode =3D (oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MODE_FROM_SID= ) && + (oparms->mode !=3D ACL_NO_MODE); + + set_owner =3D oparms->cifs_sb->mnt_cifs_flags & CIFS_MOUNT_UID_FROM_ACL; + + if (set_owner || set_mode) { + csize =3D sizeof(struct crt_sd_ctxt) + sizeof(struct smb_ace) * 4; + csize =3D round_up(csize, 8); + + if (set_owner) { + /* sizeof(struct owner_group_sids) is already + * multiple of 8 so no need to round */ + csize +=3D sizeof(struct owner_group_sids); + } + } + offset =3D ALIGN(offset, 8) + csize; + } + + offset =3D ALIGN(offset, 8) + sizeof(struct crt_query_id_ctxt); + + /* TODO: Pass down the desired EA list and render directly into the buffe= r. */ + if (oparms->ea_cctx->iov_base && oparms->ea_cctx->iov_len) + offset =3D ALIGN(offset, 8) + oparms->ea_cctx->iov_len; + + if (tcon->posix_extensions) + offset =3D ALIGN(offset, 8) + sizeof(struct create_posix); + + lay->contexts_len =3D offset - lay->contexts_offset; + lay->offset =3D offset; + return 0; +} + +struct smb_message *SMB2_open_init(struct cifs_tcon *tcon, + struct TCP_Server_Info *server, __u8 *oplock, + struct cifs_open_parms *oparms, __le16 *path) { struct smb2_create_req *req; - unsigned int n_iov =3D 2; + struct smb_message *smb; __u32 file_attributes =3D 0; - int copy_size; - int uni_path_len; - unsigned int total_len; - struct kvec *iov =3D rqst->rq_iov; - __le16 *copy_path; int rc; =20 - rc =3D smb2_plain_req_init(SMB2_CREATE, tcon, server, - (void **) &req, &total_len); - if (rc) - return rc; + if (!server->oplocks || tcon->no_lease) + *oplock =3D SMB2_OPLOCK_LEVEL_NONE; =20 - iov[0].iov_base =3D (char *)req; - /* -1 since last byte is buf[0] which is sent below (path) */ - iov[0].iov_len =3D total_len - 1; + struct smb2_create_layout layout =3D { + .cp =3D oparms->cifs_sb->local_nls, + .offset =3D sizeof(struct smb2_create_req), + .path_len =3D UniStrnlen((wchar_t *)path, PATH_MAX) * 2, + }; + + rc =3D smb2_lay_out_open(tcon, server, *oplock, oparms, &layout); + if (rc < 0) + return ERR_PTR(rc); + + smb =3D smb2_create_request(SMB2_CREATE, server, tcon, + sizeof(*req), layout.offset, 0, + SMB2_REQ_DYNAMIC); + if (!smb) + return ERR_PTR(-ENOMEM); =20 if (oparms->create_options & CREATE_OPTION_READONLY) file_attributes |=3D ATTR_READONLY; if (oparms->create_options & CREATE_OPTION_SPECIAL) file_attributes |=3D ATTR_SYSTEM; =20 - req->ImpersonationLevel =3D IL_IMPERSONATION; - req->DesiredAccess =3D cpu_to_le32(oparms->desired_access); + req->ImpersonationLevel =3D IL_IMPERSONATION; + req->DesiredAccess =3D cpu_to_le32(oparms->desired_access); /* File attributes ignored on open (used in create though) */ - req->FileAttributes =3D cpu_to_le32(file_attributes); - req->ShareAccess =3D FILE_SHARE_ALL_LE; - - req->CreateDisposition =3D cpu_to_le32(oparms->disposition); - req->CreateOptions =3D cpu_to_le32(oparms->create_options & CREATE_OPTION= S_MASK); - req->NameOffset =3D cpu_to_le16(sizeof(struct smb2_create_req)); + req->FileAttributes =3D cpu_to_le32(file_attributes); + req->ShareAccess =3D FILE_SHARE_ALL_LE; + req->CreateDisposition =3D cpu_to_le32(oparms->disposition); + req->CreateOptions =3D cpu_to_le32(oparms->create_options & CREATE_OPTION= S_MASK); + req->NameOffset =3D cpu_to_le16(layout.name_offset); + req->NameLength =3D cpu_to_le16(layout.name_len); + req->RequestedOplockLevel =3D SMB2_OPLOCK_LEVEL_NONE; + req->CreateContextsOffset =3D cpu_to_le32(layout.contexts_offset); + req->CreateContextsLength =3D cpu_to_le32(layout.contexts_len); =20 /* [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. + * 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. */ + __le16 *name =3D smb->request + layout.name_offset; + if (tcon->share_flags & SHI1005_FLAGS_DFS) { - int name_len; + int tmp; =20 req->hdr.Flags |=3D SMB2_FLAGS_DFS_OPERATIONS; - rc =3D alloc_path_with_tree_prefix(©_path, ©_size, - &name_len, - tcon->tree_name, path); - if (rc) - return rc; - req->NameLength =3D cpu_to_le16(name_len * 2); - uni_path_len =3D copy_size; - path =3D copy_path; - } else { - uni_path_len =3D (2 * UniStrnlen((wchar_t *)path, PATH_MAX)) + 2; - /* MUST set path len (NameLength) to 0 opening root of share */ - req->NameLength =3D cpu_to_le16(uni_path_len - 2); - copy_size =3D ALIGN8(uni_path_len); - copy_path =3D kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) - return -ENOMEM; - memcpy((char *)copy_path, (const char *)path, - uni_path_len); - uni_path_len =3D copy_size; - path =3D copy_path; + + tmp =3D cifs_strtoUTF16(name, tcon->tree_name + 2, INT_MAX, + layout.cp); + WARN_ON(tmp !=3D layout.treename_len); + name +=3D tmp; + if (layout.path_len) { + *name++ =3D cpu_to_le16('\\'); + memcpy(name, path, layout.path_len); + } + } else if (layout.path_len) { + memcpy(name, path, layout.path_len); } =20 - iov[1].iov_len =3D uni_path_len; - iov[1].iov_base =3D path; + smb->offset =3D layout.name_offset + layout.name_len; + cifs_pad_to_8(smb); + WARN_ON_ONCE(smb->offset !=3D layout.contexts_offset); =20 if ((!server->oplocks) || (tcon->no_lease)) *oplock =3D SMB2_OPLOCK_LEVEL_NONE; @@ -3205,32 +3099,21 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_S= erver_Info *server, (oparms->create_options & CREATE_NOT_FILE)) req->RequestedOplockLevel =3D *oplock; /* no srv lease support */ else { - rc =3D add_lease_context(server, req, iov, &n_iov, - oparms->fid->lease_key, oplock, - oparms->fid->parent_lease_key, - oparms->lease_flags); - if (rc) - return rc; + fill_lease_context(server, req, smb, + oparms->fid->lease_key, oplock, + oparms->fid->parent_lease_key, + oparms->lease_flags); } =20 - if (*oplock =3D=3D SMB2_OPLOCK_LEVEL_BATCH) { - rc =3D add_durable_context(iov, &n_iov, oparms, - tcon->use_persistent); - if (rc) - return rc; - } + if (*oplock =3D=3D SMB2_OPLOCK_LEVEL_BATCH) + fill_durable_context(smb, oparms, tcon->use_persistent); =20 - if (tcon->posix_extensions) { - rc =3D add_posix_context(iov, &n_iov, oparms->mode); - if (rc) - return rc; - } + if (tcon->posix_extensions) + fill_posix_context(smb, oparms->mode); =20 if (tcon->snapshot_time) { cifs_dbg(FYI, "adding snapshot context\n"); - rc =3D add_twarp_context(iov, &n_iov, tcon->snapshot_time); - if (rc) - return rc; + fill_twarp_context(smb, tcon->snapshot_time); } =20 if ((oparms->disposition !=3D FILE_OPEN) && (oparms->cifs_sb)) { @@ -3252,40 +3135,13 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_S= erver_Info *server, =20 if (set_owner | set_mode) { cifs_dbg(FYI, "add sd with mode 0x%x\n", oparms->mode); - rc =3D add_sd_context(iov, &n_iov, oparms->mode, set_owner); - if (rc) - return rc; + fill_sd_context(smb, oparms->mode, set_owner); } } =20 - add_query_id_context(iov, &n_iov); - add_ea_context(oparms, iov, &n_iov); - - if (n_iov > 2) { - /* - * We have create contexts behind iov[1] (the file - * name), point at them from the main create request - */ - req->CreateContextsOffset =3D cpu_to_le32( - sizeof(struct smb2_create_req) + - iov[1].iov_len); - req->CreateContextsLength =3D 0; - - for (unsigned int i =3D 2; i < (n_iov-1); i++) { - struct kvec *v =3D &iov[i]; - size_t len =3D v->iov_len; - struct create_context *cctx =3D - (struct create_context *)v->iov_base; - - cctx->Next =3D cpu_to_le32(len); - le32_add_cpu(&req->CreateContextsLength, len); - } - le32_add_cpu(&req->CreateContextsLength, - iov[n_iov-1].iov_len); - } - - rqst->rq_nvec =3D n_iov; - return 0; + fill_query_id_context(smb); + fill_ea_context(smb, oparms); + return smb; } =20 static void @@ -3333,14 +3189,14 @@ parse_posix_ctxt(struct create_context *cc, struct = smb2_file_all_info *info, posix->nlink, posix->mode, posix->reparse_tag); } =20 -int smb2_parse_contexts(struct TCP_Server_Info *server, - struct kvec *rsp_iov, - __u16 *epoch, - char *lease_key, __u8 *oplock, - struct smb2_file_all_info *buf, - struct create_posix_rsp *posix) +int smb2_parse_create_response(struct TCP_Server_Info *server, + struct smb_message *smb, + __u16 *epoch, + char *lease_key, __u8 *oplock, + struct smb2_file_all_info *buf, + struct create_posix_rsp *posix) { - struct smb2_create_rsp *rsp =3D rsp_iov->iov_base; + struct smb2_create_rsp *rsp =3D smb->response; struct create_context *cc; size_t rem, off, len; size_t doff, dlen; @@ -3356,7 +3212,7 @@ int smb2_parse_contexts(struct TCP_Server_Info *serve= r, =20 off =3D le32_to_cpu(rsp->CreateContextsOffset); rem =3D le32_to_cpu(rsp->CreateContextsLength); - if (check_add_overflow(off, rem, &len) || len > rsp_iov->iov_len) + if (check_add_overflow(off, rem, &len) || len > smb->response_len) return -EINVAL; cc =3D (struct create_context *)((u8 *)rsp + off); =20 @@ -3412,39 +3268,18 @@ int smb2_parse_contexts(struct TCP_Server_Info *ser= ver, return 0; } =20 -/* rq_iov[0] is the request and is released by cifs_small_buf_release(). - * All other vectors are freed by kfree(). - */ -void -SMB2_open_free(struct smb_rqst *rqst) -{ - int i; - - if (rqst && rqst->rq_iov) { - cifs_small_buf_release(rqst->rq_iov[0].iov_base); - for (i =3D 1; i < rqst->rq_nvec; i++) - if (rqst->rq_iov[i].iov_base !=3D smb2_padding) - kfree(rqst->rq_iov[i].iov_base); - } -} - -int -SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le16 *= path, - __u8 *oplock, struct smb2_file_all_info *buf, - struct create_posix_rsp *posix, - struct kvec *err_iov, int *buftype) +int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le= 16 *path, + __u8 *oplock, struct smb2_file_all_info *buf, + struct create_posix_rsp *posix, struct kvec *err_iov) { - struct smb_rqst rqst; + struct TCP_Server_Info *server; struct smb2_create_rsp *rsp =3D NULL; + struct smb_message *smb; struct cifs_tcon *tcon =3D oparms->tcon; struct cifs_ses *ses =3D tcon->ses; - struct TCP_Server_Info *server; - struct kvec iov[SMB2_CREATE_IOV_SIZE]; - struct kvec rsp_iov =3D {NULL, 0}; - int resp_buftype =3D CIFS_NO_BUFFER; - int rc =3D 0; - int flags =3D 0; int retries =3D 0, cur_sleep =3D 1; + int flags =3D 0; + int rc =3D 0; =20 replay_again: /* reinitialize for possible replay */ @@ -3459,34 +3294,27 @@ SMB2_open(const unsigned int xid, struct cifs_open_= parms *oparms, __le16 *path, if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - memset(&rqst, 0, sizeof(struct smb_rqst)); - memset(&iov, 0, sizeof(iov)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D SMB2_CREATE_IOV_SIZE; - - rc =3D SMB2_open_init(tcon, server, - &rqst, oplock, oparms, path); - if (rc) + smb =3D SMB2_open_init(tcon, server, oplock, oparms, path); + if (IS_ERR(smb)) { + rc =3D PTR_ERR(smb); + smb =3D NULL; goto creat_exit; + } =20 trace_smb3_open_enter(xid, tcon->tid, tcon->ses->Suid, oparms->path, oparms->create_options, oparms->desired_access); =20 if (retries) - smb2_set_replay(server, &rqst); + smb2_set_replay_smb(server, smb); =20 - rc =3D cifs_send_recv(xid, ses, server, - &rqst, &resp_buftype, flags, - &rsp_iov); - rsp =3D (struct smb2_create_rsp *)rsp_iov.iov_base; + rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); + rsp =3D (struct smb2_create_rsp *)smb->response; =20 if (rc !=3D 0) { cifs_stats_fail_inc(tcon, SMB2_CREATE); if (err_iov && rsp) { - *err_iov =3D rsp_iov; - *buftype =3D resp_buftype; - resp_buftype =3D CIFS_NO_BUFFER; - rsp =3D NULL; + err_iov->iov_base =3D smb->response; + err_iov->iov_len =3D smb->response_len; } trace_smb3_open_err(xid, tcon->tid, ses->Suid, oparms->create_options, oparms->desired_access, rc); @@ -3496,10 +3324,11 @@ SMB2_open(const unsigned int xid, struct cifs_open_= parms *oparms, __le16 *path, tcon->need_reconnect =3D true; } goto creat_exit; - } else if (rsp =3D=3D NULL) /* unlikely to happen, but safer to check */ + } + if (!rsp) /* unlikely to happen, but safer to check */ goto creat_exit; - else - trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, + + trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, oparms->create_options, oparms->desired_access); =20 atomic_inc(&tcon->num_remote_opens); @@ -3523,12 +3352,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_= parms *oparms, __le16 *path, } =20 =20 - rc =3D smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch, - oparms->fid->lease_key, oplock, buf, posix); + rc =3D smb2_parse_create_response(server, smb, &oparms->fid->epoch, + oparms->fid->lease_key, oplock, buf, posix); creat_exit: - SMB2_open_free(&rqst); - free_rsp_buf(resp_buftype, rsp); - + smb_put_messages(smb); if (is_replayable_error(rc) && smb2_should_replay(tcon, &retries, &cur_sleep)) goto replay_again; diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 22284a52f300..f854093dd92c 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -151,17 +151,12 @@ extern int SMB2_tcon(const unsigned int xid, struct c= ifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *); extern int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); -extern int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparm= s, - __le16 *path, __u8 *oplock, - struct smb2_file_all_info *buf, - struct create_posix_rsp *posix, - struct kvec *err_iov, int *resp_buftype); -extern int SMB2_open_init(struct cifs_tcon *tcon, - struct TCP_Server_Info *server, - struct smb_rqst *rqst, - __u8 *oplock, struct cifs_open_parms *oparms, - __le16 *path); -extern void SMB2_open_free(struct smb_rqst *rqst); +int SMB2_open(const unsigned int xid, struct cifs_open_parms *oparms, __le= 16 *path, + __u8 *oplock, struct smb2_file_all_info *buf, + struct create_posix_rsp *posix, struct kvec *err_iov); +struct smb_message *SMB2_open_init(struct cifs_tcon *tcon, + struct TCP_Server_Info *server, __u8 *oplock, + struct cifs_open_parms *oparms, __le16 *path); extern int SMB2_ioctl(const unsigned int xid, struct cifs_tcon *tcon, u64 persistent_fid, u64 volatile_fid, u32 opcode, char *in_data, u32 indatalen, u32 maxoutlen, @@ -276,12 +271,12 @@ extern int smb3_validate_negotiate(const unsigned int= , struct cifs_tcon *); =20 extern enum securityEnum smb2_select_sectype(struct TCP_Server_Info *, enum securityEnum); -int smb2_parse_contexts(struct TCP_Server_Info *server, - struct kvec *rsp_iov, - __u16 *epoch, - char *lease_key, __u8 *oplock, - struct smb2_file_all_info *buf, - struct create_posix_rsp *posix); +int smb2_parse_create_response(struct TCP_Server_Info *server, + struct smb_message *smb, + __u16 *epoch, + char *lease_key, __u8 *oplock, + struct smb2_file_all_info *buf, + struct create_posix_rsp *posix); =20 extern int smb3_encryption_required(const struct cifs_tcon *tcon); extern int smb2_validate_iov(unsigned int offset, unsigned int buffer_leng= th,