From nobody Mon May 25 02:42:24 2026 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 990683E1223 for ; Tue, 19 May 2026 10:22:22 +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=1779186144; cv=none; b=myh1oD5A3o6nOBs8pA56pH7lfOXplt4tQ9coSCGEGC6xnU2vc4dHxHiNQLn3UxW2+MhBwI+2cee8Z9w6nPvMPfSeejsa/zU8wgVFIfZYGLcuTW5C6WZmm0KJK/vwH/dk9UKcQs1w/vkhPrF0PAUz8xQjdbvS/CjNAzVJs2YxMyM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186144; c=relaxed/simple; bh=81z9I5hTk0GkEethM3pXIgRu18Sm5rwYvQwLj7nqAak=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=M3jBlX8CUr1cluo1wxNZePxv7ymK+5VgeTNZS9WvCk+OGPee8Lpr8CtYWTn4JGWyquspEZt+gMIY1FesU0shEEhFuhTJHNXBFH20EMl6uflpuv+MBbkSKoluCo/d5dfOx/a5/95rXkIY4N2UbGadl3j5CINxHWzYN8h258y5bOU= 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=KTJUnUgM; 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="KTJUnUgM" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186141; 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=n/vlkD/23OmrAj2LzzqI9Nh1utpeYvDExMI4wj2//ls=; b=KTJUnUgMId1V87oVw7JdeoiDgWG2d6FMdkzeQ/U7USCB4o4RAKRr/bbJYbqb69A+eXW2PY 9TJlCyzkTuX2ihNO19+EvVhvCSzQxSO2apR6uMemm8vfaL7Pk+uxJXsvmtSBTROAgfLtzV qmKYzeBbXiRAcs7Dry17sn0i8L47MyM= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-627-hgdWFDm0PLeawxqS8hdJcw-1; Tue, 19 May 2026 06:22:14 -0400 X-MC-Unique: hgdWFDm0PLeawxqS8hdJcw-1 X-Mimecast-MFC-AGG-ID: hgdWFDm0PLeawxqS8hdJcw_1779186132 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A1E0619560AA; Tue, 19 May 2026 10:22:11 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 218261800352; Tue, 19 May 2026 10:22:05 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , Neal Cardwell , Kuniyuki Iwashima , netfs@lists.linux.dev, linux-fsdevel@vger.kernel.org, netdev@vger.kernel.org Subject: [RFC PATCH 01/36] net: Perform special handling for a splice from a bvecq Date: Tue, 19 May 2026 11:21:19 +0100 Message-ID: <20260519102158.592165-2-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" In skb_splice_from_iter() used for MSG_SPLICE_PAGES, if it sees that it is given a bvecq-based iterator, walk the bvecq directly rather than calling iov_iter_extract_pages() to extract into a separate table. Note that the bvecq chain carries information about whether a page can be get_page'd or whether it has to be pinned (GUP), though the sk_buff can't currently make use of this information. Signed-off-by: David Howells cc: Eric Dumazet cc: Neal Cardwell cc: Kuniyuki Iwashima cc: Mina Almasry 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 cc: netdev@vger.kernel.org --- net/core/skbuff.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 7dad68e3b518..127c300ab938 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -7295,6 +7295,122 @@ nodefer: kfree_skb_napi_cache(skb); kick_defer_list_purge(cpu); } =20 +static __always_inline +size_t iterate_one_bvec(struct bio_vec *p, size_t skip, size_t len, + void *priv, void *priv2, iov_step_f step) +{ +#ifdef CONFIG_HIGHMEM + size_t progress =3D 0; + + if (skip >=3D p->bv_len) + return 0; + + len =3D umin(len, p->bv_len - skip); + while (len > 0) { + size_t remain, consumed; + size_t offset =3D p->bv_offset + skip, part; + void *kaddr =3D kmap_local_bvec(p, skip); + + part =3D umin(len, PAGE_SIZE - offset % PAGE_SIZE); + remain =3D step(kaddr, progress, part, priv, priv2); + kunmap_local(kaddr); + + consumed =3D part - remain; + len -=3D consumed; + progress +=3D consumed; + skip +=3D consumed; + if (remain) + break; + } + + return progress; +#else + return len - step(bvec_virt(p) + skip, 0, len, priv, priv2); +#endif +} + +static __always_inline +size_t csum_one(void *iter_from, size_t progress, + size_t len, void *priv, void *priv2) +{ + __wsum *csum =3D priv; + + *csum =3D csum_partial(iter_from, len, *csum); + return 0; +} + +static void skb_splice_csum_bv(struct sk_buff *skb, struct bio_vec *bv, + size_t skip, size_t len) +{ + __wsum csum =3D 0; + + size_t did =3D iterate_one_bvec(bv, skip, len, &csum, NULL, csum_one); + + WARN_ON_ONCE(did !=3D len); + skb->csum =3D csum_block_add(skb->csum, csum, len); +} + +/* + * Splice from a bvecq iterator to an skbuff. + */ +static size_t skb_splice_from_bvecq(struct sk_buff *skb, struct iov_iter *= iter, + size_t len) +{ + const struct bvecq *bq =3D iter->bvecq; + unsigned int slot =3D iter->bvecq_slot; + size_t frag_limit =3D READ_ONCE(net_hotdata.sysctl_max_skb_frags); + size_t spliced =3D 0, skip =3D iter->iov_offset; + + len =3D umin(len, iter->count); + if (!len) + return 0; + if (slot =3D=3D bq->nr_slots) { + /* The iterator may have been extended. */ + bq =3D bq->next; + slot =3D 0; + } + + do { + struct bio_vec *bvec =3D &bq->bv[slot]; + + if (skip < bvec->bv_len) { + size_t part =3D umin(bvec->bv_len - skip, len); + size_t off =3D bvec->bv_offset + skip; + int ret =3D -EIO; + + if (WARN_ON_ONCE(!sendpage_ok(bvec->bv_page))) + break; + + ret =3D skb_append_pagefrags(skb, bvec->bv_page, off, part, + frag_limit); + if (ret < 0) + return ret; + + if (skb->ip_summed =3D=3D CHECKSUM_NONE) + skb_splice_csum_bv(skb, bvec, off, part); + + len -=3D part; + spliced +=3D part; + skip +=3D part; + } + if (skip >=3D bvec->bv_len) { + skip =3D 0; + slot++; + if (slot >=3D bq->nr_slots && bq->next) { + bq =3D bq->next; + slot =3D 0; + } + } + } while (len); + + iter->bvecq_slot =3D slot; + iter->bvecq =3D bq; + iter->iov_offset =3D skip; + iter->count -=3D spliced; + skb_len_add(skb, spliced); + return spliced; +} + static void skb_splice_csum_page(struct sk_buff *skb, struct page *page, size_t offset, size_t len) { @@ -7329,6 +7445,9 @@ ssize_t skb_splice_from_iter(struct sk_buff *skb, str= uct iov_iter *iter, ssize_t spliced =3D 0, ret =3D 0; unsigned int i; =20 + if (iov_iter_is_bvecq(iter)) + return skb_splice_from_bvecq(skb, iter, maxsize); + while (iter->count > 0) { ssize_t space, nr, len; size_t off; From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 081493A9D9F for ; Tue, 19 May 2026 10:22:21 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186143; cv=none; b=qbiwwu9dkDp17wwpFxsZkYX5blRQhxiBwSPthXx4XcUZzHWQvOOyPDyEq6LyS1e06BeYfEXHMZBwRfd8nBsG4ISahWiTBmYBmKar4R9ojqf7Y9kqUxwmpFysyAB+eTU5DubxUnWwUKG2FuoLNpbmBmrebL20br59j5t8viU9CFQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186143; c=relaxed/simple; bh=ZWRlTlULMlgQmy4zYCe/ilAxmmzK6RqK3epXm/pq+xM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I4OB65U+TtQirmlJiFLaZgfC/vq2JyTX5pK3jW7TMqX5Jd4FfQUzMKhpbmuquGETlAEX77FlpHKH4P6XmBrhuaQCbYmKSyQnZS70mtqI/2vjxzpcqUJ4aK+H0owxGr9OtkBo2pOcFzLDmsDfbswn2sW9mUpM8q747V/OeHpuVtM= 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=UdkedSwA; arc=none smtp.client-ip=170.10.133.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="UdkedSwA" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186141; 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=HOVY75L14Dl93yhDO85IElKyNvCooLz7DO01WljhJr4=; b=UdkedSwAb1zKzQgMsgPnacLZfwlxSlFqh3fKNvI7UCeBJOX1i1euBXIhBkMa2HYVBj0din hqx3MmyRtsEvmfOXudzBuVT2fH6/JRcXexez/mPbrHnRTeN6UadkA85JxlvogBMrP31pgS IQne4DU9UWMIgjfQ85Yu2FzhR/2Ycas= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-64-AGlo3YNMNeOFxIKZQy32Vg-1; Tue, 19 May 2026 06:22:17 -0400 X-MC-Unique: AGlo3YNMNeOFxIKZQy32Vg-1 X-Mimecast-MFC-AGG-ID: AGlo3YNMNeOFxIKZQy32Vg_1779186135 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B64DE195609E; Tue, 19 May 2026 10:22:15 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 115E830002DC; Tue, 19 May 2026 10:22:11 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, Eric Dumazet , netfs@lists.linux.dev, linux-fsdevel@vger.kernel.org, netdev@vger.kernel.org Subject: [RFC PATCH 02/36] netfs: Add a facility to splice TCP receive buffers into a bvecq Date: Tue, 19 May 2026 11:21:20 +0100 Message-ID: <20260519102158.592165-3-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Add a function by which receive buffers can be spliced from a TCP socket into a bvecq (bio_vec queue) allowing the caller to process the contained data without holding the socket lock. This is of particular interest where, say, a network filesystem has to copy a lot of data from a TCP socket from the response to a Read request - but holding the socket lock prevents messages from being sent. Signed-off-by: David Howells cc: Eric Dumazet cc: Mina Almasry 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 cc: netdev@vger.kernel.org --- fs/netfs/Makefile | 1 + fs/netfs/tcp_splice.c | 269 ++++++++++++++++++++++++++++++++++++++++++ include/linux/netfs.h | 6 + 3 files changed, 276 insertions(+) create mode 100644 fs/netfs/tcp_splice.c diff --git a/fs/netfs/Makefile b/fs/netfs/Makefile index 421dd0be413b..9cfc3ccf46a0 100644 --- a/fs/netfs/Makefile +++ b/fs/netfs/Makefile @@ -20,6 +20,7 @@ netfs-y :=3D \ =20 netfs-$(CONFIG_NETFS_PGPRIV2) +=3D read_pgpriv2.o netfs-$(CONFIG_NETFS_STATS) +=3D stats.o +netfs-$(CONFIG_INET) +=3D tcp_splice.o =20 netfs-$(CONFIG_FSCACHE) +=3D \ fscache_cache.o \ diff --git a/fs/netfs/tcp_splice.c b/fs/netfs/tcp_splice.c new file mode 100644 index 000000000000..1ff312d5bfdc --- /dev/null +++ b/fs/netfs/tcp_splice.c @@ -0,0 +1,269 @@ +/* Splice from TCP to a bvecq + * + * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public Licence + * as published by the Free Software Foundation; either version + * 2 of the Licence, or (at your option) any later version. + */ +#include "internal.h" +#include +#include +#include + +static struct page *linear_to_page(struct page *page, unsigned int *len, + unsigned int *offset, + struct sock *sk) +{ + struct page_frag *pfrag =3D sk_page_frag(sk); + + if (!sk_page_frag_refill(sk, pfrag)) + return NULL; + + *len =3D min_t(unsigned int, *len, pfrag->size - pfrag->offset); + + memcpy(page_address(pfrag->page) + pfrag->offset, + page_address(page) + *offset, *len); + *offset =3D pfrag->offset; + pfrag->offset +=3D *len; + + return pfrag->page; +} + +static bool bvecq_can_coalesce(const struct bvecq *bvecq, + struct page *page, + unsigned int offset) +{ + const struct bio_vec *bv =3D &bvecq->bv[bvecq->nr_slots - 1]; + + return bvecq->nr_slots > 0 && + bv->bv_page =3D=3D page && + bv->bv_offset + bv->bv_len =3D=3D offset; +} + +/* + * Add {page,offset,length} into bvecq, if it has more capacity available. + */ +static bool bvecq_add_page(struct bvecq *bvecq, struct page *page, + unsigned int *len, unsigned int offset, bool linear, + struct sock *sk) +{ + if (unlikely(bvecq_is_full(bvecq))) + return true; + + if (linear) { + page =3D linear_to_page(page, len, &offset, sk); + if (!page) + return true; + } + if (bvecq_can_coalesce(bvecq, page, offset)) { + unsigned int old_len =3D bvecq->bv[bvecq->nr_slots - 1].bv_len; + + WRITE_ONCE(bvecq->bv[bvecq->nr_slots - 1].bv_len, old_len + *len); + return false; + } + + get_page(page); + bvec_set_page(&bvecq->bv[bvecq->nr_slots], page, *len, offset); + bvecq->nr_slots++; + return false; +} + +static bool bvecq_splice_segment(struct bvecq *bvecq, + struct page *page, unsigned int poff, + unsigned int plen, unsigned int *off, + unsigned int *len, bool linear, + struct sock *sk) +{ + if (!*len) + return true; + + /* skip this segment if already processed */ + if (*off >=3D plen) { + *off -=3D plen; + return false; + } + + /* ignore any bits we already processed */ + poff +=3D *off; + plen -=3D *off; + *off =3D 0; + + /* TODO: Splice in large pages as single bio_vecs. */ + do { + unsigned int flen =3D umin(*len, plen); + + if (bvecq_add_page(bvecq, page, &flen, poff, linear, sk)) + return true; + poff +=3D flen; + plen -=3D flen; + *len -=3D flen; + } while (*len && plen); + + return false; +} + +/* + * Map linear and fragment data from the skb to spd. It reports true if the + * pipe is full or if we already spliced the requested length. + */ +static bool bvecq_splice_bits_recursive(struct bvecq *bvecq, struct sk_buf= f *skb, + unsigned int *offset, unsigned int *len, + struct sock *sk) +{ + struct sk_buff *iter; + int seg; + + /* map the linear part : + * If skb->head_frag is set, this 'linear' part is backed by a + * fragment, and if the head is not shared with any clones then + * we can avoid a copy since we own the head portion of this page. + */ + if (bvecq_splice_segment(bvecq, virt_to_page(skb->data), + (unsigned long) skb->data & (PAGE_SIZE - 1), + skb_headlen(skb), offset, len, + skb_head_is_locked(skb), sk)) + return true; + + /* + * then map the fragments + */ + if (!skb_frags_readable(skb)) + return false; + + for (seg =3D 0; seg < skb_shinfo(skb)->nr_frags; seg++) { + const skb_frag_t *f =3D &skb_shinfo(skb)->frags[seg]; + + if (WARN_ON_ONCE(!skb_frag_page(f))) + return false; + + if (bvecq_splice_segment(bvecq, skb_frag_page(f), + skb_frag_off(f), skb_frag_size(f), + offset, len, false, sk)) + return true; + } + + skb_walk_frags(skb, iter) { + if (*offset >=3D iter->len) { + *offset -=3D iter->len; + continue; + } + /* We only fail if the output has no room left, so no point in + * going over the frag_list for the error case. + */ + if (bvecq_splice_bits_recursive(bvecq, iter, offset, len, sk)) + return true; + } + + return false; +} + +/* + * Map data from the skb to a pipe. Should handle both the linear part, + * the fragments, and the frag list. + */ +static int tcp_splice_data_to_bvecq(read_descriptor_t *rd_desc, struct sk_= buff *skb, + unsigned int offset, size_t len) +{ + struct bvecq *bvecq =3D rd_desc->arg.data; + unsigned int tlen =3D umin(rd_desc->count, len); + unsigned int used; + + bvecq_splice_bits_recursive(bvecq, skb, &offset, &tlen, skb->sk); + used =3D len - tlen; + rd_desc->count -=3D used; + return used; +} + +/** + * netfs_tcp_splice_to_bvecq - splice data from TCP socket to a bvec queue + * @sock: The socket to splice from + * @bvecq: The bvec queue to splice to + * @len: The number of bytes to splice + * + * Read pages from the given socket and transfer them into a bvec queue. = Data + * segments are attached starting at the next available segment in the bve= cq + * (from bvecq->nr_slots+1 up to bvecq->max_slots) and may extend the last + * segment used if contiguous with it. + */ +ssize_t netfs_tcp_splice_to_bvecq(struct socket *sock, struct bvecq *bvecq, + size_t len) +{ + read_descriptor_t rd_desc =3D { + .arg.data =3D bvecq, + .count =3D len, + }; + struct sock *sk =3D sock->sk; + ssize_t spliced =3D 0; + long timeo; + int ret =3D 0; + + sock_rps_record_flow(sk); + if (unlikely(bvecq_is_full(bvecq))) + return -ENOBUFS; + + lock_sock(sk); + + timeo =3D sock_rcvtimeo(sk, true /* non-blocking */); + while (len) { + ret =3D tcp_read_sock(sk, &rd_desc, tcp_splice_data_to_bvecq); + if (ret < 0) + break; + if (!ret) { + if (spliced) + break; + if (sock_flag(sk, SOCK_DONE)) + break; + if (sk->sk_err) { + ret =3D sock_error(sk); + break; + } + if (sk->sk_shutdown & RCV_SHUTDOWN) + break; + if (sk->sk_state =3D=3D TCP_CLOSE) { + /* + * This occurs when user tries to read + * from never connected socket. + */ + ret =3D -ENOTCONN; + break; + } + if (!timeo) { + ret =3D -EAGAIN; + break; + } + /* if __tcp_splice_read() got nothing while we have + * an skb in receive queue, we do not want to loop. + * This might happen with URG data. + */ + if (!skb_queue_empty(&sk->sk_receive_queue)) + break; + ret =3D sk_wait_data(sk, &timeo, NULL); + if (ret < 0) + break; + if (signal_pending(current)) { + ret =3D sock_intr_errno(timeo); + break; + } + continue; + } + len -=3D ret; + spliced +=3D ret; + + if (!len || !timeo || bvecq_is_full(bvecq)) + break; + release_sock(sk); + lock_sock(sk); + + if (sk->sk_err || sk->sk_state =3D=3D TCP_CLOSE || + (sk->sk_shutdown & RCV_SHUTDOWN) || + signal_pending(current)) + break; + } + + release_sock(sk); + return spliced ?: ret; +} +EXPORT_SYMBOL_GPL(netfs_tcp_splice_to_bvecq); diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 86bef8fec14b..8fd23653a911 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -23,6 +23,7 @@ enum netfs_sreq_ref_trace; typedef struct mempool mempool_t; struct readahead_control; +struct socket; struct netfs_io_request; struct netfs_io_subrequest; struct fscache_occupancy; @@ -482,6 +483,11 @@ void netfs_end_io_write(struct inode *inode); int netfs_start_io_direct(struct inode *inode); void netfs_end_io_direct(struct inode *inode); =20 +/* TCP transport helper API. */ +#ifdef CONFIG_INET +ssize_t netfs_tcp_splice_to_bvecq(struct socket *sock, struct bvecq *bvecq= , size_t len); +#endif + /** * netfs_inode - Get the netfs inode context from the inode * @inode: The inode to query From nobody Mon May 25 02:42:24 2026 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 DDF4A3A8384 for ; Tue, 19 May 2026 10:22:28 +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=1779186151; cv=none; b=YtF7uU/gA3VpxzkWpTrTCS8J7Iju64m6xHvBAcxUyUYw5Crc+R0ZOkMTpT1eAV3wkwz5Dxhd2E9QCctM9s+VqHzhvgVhS0DxO23Qql20l4YksALpr5vzV8b0latIfXzc3RBExMHdSXeXjjEO9xL5T60QNqlbNwRF0zeTWOP3K8o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186151; c=relaxed/simple; bh=lFZfb2qmDYwykTp1Cpfrowdt41V2O4lMCoFNJlEa/1I=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lM3J7V3KmYUJPyuMlHknooVDksq2/Q81Lj6SP2LNmPGlkY3oRfxr3M9rEhKF0tR6PDT04wxcH4dPZ1j41tgQK9Khx2dNjqzgJ2sunFHKYlhggBveZPVLpAyz3LUEtfiAgwa9KvOlYu/uR+D/YA/ChqUyPqkhA/yBXkel3qClqFU= 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=PaJfwdtE; 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="PaJfwdtE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186148; 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=w3lFbu81yUMfAe2aK/cD8XDhTc8jRvOyQBk6lCpA3vE=; b=PaJfwdtEoBEUW+pn7IS3W3A+FCZjr+7so98fH0jiRI8LnVva0XaRbMsfI5oAFTeAGl23xS Ol7clT/QeFvkv+KMW8zAAvAr2DYxYhqBchNoVqdbuVVOi67YyE5giKvLS3BjUfpFwycUYA cdj5OkmPqp35syaHuagYJNhIrajohVM= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-81-Lll8fd_AOLCNN6wpcVkHow-1; Tue, 19 May 2026 06:22:22 -0400 X-MC-Unique: Lll8fd_AOLCNN6wpcVkHow-1 X-Mimecast-MFC-AGG-ID: Lll8fd_AOLCNN6wpcVkHow_1779186141 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B5D4919560AD; Tue, 19 May 2026 10:22:20 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 663C430002DC; Tue, 19 May 2026 10:22:17 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 03/36] netfs: Add some TCP receive queue helpers Date: Tue, 19 May 2026 11:21:21 +0100 Message-ID: <20260519102158.592165-4-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Add some helpers to splice buffers from a TCP receive queue to a private queue from where they can be processed without the need to hold the socket lock. This is particularly significant if a large amount of data is being copied, say for a read-data RPC call. 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/netfs/Makefile | 5 +- fs/netfs/rxqueue.c | 532 +++++++++++++++++++++++++++++++++++ include/linux/netfs.h | 31 ++ include/trace/events/netfs.h | 28 ++ 4 files changed, 595 insertions(+), 1 deletion(-) create mode 100644 fs/netfs/rxqueue.c diff --git a/fs/netfs/Makefile b/fs/netfs/Makefile index 9cfc3ccf46a0..66e642650a5f 100644 --- a/fs/netfs/Makefile +++ b/fs/netfs/Makefile @@ -20,7 +20,10 @@ netfs-y :=3D \ =20 netfs-$(CONFIG_NETFS_PGPRIV2) +=3D read_pgpriv2.o netfs-$(CONFIG_NETFS_STATS) +=3D stats.o -netfs-$(CONFIG_INET) +=3D tcp_splice.o + +netfs-$(CONFIG_INET) +=3D \ + rxqueue.o \ + tcp_splice.o =20 netfs-$(CONFIG_FSCACHE) +=3D \ fscache_cache.o \ diff --git a/fs/netfs/rxqueue.c b/fs/netfs/rxqueue.c new file mode 100644 index 000000000000..e40c4e23a9af --- /dev/null +++ b/fs/netfs/rxqueue.c @@ -0,0 +1,532 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* Receive buffer handling. Move memory copy outside of the socket lock. + * + * Copyright (C) 2026 Red Hat, Inc. All Rights Reserved. + * Written by David Howells (dhowells@redhat.com) + */ + +#include +#include "internal.h" + +/* + * Get a ref on an Rx page. + */ +static void netfs_get_rx_page(struct bio_vec *bv) +{ + get_page(bv->bv_page); +} + +/* + * Drop a ref on an Rx page. + */ +static void netfs_put_rx_page(struct bio_vec *bv) +{ + put_page(bv->bv_page); +} + +/* + * netfs_alloc_rx_bvecq - Allocate a receive buffer. + * nr_bv: Number of slots to allocate + * + * Allocate a receive buffer with the specified number of slots. This fun= ction + * will not fail, though it has no upper bound on the time taken to succee= d. + * + * Return: The new buffer. + */ +struct bvecq *netfs_alloc_rx_bvecq(unsigned int nr_bv) +{ + struct bvecq *bq; + + for (;;) { + bq =3D bvecq_alloc_one(nr_bv, GFP_NOFS); + if (bq) + return bq; + msleep(50); + } +} +EXPORT_SYMBOL(netfs_alloc_rx_bvecq); + +/** + * netfs_put_rx_bvecq - Put a receive buffer chain + * @bq: The head buffer to put + * + * Put a ref on the first buffer segment in a bvecq chain and if that reac= hes + * zero, destroy it, move on to the next buffer and repeat the put. + */ +void netfs_put_rx_bvecq(struct bvecq *bq) +{ + struct bvecq *next; + + for (; bq; bq =3D next) { + if (!refcount_dec_and_test(&bq->ref)) + break; + for (int seg =3D 0; seg < bq->nr_slots; seg++) + if (bq->bv[seg].bv_page) + netfs_put_rx_page(&bq->bv[seg]); + next =3D bq->next; + kfree(bq); + } +} +EXPORT_SYMBOL(netfs_put_rx_bvecq); + +/** + * netfs_rxqueue_read_iter - Read data from a queue to an iterator + * @rxq: The receive queue to read + * @dest: The buffer to fill + * @skip: The amount of data in the queue to skip over + * @amount: The amount of data to read + * + * Copy data from the receive queue to an iterator. The data doesn't have= to + * lie at the beginning of the buffer, but the initial unwanted data can be + * skipped over. + * + * Note that this does not discard any data from the queue. + * + * Return: The amount of data copied. 0 is returned on failure or if @amo= unt + * is 0. + */ +size_t netfs_rxqueue_read_iter(const struct netfs_rxqueue *rxq, + struct iov_iter *dest, size_t skip, size_t amount) +{ + const struct bvecq *from =3D rxq->take_from; + unsigned int slot =3D rxq->take_slot; + size_t qsize =3D rxq->qsize, copied =3D 0; + + if (WARN(amount > iov_iter_count(dest), + "MSG=3D%x %zx > %zx", + rxq->msg_id, amount, iov_iter_count(dest))) + amount =3D iov_iter_count(dest); + + if (skip > rxq->pdu_remain) { + pr_warn("Rx over-skip %zx > %x\n", skip, rxq->pdu_remain); + return 0; + } + if (amount > rxq->pdu_remain - skip) { + pr_warn("Rx over-read %zx+%zx > %x\n", + skip, amount, rxq->pdu_remain); + amount =3D rxq->pdu_remain - skip; + if (amount =3D=3D 0) + return 0; + } + if (amount > qsize) + amount =3D qsize; + + skip +=3D rxq->take_offset; + + while (copied < amount) { + if (slot >=3D from->nr_slots) { + slot =3D 0; + from =3D from->next; + if (!from) + break; + } + + const struct bio_vec *bv =3D &from->bv[slot]; + size_t blen =3D bv->bv_len; + + if (skip >=3D blen) { + skip -=3D blen; + slot++; + continue; + } + + size_t part =3D umin(blen - skip, amount - copied), got; + + trace_netfs_rxq_read(rxq, slot, skip, part, copied); + + got =3D copy_page_to_iter(bv->bv_page, + bv->bv_offset + skip, part, dest); + if (WARN_ON(got !=3D part)) { + bvecq_dump(rxq->take_from); + return 0; + } + + copied +=3D part; + skip =3D 0; + slot++; + } + + if (amount !=3D copied) + pr_warn("Failed to fully read %zx/%zx %x %pSR\n", + copied, amount, rxq->qsize, __builtin_return_address(0)); + return copied; +} +EXPORT_SYMBOL(netfs_rxqueue_read_iter); + +/** + * netfs_rxqueue_read - Read data from a queue to a flat buffer + * @rxq: The receive queue to read + * @buffer: The buffer to fill + * @skip: The amount of data in the queue to skip over + * @amount: The amount of data to read + * + * Copy data from the receive queue to a flat buffer. The data doesn't ha= ve to + * lie at the beginning of the buffer, but the initial unwanted data can be + * skipped over. + * + * Note that this does not discard any data from the queue. + * + * Return: The amount of data copied. 0 is returned on failure or if @amo= unt + * is 0. + */ +size_t netfs_rxqueue_read(const struct netfs_rxqueue *rxq, + void *buffer, size_t skip, size_t amount) +{ + struct iov_iter iter; + struct kvec kv =3D { .iov_base =3D buffer, .iov_len =3D amount }; + + iov_iter_kvec(&iter, ITER_DEST, &kv, 1, amount); + return netfs_rxqueue_read_iter(rxq, &iter, skip, amount); +} +EXPORT_SYMBOL(netfs_rxqueue_read); + +/** + * netfs_rxqueue_discard - Discard data from a queue + * @rxq: The receive queue to modify + * @amount: The amount of data to discard + * + * Discard the specified amount of data from @rxq. This may free pages and + * bvecq segments. In the event that the last bvecq is entirely cleared, = it + * will be refurbished and prepared for future refilling. + */ +void netfs_rxqueue_discard(struct netfs_rxqueue *rxq, size_t amount) +{ + struct bvecq *from =3D rxq->take_from, *dead; + unsigned int offset =3D rxq->take_offset; + unsigned int slot =3D rxq->take_slot; + size_t qsize =3D rxq->qsize; + + if (amount > rxq->pdu_remain) { + pr_warn("Rx over discard %zx > %x\n", amount, rxq->pdu_remain); + amount =3D rxq->pdu_remain; + } + + rxq->pdu_remain -=3D amount; + + for (;;) { + if (slot >=3D from->nr_slots) { + slot =3D 0; + offset =3D 0; + if (!from->next) { + /* Refurbish the final bvecq. add_to is NULL + * for a queue excerpt. + */ + if (!rxq->add_to) { + netfs_put_rx_bvecq(from); + from =3D NULL; + break; + } + + WARN_ON_ONCE(from !=3D rxq->add_to); + from->nr_slots =3D 0; + rxq->add_to =3D from; + break; + } + dead =3D from; + from =3D dead->next; + from->prev =3D NULL; + dead->next =3D NULL; + netfs_put_rx_bvecq(dead); + } + + if (!amount) + break; + + struct bio_vec *bv =3D &from->bv[slot]; + + if (offset < bv->bv_len) { + size_t part =3D umin(umin(bv->bv_len - offset, amount), qsize); + offset +=3D part; + amount -=3D part; + qsize -=3D part; + if (offset < bv->bv_len) + break; + } + + if (!WARN_ON_ONCE(!bv->bv_page)) + netfs_put_rx_page(bv); + bv->bv_page =3D NULL; + bv->bv_offset =3D 0; + bv->bv_len =3D 0; + slot++; + offset =3D 0; + } + + if (amount > 0) + pr_warn("Failed to fully discard %zx %zx %pSR\n", + amount, qsize, __builtin_return_address(0)); + + rxq->take_from =3D from; + rxq->take_slot =3D slot; + rxq->take_offset =3D offset; + rxq->qsize =3D qsize; +} +EXPORT_SYMBOL(netfs_rxqueue_discard); + +/** + * netfs_rxqueue_count - Count the number of segs holding the specified da= ta + * @rxq: The receive queue to assess + * @amount: The amount of data desired + * + * Count the number of segments in the receive queue that the requested am= ount + * of data spans. + * + * Return: Segment count; 0 is returned if there is in sufficient data. + */ +unsigned int netfs_rxqueue_count(const struct netfs_rxqueue *rxq, size_t a= mount) +{ + const struct bvecq *from =3D rxq->take_from; + unsigned int offset =3D rxq->take_offset; + unsigned int count =3D 0; + unsigned int slot =3D rxq->take_slot; + + while (amount > 0) { + if (slot >=3D from->nr_slots) { + if (WARN_ON_ONCE(!from->next)) + return 0; + from =3D from->next; + slot =3D 0; + offset =3D 0; + } + + const struct bio_vec *bv =3D &from->bv[slot]; + + if (offset < bv->bv_len) { + count++; + if (bv->bv_len - offset >=3D amount) + return count; + amount -=3D bv->bv_len - offset; + } + + slot++; + offset =3D 0; + } + + return count; +} +EXPORT_SYMBOL(netfs_rxqueue_count); + +/* + * Append (part of) a segment to a bvec queue and get/transfer a page coun= t. + * If we use up to the end of the source segment, we steal the page ref and + * clear the segment. + */ +static void netfs_bvecq_append_seg(struct bvecq **pdestq, struct bio_vec *= sv, + size_t offset, size_t len) +{ + struct bvecq *destq =3D *pdestq; + struct bio_vec *dv; + + if (bvecq_is_full(destq)) { + destq =3D destq->next; + *pdestq =3D destq; + } + dv =3D &destq->bv[destq->nr_slots++]; + *dv =3D *sv; + if (offset > 0) { + dv->bv_offset +=3D offset; + dv->bv_len -=3D offset; + } + if (len < dv->bv_len) { + dv->bv_len =3D len; + netfs_get_rx_page(dv); + } else { + sv->bv_page =3D NULL; + sv->bv_offset =3D 0; + sv->bv_len =3D 0; + } +} + +/** + * netfs_rxqueue_decant - Decant data segs to a private queue + * @rxq: The receive queue to decant from + * @amount: The amount of data received + * + * Decant data from the receive queue to a private queue. This prevents t= he + * receive queue keeping the buffers pinned. + * + * Return: A bvecq chain, with ref, holding the decanted data or NULL if o= ut of + * memory. + */ +struct bvecq *netfs_rxqueue_decant(struct netfs_rxqueue *rxq, size_t amoun= t) +{ + struct bvecq *head_bq =3D NULL, *pbq, *destq; + struct bvecq *from =3D rxq->take_from; + unsigned int need_segs; + unsigned int offset =3D rxq->take_offset; + unsigned int slot =3D rxq->take_slot; + size_t qsize =3D rxq->qsize; + + if (amount > rxq->pdu_remain) { + pr_warn("Rx over decant %zx > %x\n", + amount, rxq->pdu_remain); + amount =3D rxq->pdu_remain; + } + + /* Count the number of segments in the queue for this PDU and then + * allocate sufficient bvecq capacity to hold the whole PDU. + */ + need_segs =3D netfs_rxqueue_count(rxq, amount); + while (need_segs > 0) { + struct bvecq *b; + unsigned int max_bv =3D (PAGE_SIZE - sizeof(*b)) / sizeof(b->bv[0]); + unsigned int nr_bv =3D umin(need_segs, max_bv); + + need_segs -=3D nr_bv; + b =3D netfs_alloc_rx_bvecq(nr_bv); + if (!b) + goto nomem; + b->prev =3D pbq; + if (head_bq) + pbq->next =3D b; + else + head_bq =3D b; + pbq =3D b; + } + + rxq->pdu_remain -=3D amount; + destq =3D head_bq; + for (;;) { + if (slot >=3D from->nr_slots) { + struct bvecq *dead; + + slot =3D 0; + offset =3D 0; + if (!from->next) { + /* Refurbish the final bvecq. */ + WARN_ON_ONCE(from !=3D rxq->add_to); + from->nr_slots =3D 0; + rxq->add_to =3D from; + break; + } + dead =3D from; + from =3D dead->next; + from->prev =3D NULL; + dead->next =3D NULL; + netfs_put_rx_bvecq(dead); + } + + if (!amount) + break; + + struct bio_vec *bv =3D &from->bv[slot]; + + if (offset < bv->bv_len) { + size_t part =3D umin(umin(bv->bv_len - offset, amount), qsize); + netfs_bvecq_append_seg(&destq, bv, offset, part); + offset +=3D part; + amount -=3D part; + qsize -=3D part; + if (offset < bv->bv_len) + break; + } + + if (WARN_ON_ONCE(bv->bv_page)) { + netfs_put_rx_page(bv); + bv->bv_page =3D NULL; + bv->bv_offset =3D 0; + bv->bv_len =3D 0; + } + slot++; + offset =3D 0; + } + + rxq->take_from =3D from; + rxq->take_slot =3D slot; + rxq->take_offset =3D offset; + rxq->qsize =3D qsize; + return head_bq; + +nomem: + netfs_put_rx_bvecq(head_bq); + return NULL; +} +EXPORT_SYMBOL(netfs_rxqueue_decant); + +/** + * netfs_rxqueue_tcp_refill - Refill receive queue by TCP splice + * @tcp_sock: The TCP socket to splice data from + * @rxq: The Rx queue to splice into + * @min_size: The amount of data we're interested in + * + * Refill the receive queue by splicing network receive buffer segments fr= om a + * TCP socket, but don't wait for data. The caller must do any waiting + * required. + * + * Note that whilst the peer may send PDUs in separate TCP packets, it's + * possible that the local NIC may join them back together if doing receive + * offload. + */ +int netfs_rxqueue_tcp_refill(struct socket *tcp_sock, struct netfs_rxqueue= *rxq, + size_t min_size) +{ + struct bvecq *add_to =3D rxq->add_to; + size_t qsize =3D rxq->qsize; + int rc =3D 0; + + if (!rxq->refillable) { + WARN_ON(min_size > qsize); + return 0; + } + if (qsize >=3D min_size && min_size > 0) + return 0; + + do { + if (!add_to || bvecq_is_full(add_to)) { + struct bvecq *b; + unsigned int nr_bv =3D (2048 - sizeof(*add_to)) / sizeof(add_to->bv[0]); + + b =3D netfs_alloc_rx_bvecq(nr_bv); + b->prev =3D add_to; + if (!add_to) + rxq->take_from =3D b; + else + add_to->next =3D b; + add_to =3D b; + } + + rc =3D netfs_tcp_splice_to_bvecq(tcp_sock, add_to, INT_MAX); + //trace_smb3_tcp_splice(rc); + if (rc < 0) + break; + + qsize +=3D rc; + rc =3D 0; + } while (qsize < min_size); + + rxq->add_to =3D add_to; + rxq->qsize =3D qsize; + return rc; +} +EXPORT_SYMBOL(netfs_rxqueue_tcp_refill); + +/** + * netfs_rxqueue_tcp_consume - Receive and discard data from a receive que= ue + * @tcp_sock: The TCP socket that's the data source + * @rxq: The Rx queue to discard from + * @amount: The amount of data to discard + * + * Consume received data by receiving it if it's not already queued and th= en + * discarding it. This function does no waiting, so the caller must do the + * waiting and repeatedly call it until the desired amount of data is cons= umed. + */ +int netfs_rxqueue_tcp_consume(struct socket *tcp_sock, struct netfs_rxqueu= e *rxq, + size_t amount) +{ + while (amount) { + size_t part =3D umin(amount, rxq->qsize); + int rc; + + amount -=3D part; + netfs_rxqueue_discard(rxq, part); + + if (!amount) + break; + + rc =3D netfs_rxqueue_tcp_refill(tcp_sock, rxq, 1); + if (rc < 0) + return rc; + } + return 0; +} +EXPORT_SYMBOL(netfs_rxqueue_tcp_consume); diff --git a/include/linux/netfs.h b/include/linux/netfs.h index 8fd23653a911..9f5168994a95 100644 --- a/include/linux/netfs.h +++ b/include/linux/netfs.h @@ -422,6 +422,22 @@ struct netfs_cache_ops { enum netfs_cache_collect block_type); }; =20 +/* + * (An excerpt from) a receive queue. Data buffers can be spliced out of,= say, + * a TCP socket into a sequence of these and then a variety of helpers used + * to manipulate them and extract data. + */ +struct netfs_rxqueue { + struct bvecq *add_to; /* Where to add data to the Rx queue */ + struct bvecq *take_from; /* Where to take data from the Rx queue */ + unsigned int take_offset; /* Current offset in rx_take_slot */ + unsigned short take_slot; /* Current slot in rx_take_from */ + bool refillable; /* T if refillable; F if excerpt */ + unsigned int qsize; /* Amount of data in rx_queue */ + unsigned int pdu_remain; /* Amount of current PDU left */ + unsigned int msg_id; /* ID to log in tracepoints as MSG=3Dxx */ +}; + /* High-level read API. */ ssize_t netfs_unbuffered_read_iter_locked(struct kiocb *iocb, struct iov_i= ter *iter); ssize_t netfs_unbuffered_read_iter(struct kiocb *iocb, struct iov_iter *it= er); @@ -483,6 +499,21 @@ void netfs_end_io_write(struct inode *inode); int netfs_start_io_direct(struct inode *inode); void netfs_end_io_direct(struct inode *inode); =20 +/* Receive queue API. */ +struct bvecq *netfs_alloc_rx_bvecq(unsigned int nr_bv); +void netfs_put_rx_bvecq(struct bvecq *bq); +size_t netfs_rxqueue_read_iter(const struct netfs_rxqueue *rxq, + struct iov_iter *dest, size_t skip, size_t amount); +size_t netfs_rxqueue_read(const struct netfs_rxqueue *rxq, + void *buffer, size_t skip, size_t amount); +void netfs_rxqueue_discard(struct netfs_rxqueue *rxq, size_t amount); +unsigned int netfs_rxqueue_count(const struct netfs_rxqueue *rxq, size_t a= mount); +struct bvecq *netfs_rxqueue_decant(struct netfs_rxqueue *rxq, size_t amoun= t); +int netfs_rxqueue_tcp_refill(struct socket *tcp_sock, struct netfs_rxqueue= *rxq, + size_t min_size); +int netfs_rxqueue_tcp_consume(struct socket *tcp_sock, struct netfs_rxqueu= e *rxq, + size_t amount); + /* TCP transport helper API. */ #ifdef CONFIG_INET ssize_t netfs_tcp_splice_to_bvecq(struct socket *sock, struct bvecq *bvecq= , size_t len); diff --git a/include/trace/events/netfs.h b/include/trace/events/netfs.h index fbd000399b26..96a2c1f3880e 100644 --- a/include/trace/events/netfs.h +++ b/include/trace/events/netfs.h @@ -855,6 +855,34 @@ TRACE_EVENT(netfs_bv_slot, __entry->pfn, __entry->offset, __entry->offset + __entry->len) ); =20 +TRACE_EVENT(netfs_rxq_read, + TP_PROTO(const struct netfs_rxqueue *rxq, unsigned int slot, + size_t skip, size_t part, size_t copied), + + TP_ARGS(rxq, slot, skip, part, copied), + + TP_STRUCT__entry( + __field(unsigned int, msg_id) + __field(unsigned int, slot) + __field(unsigned int, skip) + __field(unsigned int, part) + __field(unsigned int, copied) + ), + + TP_fast_assign( + __entry->msg_id =3D rxq->msg_id; + __entry->slot =3D slot; + __entry->skip =3D skip; + __entry->part =3D part; + __entry->copied =3D copied; + ), + + TP_printk("MSG=3D%08x [%02x] b=3D%04x-%04x c=3D%04x", + __entry->msg_id, __entry->slot, + __entry->skip, __entry->skip + __entry->part, + __entry->copied) + ); + #undef EM #undef E_ #endif /* _TRACE_NETFS_H */ From nobody Mon May 25 02:42:24 2026 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 91CE03A9D89 for ; Tue, 19 May 2026 10:22:31 +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=1779186153; cv=none; b=oGmKJWk468jeZl80dHkHToH4FxlHaaI2V/5Su6PTRre+tKB1KsPa05ciptMekNsCXQmUKif+bZoc0SUJiJTB8mqr2YpGzyqQmj/1djbzwD//scnSGecyCSXHO4SzZvSU2UXS5TY92FyS/Hmy6ACky+/GvIBA2IYSSKEbkSFMvVQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186153; c=relaxed/simple; bh=73ZY8mW8gUqD884gH4nOwq7lM6Zo/5jkbSSuOt61xjU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=XUNRLwwDivG6kO3qlow0Tfb40JiJuHS53aQaBOg4bXPLotRPVDdqAu/s4bSyGpiNQd/Uhg+WPDUD3W0Ikiy+nbKFKRoAku9HK8GoZJ4H5OEXh9vVrHwuAs/z+4AXt/WXuXcn4bC1/g3G0APQRB4X6CQtldOVFU3F43rMruRD0jI= 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=LNtRPRkO; 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="LNtRPRkO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186150; 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=VtgqytRwGrmRD2asl1hoBpXgeAMJbC0kkMX9/JldibM=; b=LNtRPRkO2wA52h+pWF+HN7g8GHpLlHbFV+uc54as1I+81dQlct0r7E9PRM8vAFuYgFu7QK EArJ7bd3djgV7A/QZXbm1P99yHjEVDLaBMb7VSLl/Y5Yom+Pv1L+CoSsuzEivx+a2pnjLL 1zRRlbz0tB6PRs3qHnesIb4y21ErZ44= Received: from mx-prod-mc-06.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-663-LcVG3lBxPWCABxmRFfliNQ-1; Tue, 19 May 2026 06:22:27 -0400 X-MC-Unique: LcVG3lBxPWCABxmRFfliNQ-1 X-Mimecast-MFC-AGG-ID: LcVG3lBxPWCABxmRFfliNQ_1779186145 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9898318005BA; Tue, 19 May 2026 10:22:25 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 68E9D19560B0; Tue, 19 May 2026 10:22:22 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 04/36] cifs, nls: Provide unicode size determination func Date: Tue, 19 May 2026 11:21:22 +0100 Message-ID: <20260519102158.592165-5-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.12 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/nls/nls_base.c | 33 ++++++++++++++++++++++++++++++ fs/smb/client/cifs_unicode.c | 39 ++++++++++++++++++++++++++++++++++++ fs/smb/client/cifs_unicode.h | 2 ++ include/linux/nls.h | 1 + 4 files changed, 75 insertions(+) diff --git a/fs/nls/nls_base.c b/fs/nls/nls_base.c index a5c3a9f1b8dc..69bc266b4a49 100644 --- a/fs/nls/nls_base.c +++ b/fs/nls/nls_base.c @@ -174,6 +174,39 @@ int utf8s_to_utf16s(const u8 *s, int inlen, enum utf16= _endian endian, } EXPORT_SYMBOL(utf8s_to_utf16s); =20 +/** + * utf8s_to_len_utf16s - Determine the length of a conversion of UTF8 to U= TF16. + * @s: The source utf8 string + * @inlen: The length of the string + */ +ssize_t utf8s_to_len_utf16s(const u8 *s, int inlen) +{ + unicode_t u; + size_t outcount =3D 0; + int size; + + while (inlen > 0 && *s) { + if (*s & 0x80) { + size =3D utf8_to_utf32(s, inlen, &u); + if (size < 0) + return -EINVAL; + s +=3D size; + inlen -=3D size; + + if (u >=3D PLANE_SIZE) + outcount +=3D 2; + else + outcount++; + } else { + s++; + outcount++; + inlen--; + } + } + return outcount * sizeof(wchar_t); +} +EXPORT_SYMBOL(utf8s_to_len_utf16s); + static inline unsigned long get_utf16(unsigned c, enum utf16_endian endian) { switch (endian) { diff --git a/fs/smb/client/cifs_unicode.c b/fs/smb/client/cifs_unicode.c index 4a8a591f4bca..f8fac73dcc1e 100644 --- a/fs/smb/client/cifs_unicode.c +++ b/fs/smb/client/cifs_unicode.c @@ -276,6 +276,45 @@ cifs_strtoUTF16(__le16 *to, const char *from, int len, return i; } =20 +/* + * Work out how long a string will be once converted to UTF16 in bytes. T= his + * does not include a NUL terminator. + */ +size_t cifs_size_strtoUTF16(const char *from, int len, + const struct nls_table *codepage) +{ + wchar_t wchar_to; /* needed to quiet sparse */ + ssize_t out_len =3D 0; + int charlen; + + /* special case for utf8 to handle no plane0 chars */ + if (strcmp(codepage->charset, "utf8") =3D=3D 0) { + out_len =3D utf8s_to_len_utf16s(from, len); + if (out_len >=3D 0) + goto success; + /* + * On failure, fall back to UCS encoding as this function + * should not return negative values currently can fail only if + * source contains invalid encoded characters + */ + } + + for (; len && *from; len -=3D charlen) { + charlen =3D codepage->char2uni(from, len, &wchar_to); + if (charlen < 1) { + cifs_dbg(VFS, "strtoUTF16: char2uni of 0x%x returned %d\n", + *from, charlen); + /* Replace with a question mark */ + charlen =3D 1; + } + from +=3D charlen; + out_len +=3D 2; + } + +success: + return out_len; +} + /* * cifs_utf16_bytes - how long will a string be after conversion? * @utf16 - pointer to input string diff --git a/fs/smb/client/cifs_unicode.h b/fs/smb/client/cifs_unicode.h index 3e9cd9acf0a9..f774e0dd7461 100644 --- a/fs/smb/client/cifs_unicode.h +++ b/fs/smb/client/cifs_unicode.h @@ -61,6 +61,8 @@ int cifs_utf16_bytes(const __le16 *from, int maxbytes, const struct nls_table *codepage); int cifs_strtoUTF16(__le16 *to, const char *from, int len, const struct nls_table *codepage); +size_t cifs_size_strtoUTF16(const char *from, int len, + const struct nls_table *codepage); char *cifs_strndup_from_utf16(const char *src, const int maxlen, const bool is_unicode, const struct nls_table *codepage); diff --git a/include/linux/nls.h b/include/linux/nls.h index e0bf8367b274..026da1d5ffaa 100644 --- a/include/linux/nls.h +++ b/include/linux/nls.h @@ -56,6 +56,7 @@ extern int utf8_to_utf32(const u8 *s, int len, unicode_t = *pu); extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen); extern int utf8s_to_utf16s(const u8 *s, int len, enum utf16_endian endian, wchar_t *pwcs, int maxlen); +ssize_t utf8s_to_len_utf16s(const u8 *s, int inlen); extern int utf16s_to_utf8s(const wchar_t *pwcs, int len, enum utf16_endian endian, u8 *s, int maxlen); From nobody Mon May 25 02:42:24 2026 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 3512B3A960F for ; Tue, 19 May 2026 10:22:38 +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=1779186159; cv=none; b=BXVRF4qBXNrVDUFkdzoJBQcc2edXyG3hwBCLUV+56xNSPz10PGRtTgkFxOKAvodKaWpYNeS+8cAFYfJ32ExI7zST0Hz79WQkvXSvujeIXCNu+E9GATaqByvGtXJzSySMGMEe0K3Xr4oRmE+MVPikojxsuuxXZS3XEPhWIfCzc6I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186159; c=relaxed/simple; bh=PnXentWPsyoPKjP40iCcdK35fQI5gIzpIF96ZXj4bfU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SXJXXbE6Jf58y8G0U0L4hl1exDmqeV4ndMUH801tzZeZzGZF5trtR9QZcGJuk7vupJAP+RYogqaM1820+2a8iyyrecTiZM0zQyC/e7nmnEC/gZ2eLhB/nCzHGfiF6eBL1M9ogpgBHhbroDl3m4c62xGTtDFa8pSo9L+wREqN8Do= 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=LylEZw22; 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="LylEZw22" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186157; 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=x2zkQ8QHVerDmJclJusaydT7y/LVeo8p20ja76pOAZo=; b=LylEZw22AXlaC7+BRfDNb3G4M6f77K9nPTpfYkiaMwhQ+DIPCpwRdfvJ+yvXrbrtygRpkr zVVJaqMHUM3CqSPQsLRdkSfAxwctkdU1idfFbn0wxpeKTsZcCY/drOMHxZCWbBQxwtASpi q9oJqTf/G5+DyBGVhRxCG47vONJD7nE= 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-659-4W1A-IuaM_-iYZyyLrpYNA-1; Tue, 19 May 2026 06:22:32 -0400 X-MC-Unique: 4W1A-IuaM_-iYZyyLrpYNA-1 X-Mimecast-MFC-AGG-ID: 4W1A-IuaM_-iYZyyLrpYNA_1779186150 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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 752EB180034E; Tue, 19 May 2026 10:22:30 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4A180180034E; Tue, 19 May 2026 10:22:27 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 05/36] cifs: Introduce an ALIGN8() macro Date: Tue, 19 May 2026 11:21:23 +0100 Message-ID: <20260519102158.592165-6-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" The PDU generation seems to do ALIGN(x, 8) a lot, so make a macro for that. 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/cifsglob.h | 2 ++ fs/smb/client/reparse.c | 2 +- fs/smb/client/smb2file.c | 3 +-- fs/smb/client/smb2misc.c | 2 +- fs/smb/client/smb2pdu.c | 28 ++++++++++++++-------------- 5 files changed, 19 insertions(+), 18 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index fc4028b5b5c8..69924b01dd2c 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -2392,4 +2392,6 @@ static inline int cifs_open_create_options(unsigned i= nt oflags, int opts) */ #define CIFS_INO_BLOCKS(size) DIV_ROUND_UP_ULL((u64)(size), 512) =20 +#define ALIGN8(x) ALIGN((x), 8) + #endif /* _CIFS_GLOB_H */ diff --git a/fs/smb/client/reparse.c b/fs/smb/client/reparse.c index cd1e1eaee67a..f6f9093e04fd 100644 --- a/fs/smb/client/reparse.c +++ b/fs/smb/client/reparse.c @@ -575,7 +575,7 @@ static struct smb2_create_ea_ctx *ea_create_context(u32= dlen, size_t *cc_len) { struct smb2_create_ea_ctx *cc; =20 - *cc_len =3D round_up(sizeof(*cc) + dlen, 8); + *cc_len =3D ALIGN8(sizeof(*cc) + dlen); cc =3D kzalloc(*cc_len, GFP_KERNEL); if (!cc) return ERR_PTR(-ENOMEM); diff --git a/fs/smb/client/smb2file.c b/fs/smb/client/smb2file.c index 6860eff31693..152ede08cd09 100644 --- a/fs/smb/client/smb2file.c +++ b/fs/smb/client/smb2file.c @@ -48,10 +48,9 @@ static struct smb2_symlink_err_rsp *symlink_data(const s= truct kvec *iov) cifs_dbg(FYI, "%s: skipping unhandled error context: 0x%x\n", __func__, le32_to_cpu(p->ErrorId)); =20 - len =3D ALIGN(le32_to_cpu(p->ErrorDataLength), 8); + len =3D ALIGN8(le32_to_cpu(p->ErrorDataLength)); if (len > end - ((u8 *)p + sizeof(*p))) return ERR_PTR(-EINVAL); - p =3D (struct smb2_error_context_rsp *)(p->ErrorContextData + len); } } else if (le32_to_cpu(err->ByteCount) >=3D sizeof(*sym) && diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 2a7355ce1a07..6194d677b0ba 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -255,7 +255,7 @@ smb2_check_message(char *buf, unsigned int pdu_len, uns= igned int len, * Some windows servers (win2016) will pad also the final * PDU in a compound to 8 bytes. */ - if (ALIGN(calc_len, 8) =3D=3D len) + if (ALIGN8(calc_len) =3D=3D len) return 0; =20 /* diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 971b075e2e7d..2d9fe803682e 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -652,14 +652,14 @@ build_signing_ctxt(struct smb2_signing_capabilities *= pneg_ctxt) /* * Context Data length must be rounded to multiple of 8 for some servers */ - pneg_ctxt->DataLength =3D cpu_to_le16(ALIGN(sizeof(struct smb2_signing_ca= pabilities) - + pneg_ctxt->DataLength =3D cpu_to_le16(ALIGN8(sizeof(struct smb2_signing_c= apabilities) - sizeof(struct smb2_neg_context) + - (num_algs * sizeof(u16)), 8)); + (num_algs * sizeof(u16)))); pneg_ctxt->SigningAlgorithmCount =3D cpu_to_le16(num_algs); pneg_ctxt->SigningAlgorithms[0] =3D cpu_to_le16(SIGNING_ALG_AES_CMAC); =20 ctxt_len +=3D sizeof(__le16) * num_algs; - ctxt_len =3D ALIGN(ctxt_len, 8); + ctxt_len =3D ALIGN8(ctxt_len); return ctxt_len; /* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */ } @@ -696,7 +696,7 @@ build_netname_ctxt(struct smb2_netname_neg_context *pne= g_ctxt, char *hostname) /* copy up to max of first 100 bytes of server name to NetName field */ pneg_ctxt->DataLength =3D cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetN= ame, hostname, 100, cp)); /* context size is DataLength + minimal smb2_neg_context */ - return ALIGN(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg_= context), 8); + return ALIGN8(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg= _context)); } =20 static void @@ -742,18 +742,18 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, * round up total_len of fixed part of SMB3 negotiate request to 8 * byte boundary before adding negotiate contexts */ - *total_len =3D ALIGN(*total_len, 8); + *total_len =3D ALIGN8(*total_len); =20 pneg_ctxt =3D (*total_len) + (char *)req; req->NegotiateContextOffset =3D cpu_to_le32(*total_len); =20 build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt); - ctxt_len =3D ALIGN(sizeof(struct smb2_preauth_neg_context), 8); + ctxt_len =3D ALIGN8(sizeof(struct smb2_preauth_neg_context)); *total_len +=3D ctxt_len; pneg_ctxt +=3D ctxt_len; =20 build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); - ctxt_len =3D ALIGN(sizeof(struct smb2_encryption_neg_context), 8); + ctxt_len =3D ALIGN8(sizeof(struct smb2_encryption_neg_context)); *total_len +=3D ctxt_len; pneg_ctxt +=3D ctxt_len; =20 @@ -782,7 +782,7 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, if (server->compression.requested) { build_compression_ctxt((struct smb2_compression_capabilities_context *) pneg_ctxt); - ctxt_len =3D ALIGN(sizeof(struct smb2_compression_capabilities_context),= 8); + ctxt_len =3D ALIGN8(sizeof(struct smb2_compression_capabilities_context)= ); *total_len +=3D ctxt_len; pneg_ctxt +=3D ctxt_len; neg_context_count++; @@ -973,7 +973,7 @@ static int smb311_decode_neg_context(struct smb2_negoti= ate_rsp *rsp, * aligned offset following the previous negotiate context. */ if (i + 1 !=3D ctxt_cnt) - clen =3D ALIGN(clen, 8); + clen =3D ALIGN8(clen); if (clen > len_of_ctxts) break; =20 @@ -2702,7 +2702,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned = int *len) unsigned int group_offset =3D 0; struct smb3_acl acl =3D {}; =20 - *len =3D round_up(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * = 4), 8); + *len =3D ALIGN8(sizeof(struct crt_sd_ctxt) + (sizeof(struct smb_ace) * 4)= ); =20 if (set_owner) { /* sizeof(struct owner_group_sids) is already multiple of 8 so no need t= o round */ @@ -2777,7 +2777,7 @@ create_sd_buf(umode_t mode, bool set_owner, unsigned = int *len) memcpy(aclptr, &acl, sizeof(struct smb3_acl)); =20 buf->ccontext.DataLength =3D cpu_to_le32(ptr - (__u8 *)&buf->sd); - *len =3D round_up((unsigned int)(ptr - (__u8 *)buf), 8); + *len =3D ALIGN8((unsigned int)(ptr - (__u8 *)buf)); =20 return buf; } @@ -2870,7 +2870,7 @@ alloc_path_with_tree_prefix(__le16 **out_path, int *o= ut_size, int *out_len, * final path needs to be 8-byte aligned as specified in * MS-SMB2 2.2.13 SMB2 CREATE Request. */ - *out_size =3D round_up(*out_len * sizeof(__le16), 8); + *out_size =3D ALIGN8(*out_len * sizeof(__le16)); *out_path =3D kzalloc(*out_size + sizeof(__le16) /* null */, GFP_KERNEL); if (!*out_path) return -ENOMEM; @@ -3141,7 +3141,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Ser= ver_Info *server, 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 round_up(uni_path_len, 8); + copy_size =3D ALIGN8(uni_path_len); copy_path =3D kzalloc(copy_size, GFP_KERNEL); if (!copy_path) return -ENOMEM; @@ -4580,7 +4580,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, if (request_type & CHAINED_REQUEST) { if (!(request_type & END_OF_CHAIN)) { /* next 8-byte aligned request */ - *total_len =3D ALIGN(*total_len, 8); + *total_len =3D ALIGN8(*total_len); shdr->NextCommand =3D cpu_to_le32(*total_len); } else /* END_OF_CHAIN */ shdr->NextCommand =3D 0; From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 993093A3E84 for ; Tue, 19 May 2026 10:22:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186166; cv=none; b=M0y++zSnEO/ZUpBuHEa1ZKrGV4ZAVGzApK4xuyzWP/DJJ2E0X+n3HQBM1H2v6Uq1M2EIpwhkbj7d5VicWII3MmiyE0+81zqGVxIIzE/AjPxxMZiCFmDbyxeKUh/hCDzZ/my0HoTRpZH3gdUaLdJFBtYH2BIiUuby+Bv3+zzNK9U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186166; c=relaxed/simple; bh=UnS3WLlEax4aKAQWI/Skfg3/IPLZZ5O+TjEVbib96ic=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=O/cq6A2tKsevQq0cMThMukb85jlrmSS5QWo7pr2ikUBHL9EC42iIT2NiKBeB9oN9V3EFkZbd+AVmndknkOaCtIHXj2a1KVj6pZNB9g6I8a+2YUYAvBjE0qKDzdX7B04Vd3J0mX9qRqBabC9EwNCZsJHQ8pqwnP4U+pacGj9PMrE= 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=AX9DzfTe; arc=none smtp.client-ip=170.10.133.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="AX9DzfTe" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186160; 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=VHv6uzP2cc3lhBUn+FDpH06+8TVfqASFrneWbhS4li8=; b=AX9DzfTeVNWLYFRI8Eq7oguH4fOdlpWoZOZUIhyEWMH3rfS2QdHTQmPnH2TUEpjvQ7GlPU QM/XNhaF5yVSZSGsXwZEFclH58U9Vb8lhFe6rdtaoPT7nJ/w7YuYfnMfvUAVDkL8xJG7OB RmLSBlXtSrItQsnYk7SExkv8MCiwJmY= Received: from mx-prod-mc-06.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-518-sC-HbGaPOjq7h7g-SrkiiA-1; Tue, 19 May 2026 06:22:37 -0400 X-MC-Unique: sC-HbGaPOjq7h7g-SrkiiA-1 X-Mimecast-MFC-AGG-ID: sC-HbGaPOjq7h7g-SrkiiA_1779186155 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C04161800617; Tue, 19 May 2026 10:22:35 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1C4621956053; Tue, 19 May 2026 10:22:31 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 06/36] cifs: Rename mid_q_entry to smb_message Date: Tue, 19 May 2026 11:21:24 +0100 Message-ID: <20260519102158.592165-7-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" Rename mid_q_entry to smb_message as future development that will allocate it at a higher level in the marshalling code and then hand it down into the transport layer. It will also be used to pass parameters such as the send and receive data buffers, credits and other things. 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/cifs_debug.c | 44 +++---- fs/smb/client/cifsfs.c | 30 ++--- fs/smb/client/cifsglob.h | 58 ++++---- fs/smb/client/cifsproto.h | 31 +++-- fs/smb/client/cifssmb.c | 36 ++--- fs/smb/client/connect.c | 150 ++++++++++----------- fs/smb/client/smb1maperror.c | 12 +- fs/smb/client/smb1ops.c | 40 +++--- fs/smb/client/smb1proto.h | 10 +- fs/smb/client/smb1transport.c | 86 ++++++------ fs/smb/client/smb2misc.c | 8 +- fs/smb/client/smb2ops.c | 122 ++++++++--------- fs/smb/client/smb2pdu.c | 38 +++--- fs/smb/client/smb2proto.h | 10 +- fs/smb/client/smb2transport.c | 76 +++++------ fs/smb/client/transport.c | 240 +++++++++++++++++----------------- 16 files changed, 495 insertions(+), 496 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 4ed4f55a0bb7..2d0d26ee57ce 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -38,33 +38,33 @@ cifs_dump_mem(char *label, void *data, int length) void cifs_dump_mids(struct TCP_Server_Info *server) { #ifdef CONFIG_CIFS_DEBUG2 - struct mid_q_entry *mid_entry; + struct smb_message *smb; =20 if (server =3D=3D NULL) return; =20 cifs_dbg(VFS, "Dump pending requests:\n"); spin_lock(&server->mid_queue_lock); - list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { + list_for_each_entry(smb, &server->pending_mid_q, qhead) { cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", - mid_entry->mid_state, - le16_to_cpu(mid_entry->command), - mid_entry->pid, - mid_entry->callback_data, - mid_entry->mid); + smb->mid_state, + le16_to_cpu(smb->command), + smb->pid, + smb->callback_data, + smb->mid); #ifdef CONFIG_CIFS_STATS2 cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", - mid_entry->large_buf, - mid_entry->resp_buf, - mid_entry->when_received, + smb->large_buf, + smb->resp_buf, + smb->when_received, jiffies); #endif /* STATS2 */ cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n", - mid_entry->multiRsp, mid_entry->multiEnd); - if (mid_entry->resp_buf) { - server->ops->dump_detail(mid_entry->resp_buf, - mid_entry->response_pdu_len, server); - cifs_dump_mem("existing buf: ", mid_entry->resp_buf, 62); + smb->multiRsp, smb->multiEnd); + if (smb->resp_buf) { + server->ops->dump_detail(smb->resp_buf, + smb->response_pdu_len, server); + cifs_dump_mem("existing buf: ", smb->resp_buf, 62); } } spin_unlock(&server->mid_queue_lock); @@ -437,7 +437,7 @@ static __always_inline const char *cipher_alg_str(__le1= 6 cipher) =20 static int cifs_debug_data_proc_show(struct seq_file *m, void *v) { - struct mid_q_entry *mid_entry; + struct smb_message *smb; struct TCP_Server_Info *server; struct TCP_Server_Info *chan_server; struct cifs_ses *ses; @@ -694,13 +694,13 @@ static int cifs_debug_data_proc_show(struct seq_file = *m, void *v) seq_printf(m, "\n\tServer ConnectionId: 0x%llx", chan_server->conn_id); spin_lock(&chan_server->mid_queue_lock); - list_for_each_entry(mid_entry, &chan_server->pending_mid_q, qhead) { + list_for_each_entry(smb, &chan_server->pending_mid_q, qhead) { seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu", - mid_entry->mid_state, - le16_to_cpu(mid_entry->command), - mid_entry->pid, - mid_entry->callback_data, - mid_entry->mid); + smb->mid_state, + le16_to_cpu(smb->command), + smb->pid, + smb->callback_data, + smb->mid); } spin_unlock(&chan_server->mid_queue_lock); } diff --git a/fs/smb/client/cifsfs.c b/fs/smb/client/cifsfs.c index f557eb7875c7..434c6943dd69 100644 --- a/fs/smb/client/cifsfs.c +++ b/fs/smb/client/cifsfs.c @@ -405,13 +405,13 @@ static int cifs_permission(struct mnt_idmap *idmap, =20 static struct kmem_cache *cifs_inode_cachep; static struct kmem_cache *cifs_req_cachep; -static struct kmem_cache *cifs_mid_cachep; +static struct kmem_cache *smb_message_cachep; static struct kmem_cache *cifs_sm_req_cachep; static struct kmem_cache *cifs_io_request_cachep; static struct kmem_cache *cifs_io_subrequest_cachep; mempool_t *cifs_sm_req_poolp; mempool_t *cifs_req_poolp; -mempool_t cifs_mid_pool; +mempool_t smb_message_pool; mempool_t cifs_io_request_pool; mempool_t cifs_io_subrequest_pool; =20 @@ -1820,27 +1820,27 @@ cifs_destroy_request_bufs(void) kmem_cache_destroy(cifs_sm_req_cachep); } =20 -static int init_mids(void) +static int init_smb_message(void) { - cifs_mid_cachep =3D kmem_cache_create("cifs_mpx_ids", - sizeof(struct mid_q_entry), 0, - SLAB_HWCACHE_ALIGN, NULL); - if (cifs_mid_cachep =3D=3D NULL) + smb_message_cachep =3D kmem_cache_create("cifs_smb_message", + sizeof(struct smb_message), 0, + SLAB_HWCACHE_ALIGN, NULL); + if (smb_message_cachep =3D=3D NULL) return -ENOMEM; =20 /* 3 is a reasonable minimum number of simultaneous operations */ - if (mempool_init_slab_pool(&cifs_mid_pool, 3, cifs_mid_cachep) < 0) { - kmem_cache_destroy(cifs_mid_cachep); + if (mempool_init_slab_pool(&smb_message_pool, 3, smb_message_cachep) < 0)= { + kmem_cache_destroy(smb_message_cachep); return -ENOMEM; } =20 return 0; } =20 -static void destroy_mids(void) +static void destroy_smb_message(void) { - mempool_exit(&cifs_mid_pool); - kmem_cache_destroy(cifs_mid_cachep); + mempool_exit(&smb_message_pool); + kmem_cache_destroy(smb_message_cachep); } =20 static int cifs_init_netfs(void) @@ -2015,7 +2015,7 @@ init_cifs(void) if (rc) goto out_destroy_inodecache; =20 - rc =3D init_mids(); + rc =3D init_smb_message(); if (rc) goto out_destroy_netfs; =20 @@ -2072,7 +2072,7 @@ init_cifs(void) #endif cifs_destroy_request_bufs(); out_destroy_mids: - destroy_mids(); + destroy_smb_message(); out_destroy_netfs: cifs_destroy_netfs(); out_destroy_inodecache: @@ -2114,7 +2114,7 @@ exit_cifs(void) dfs_cache_destroy(); #endif cifs_destroy_request_bufs(); - destroy_mids(); + destroy_smb_message(); cifs_destroy_netfs(); cifs_destroy_inodecache(); destroy_workqueue(deferredclose_wq); diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 69924b01dd2c..a5e12a2eefdd 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -291,7 +291,7 @@ struct smb_rqst { struct bvecq *rq_buffer; /* Buffer for encryption */ }; =20 -struct mid_q_entry; +struct smb_message; struct TCP_Server_Info; struct cifsFileInfo; struct cifs_ses; @@ -309,25 +309,25 @@ struct cifs_credits; =20 struct smb_version_operations { int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct mid_q_entry *mid, + struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid); bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *); /* setup request: allocate mid, sign message */ - struct mid_q_entry *(*setup_request)(struct cifs_ses *, - struct TCP_Server_Info *, - struct smb_rqst *); + struct smb_message *(*setup_request)(struct cifs_ses *ses, + struct TCP_Server_Info *server, + struct smb_rqst *rqst); /* setup async request: allocate mid, sign message */ - struct mid_q_entry *(*setup_async_request)(struct TCP_Server_Info *, - struct smb_rqst *); + struct smb_message *(*setup_async_request)(struct TCP_Server_Info *server, + struct smb_rqst *rqst); /* check response: verify signature, map error */ - int (*check_receive)(struct mid_q_entry *, struct TCP_Server_Info *, - bool); + int (*check_receive)(struct smb_message *mid, struct TCP_Server_Info *ser= ver, + bool log_error); void (*add_credits)(struct TCP_Server_Info *server, struct cifs_credits *credits, const int optype); void (*set_credits)(struct TCP_Server_Info *, const int); int * (*get_credits_field)(struct TCP_Server_Info *, const int); - unsigned int (*get_credits)(struct mid_q_entry *); + unsigned int (*get_credits)(struct smb_message *smb); __u64 (*get_next_mid)(struct TCP_Server_Info *); void (*revert_current_mid)(struct TCP_Server_Info *server, const unsigned int val); @@ -344,7 +344,7 @@ struct smb_version_operations { /* map smb to linux error */ int (*map_error)(char *, bool); /* find mid corresponding to the response message */ - struct mid_q_entry *(*find_mid)(struct TCP_Server_Info *server, char *buf= ); + struct smb_message *(*find_mid)(struct TCP_Server_Info *server, char *buf= ); void (*dump_detail)(void *buf, size_t buf_len, struct TCP_Server_Info *pt= cp_info); void (*clear_stats)(struct cifs_tcon *); void (*print_stats)(struct seq_file *m, struct cifs_tcon *); @@ -353,13 +353,13 @@ struct smb_version_operations { int (*check_message)(char *buf, unsigned int pdu_len, unsigned int len, struct TCP_Server_Info *server); bool (*is_oplock_break)(char *, struct TCP_Server_Info *); - int (*handle_cancelled_mid)(struct mid_q_entry *, struct TCP_Server_Info = *); + int (*handle_cancelled_mid)(struct smb_message *smb, struct TCP_Server_In= fo *server); void (*downgrade_oplock)(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch, bool *purge_cache); /* process transaction2 response */ - bool (*check_trans2)(struct mid_q_entry *, struct TCP_Server_Info *, - char *, int); + bool (*check_trans2)(struct smb_message *smb, struct TCP_Server_Info *ser= ver, + char *buf, int malformed); /* check if we need to negotiate */ bool (*need_neg)(struct TCP_Server_Info *); /* negotiate to the server */ @@ -595,7 +595,7 @@ struct smb_version_operations { struct smb_rqst *, struct smb_rqst *); int (*is_transform_hdr)(void *buf); int (*receive_transform)(struct TCP_Server_Info *, - struct mid_q_entry **, char **, int *); + struct smb_message **smb, char **, int *); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(struct TCP_Server_Info *server, char *buf, @@ -1682,7 +1682,7 @@ static inline void cifs_stats_bytes_read(struct cifs_= tcon *tcon, * the TCP_Server_Info will also be updated. */ typedef int (*mid_receive_t)(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *msg); =20 /* * This is the prototype for the mid callback function. This is called onc= e the @@ -1692,17 +1692,17 @@ typedef int (*mid_receive_t)(struct TCP_Server_Info= *server, * - it will be called by cifsd, with no locks held * - the mid will be removed from any lists */ -typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct mid_q_e= ntry *mid); +typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct smb_mes= sage *smb); =20 /* * This is the protopyte for mid handle function. This is called once the = mid * has been recognized after decryption of the message. */ typedef int (*mid_handle_t)(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *smb); =20 /* one of these for every pending CIFS request to the server */ -struct mid_q_entry { +struct smb_message { struct list_head qhead; /* mids waiting on reply from this server */ refcount_t refcount; __u64 mid; /* multiplex id */ @@ -1768,12 +1768,12 @@ static inline void cifs_num_waiters_dec(struct TCP_= Server_Info *server) } =20 #ifdef CONFIG_CIFS_STATS2 -static inline void cifs_save_when_sent(struct mid_q_entry *mid) +static inline void cifs_save_when_sent(struct smb_message *smb) { - mid->when_sent =3D jiffies; + smb->when_sent =3D jiffies; } #else -static inline void cifs_save_when_sent(struct mid_q_entry *mid) +static inline void cifs_save_when_sent(struct smb_message *smb) { } #endif @@ -2141,7 +2141,7 @@ extern __u32 cifs_lock_secret; =20 extern mempool_t *cifs_sm_req_poolp; extern mempool_t *cifs_req_poolp; -extern mempool_t cifs_mid_pool; +extern mempool_t smb_message_pool; extern mempool_t cifs_io_request_pool; extern mempool_t cifs_io_subrequest_pool; =20 @@ -2300,17 +2300,17 @@ static inline bool cifs_netbios_name(const char *na= me, size_t namelen) * and prevents sleeping in atomic context. */ static inline void mid_execute_callback(struct TCP_Server_Info *server, - struct mid_q_entry *mid) + struct smb_message *smb) { mid_callback_t callback; =20 - spin_lock(&mid->mid_lock); - callback =3D mid->callback; - mid->callback =3D NULL; /* Mark as executed, */ - spin_unlock(&mid->mid_lock); + spin_lock(&smb->mid_lock); + callback =3D smb->callback; + smb->callback =3D NULL; /* Mark as executed, */ + spin_unlock(&smb->mid_lock); =20 if (callback) - callback(server, mid); + callback(server, smb); } =20 #define CIFS_REPARSE_SUPPORT(tcon) \ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 79d891f7df1a..f88ae04af85d 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -80,13 +80,12 @@ char *cifs_build_path_to_root(struct smb3_fs_context *c= tx, struct cifs_sb_info *cifs_sb, struct cifs_tcon *tcon, int add_treename); char *cifs_build_devname(char *nodename, const char *prepath); -void delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid); -void __release_mid(struct TCP_Server_Info *server, - struct mid_q_entry *midEntry); +void delete_mid(struct TCP_Server_Info *server, struct smb_message *smb); +void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb= ); void cifs_wake_up_task(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *smb); int cifs_handle_standard(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *smb); char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dir= sep); int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); @@ -104,7 +103,7 @@ int compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, struct TCP_Server_Info *server, const int flags, const int num_rqst, struct smb_rqst *rqst, int *resp_buf_type, struct kvec *resp_iov); -int cifs_sync_mid_result(struct mid_q_entry *mid, +int cifs_sync_mid_result(struct smb_message *mid, struct TCP_Server_Info *server); int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst); @@ -115,14 +114,14 @@ int cifs_wait_mtu_credits(struct TCP_Server_Info *ser= ver, size_t size, =20 static inline int send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct mid_q_entry *mid, + struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid) { return server->ops->send_cancel ? - server->ops->send_cancel(ses, server, rqst, mid, xid) : 0; + server->ops->send_cancel(ses, server, rqst, smb, xid) : 0; } =20 -int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *= mid); +int wait_for_response(struct TCP_Server_Info *server, struct smb_message *= smb); =20 void smb2_query_server_interfaces(struct work_struct *work); void cifs_signal_cifsd_for_reconnect(struct TCP_Server_Info *server, @@ -222,7 +221,7 @@ unsigned int setup_special_mode_ACE(struct smb_ace *pnt= ace, bool posix, __u64 nmode); unsigned int setup_special_user_owner_ACE(struct smb_ace *pntace); =20 -void dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid, +void dequeue_mid(struct TCP_Server_Info *server, struct smb_message *smb, bool malformed); int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, unsigned int to_read); @@ -334,7 +333,7 @@ struct cifs_ses *cifs_get_smb_ses(struct TCP_Server_Inf= o *server, struct smb3_fs_context *ctx); =20 int cifs_readv_receive(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *smb); =20 int cifs_query_mf_symlink(unsigned int xid, struct cifs_tcon *tcon, struct cifs_sb_info *cifs_sb, @@ -471,15 +470,15 @@ static inline bool dfs_src_pathname_equal(const char = *s1, const char *s2) return true; } =20 -static inline void smb_get_mid(struct mid_q_entry *mid) +static inline void smb_get_mid(struct smb_message *smb) { - refcount_inc(&mid->refcount); + refcount_inc(&smb->refcount); } =20 -static inline void release_mid(struct TCP_Server_Info *server, struct mid_= q_entry *mid) +static inline void release_mid(struct TCP_Server_Info *server, struct smb_= message *smb) { - if (refcount_dec_and_test(&mid->refcount)) - __release_mid(server, mid); + if (refcount_dec_and_test(&smb->refcount)) + __release_mid(server, smb); } =20 static inline void cifs_free_open_info(struct cifs_open_info_data *data) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 0b1051a17ca8..25f6289ee72f 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -727,11 +727,11 @@ CIFSSMBTDis(const unsigned int xid, struct cifs_tcon = *tcon) * FIXME: maybe we should consider checking that the reply matches request? */ static void -cifs_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) +cifs_echo_callback(struct TCP_Server_Info *server, struct smb_message *smb) { struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0 }; =20 - release_mid(server, mid); + release_mid(server, smb); add_credits(server, &credits, CIFS_ECHO_OP); } =20 @@ -1460,9 +1460,9 @@ CIFS_open(const unsigned int xid, struct cifs_open_pa= rms *oparms, int *oplock, } =20 static void -cifs_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mi= d) +cifs_readv_callback(struct TCP_Server_Info *server, struct smb_message *sm= b) { - struct cifs_io_subrequest *rdata =3D mid->callback_data; + struct cifs_io_subrequest *rdata =3D smb->callback_data; struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct inode *inode =3D &ictx->inode; @@ -1478,7 +1478,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) unsigned int subreq_debug_index =3D rdata->subreq.debug_index; =20 cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%zu\n", - __func__, mid->mid, mid->mid_state, rdata->result, + __func__, smb->mid, smb->mid_state, rdata->result, rdata->subreq.len); =20 if (rdata->got_bytes) @@ -1486,7 +1486,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) rdata->subreq.content.bvecq, rdata->subreq.content.slot, rdata->subreq.content.offset, rdata->subreq.len); =20 - switch (mid->mid_state) { + switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: /* result already set, check signature */ if (server->sign) { @@ -1494,7 +1494,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) =20 iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); rc =3D cifs_verify_signature(&rqst, server, - mid->sequence_number); + smb->sequence_number); if (rc) cifs_dbg(VFS, "SMB signature verification returned error =3D %d\n", rc); @@ -1525,7 +1525,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) default: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown); rdata->result =3D smb_EIO1(smb_eio_trace_read_mid_state_unknown, - mid->mid_state); + smb->mid_state); break; } =20 @@ -1568,7 +1568,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) rdata->subreq.transferred +=3D rdata->got_bytes; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); - release_mid(server, mid); + release_mid(server, smb); add_credits(server, &credits, 0); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, @@ -1885,11 +1885,11 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io= _parms *io_parms, * workqueue completion task. */ static void -cifs_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *m= id) +cifs_writev_callback(struct TCP_Server_Info *server, struct smb_message *s= mb) { - struct cifs_io_subrequest *wdata =3D mid->callback_data; + struct cifs_io_subrequest *wdata =3D smb->callback_data; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); - WRITE_RSP *smb =3D (WRITE_RSP *)mid->resp_buf; + WRITE_RSP *rsp =3D (WRITE_RSP *)smb->resp_buf; struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0, @@ -1899,15 +1899,15 @@ cifs_writev_callback(struct TCP_Server_Info *server= , struct mid_q_entry *mid) ssize_t result; size_t written; =20 - switch (mid->mid_state) { + switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: - result =3D cifs_check_receive(mid, tcon->ses->server, 0); + result =3D cifs_check_receive(smb, tcon->ses->server, 0); if (result !=3D 0) break; =20 - written =3D le16_to_cpu(smb->CountHigh); + written =3D le16_to_cpu(rsp->CountHigh); written <<=3D 16; - written +=3D le16_to_cpu(smb->Count); + written +=3D le16_to_cpu(rsp->Count); /* * Mask off high 16 bits when bytes written as returned * by the server is greater than bytes requested by the @@ -1942,7 +1942,7 @@ cifs_writev_callback(struct TCP_Server_Info *server, = struct mid_q_entry *mid) default: trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown); result =3D smb_EIO1(smb_eio_trace_write_mid_state_unknown, - mid->mid_state); + smb->mid_state); break; } =20 @@ -1952,7 +1952,7 @@ cifs_writev_callback(struct TCP_Server_Info *server, = struct mid_q_entry *mid) 0, cifs_trace_rw_credits_write_response_clear); wdata->credits.value =3D 0; cifs_write_subrequest_terminated(wdata, result); - release_mid(server, mid); + release_mid(server, smb); trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_write_response_add); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index dcde25da468d..97de3ae68d7a 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -295,7 +295,7 @@ cifs_mark_tcp_ses_conns_for_reconnect(struct TCP_Server= _Info *server, static void cifs_abort_connection(struct TCP_Server_Info *server) { - struct mid_q_entry *mid, *nmid; + struct smb_message *smb, *nsmb; struct list_head retry_list; =20 server->maxBuf =3D 0; @@ -326,21 +326,21 @@ cifs_abort_connection(struct TCP_Server_Info *server) INIT_LIST_HEAD(&retry_list); cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); spin_lock(&server->mid_queue_lock); - list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) { - smb_get_mid(mid); - if (mid->mid_state =3D=3D MID_REQUEST_SUBMITTED) - mid->mid_state =3D MID_RETRY_NEEDED; - list_move(&mid->qhead, &retry_list); - mid->deleted_from_q =3D true; + list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { + smb_get_mid(smb); + if (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) + smb->mid_state =3D MID_RETRY_NEEDED; + list_move(&smb->qhead, &retry_list); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); cifs_server_unlock(server); =20 cifs_dbg(FYI, "%s: issuing mid callbacks\n", __func__); - list_for_each_entry_safe(mid, nmid, &retry_list, qhead) { - list_del_init(&mid->qhead); - mid_execute_callback(server, mid); - release_mid(server, mid); + list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) { + list_del_init(&smb->qhead); + mid_execute_callback(server, smb); + release_mid(server, smb); } } =20 @@ -870,7 +870,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigne= d char type) !server->with_rfc1001 && server->rfc1001_sessinit !=3D 0) { int rc, mid_rc; - struct mid_q_entry *mid, *nmid; + struct smb_message *smb, *nsmb; LIST_HEAD(dispose_list); =20 cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate,= retrying with NetBIOS session\n"); @@ -883,10 +883,10 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned char type) * corresponding to SMB1/SMB2 Negotiate packet. */ spin_lock(&server->mid_queue_lock); - list_for_each_entry_safe(mid, nmid, &server->pending_mid_q, qhead) { - smb_get_mid(mid); - list_move(&mid->qhead, &dispose_list); - mid->deleted_from_q =3D true; + list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { + smb_get_mid(smb); + list_move(&smb->qhead, &dispose_list); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); =20 @@ -913,12 +913,12 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned char type) * callback. Use MID_RC state which indicates that the * return code should be read from mid_rc member. */ - list_for_each_entry_safe(mid, nmid, &dispose_list, qhead) { - list_del_init(&mid->qhead); - mid->mid_rc =3D mid_rc; - mid->mid_state =3D MID_RC; - mid_execute_callback(server, mid); - release_mid(server, mid); + list_for_each_entry_safe(smb, nsmb, &dispose_list, qhead) { + list_del_init(&smb->qhead); + smb->mid_rc =3D mid_rc; + smb->mid_state =3D MID_RC; + mid_execute_callback(server, smb); + release_mid(server, smb); } =20 /* @@ -950,26 +950,26 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned char type) } =20 void -dequeue_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid, bool = malformed) +dequeue_mid(struct TCP_Server_Info *server, struct smb_message *smb, bool = malformed) { #ifdef CONFIG_CIFS_STATS2 - mid->when_received =3D jiffies; + smb->when_received =3D jiffies; #endif spin_lock(&server->mid_queue_lock); if (!malformed) - mid->mid_state =3D MID_RESPONSE_RECEIVED; + smb->mid_state =3D MID_RESPONSE_RECEIVED; else - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; /* * Trying to handle/dequeue a mid after the send_recv() * function has finished processing it is a bug. */ - if (mid->deleted_from_q =3D=3D true) { + if (smb->deleted_from_q =3D=3D true) { spin_unlock(&server->mid_queue_lock); pr_warn_once("trying to dequeue a deleted mid\n"); } else { - list_del_init(&mid->qhead); - mid->deleted_from_q =3D true; + list_del_init(&smb->qhead); + smb->deleted_from_q =3D true; spin_unlock(&server->mid_queue_lock); } } @@ -989,24 +989,24 @@ smb2_get_credits_from_hdr(char *buffer, struct TCP_Se= rver_Info *server) } =20 static void -handle_mid(struct mid_q_entry *mid, struct TCP_Server_Info *server, +handle_mid(struct smb_message *smb, struct TCP_Server_Info *server, char *buf, int malformed) { if (server->ops->check_trans2 && - server->ops->check_trans2(mid, server, buf, malformed)) + server->ops->check_trans2(smb, server, buf, malformed)) return; - mid->credits_received =3D smb2_get_credits_from_hdr(buf, server); - mid->resp_buf =3D buf; - mid->large_buf =3D server->large_buf; + smb->credits_received =3D smb2_get_credits_from_hdr(buf, server); + smb->resp_buf =3D buf; + smb->large_buf =3D server->large_buf; /* Was previous buf put in mpx struct for multi-rsp? */ - if (!mid->multiRsp) { + if (!smb->multiRsp) { /* smb buffer will be freed by user thread */ if (server->large_buf) server->bigbuf =3D NULL; else server->smallbuf =3D NULL; } - dequeue_mid(server, mid, malformed); + dequeue_mid(server, smb, malformed); } =20 int @@ -1095,28 +1095,28 @@ clean_demultiplex_info(struct TCP_Server_Info *serv= er) } =20 if (!list_empty(&server->pending_mid_q)) { - struct mid_q_entry *mid_entry; + struct smb_message *smb; struct list_head *tmp, *tmp2; LIST_HEAD(dispose_list); =20 spin_lock(&server->mid_queue_lock); list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { - mid_entry =3D list_entry(tmp, struct mid_q_entry, qhead); - cifs_dbg(FYI, "Clearing mid %llu\n", mid_entry->mid); - smb_get_mid(mid_entry); - mid_entry->mid_state =3D MID_SHUTDOWN; - list_move(&mid_entry->qhead, &dispose_list); - mid_entry->deleted_from_q =3D true; + smb =3D list_entry(tmp, struct smb_message, qhead); + cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid); + smb_get_mid(smb); + smb->mid_state =3D MID_SHUTDOWN; + list_move(&smb->qhead, &dispose_list); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); =20 /* now walk dispose list and issue callbacks */ list_for_each_safe(tmp, tmp2, &dispose_list) { - mid_entry =3D list_entry(tmp, struct mid_q_entry, qhead); - cifs_dbg(FYI, "Callback mid %llu\n", mid_entry->mid); - list_del_init(&mid_entry->qhead); - mid_execute_callback(server, mid_entry); - release_mid(server, mid_entry); + smb =3D list_entry(tmp, struct smb_message, qhead); + cifs_dbg(FYI, "Callback mid %llu\n", smb->mid); + list_del_init(&smb->qhead); + mid_execute_callback(server, smb); + release_mid(server, smb); } /* 1/8th of sec is more than enough time for them to exit */ msleep(125); @@ -1150,7 +1150,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) } =20 static int -standard_receive3(struct TCP_Server_Info *server, struct mid_q_entry *mid) +standard_receive3(struct TCP_Server_Info *server, struct smb_message *smb) { int length; char *buf =3D server->smallbuf; @@ -1180,11 +1180,11 @@ standard_receive3(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) =20 dump_smb(buf, server->total_read); =20 - return cifs_handle_standard(server, mid); + return cifs_handle_standard(server, smb); } =20 int -cifs_handle_standard(struct TCP_Server_Info *server, struct mid_q_entry *m= id) +cifs_handle_standard(struct TCP_Server_Info *server, struct smb_message *s= mb) { char *buf =3D server->large_buf ? server->bigbuf : server->smallbuf; int rc; @@ -1213,10 +1213,10 @@ cifs_handle_standard(struct TCP_Server_Info *server= , struct mid_q_entry *mid) server->ops->is_status_pending(buf, server)) return -1; =20 - if (!mid) + if (!smb) return rc; =20 - handle_mid(mid, server, buf, rc); + handle_mid(smb, server, buf, rc); return 0; } =20 @@ -1253,13 +1253,13 @@ smb2_add_credits_from_hdr(char *buffer, struct TCP_= Server_Info *server) static int cifs_demultiplex_thread(void *p) { - int i, num_mids, length; + int i, num_smbs, length; struct TCP_Server_Info *server =3D p; unsigned int pdu_length; unsigned int next_offset; char *buf =3D NULL; struct task_struct *task_to_wake =3D NULL; - struct mid_q_entry *mids[MAX_COMPOUND]; + struct smb_message *smbs[MAX_COMPOUND]; char *bufs[MAX_COMPOUND]; unsigned int noreclaim_flag, num_io_timeout =3D 0; bool pending_reconnect =3D false; @@ -1330,34 +1330,34 @@ cifs_demultiplex_thread(void *p) server->pdu_size =3D next_offset; } =20 - memset(mids, 0, sizeof(mids)); + memset(smbs, 0, sizeof(smbs)); memset(bufs, 0, sizeof(bufs)); - num_mids =3D 0; + num_smbs =3D 0; =20 if (server->ops->is_transform_hdr && server->ops->receive_transform && server->ops->is_transform_hdr(buf)) { length =3D server->ops->receive_transform(server, - mids, + smbs, bufs, - &num_mids); + &num_smbs); } else { - mids[0] =3D server->ops->find_mid(server, buf); + smbs[0] =3D server->ops->find_mid(server, buf); bufs[0] =3D buf; - num_mids =3D 1; + num_smbs =3D 1; =20 - if (mids[0]) - mids[0]->response_pdu_len =3D pdu_length; - if (!mids[0] || !mids[0]->receive) - length =3D standard_receive3(server, mids[0]); + if (smbs[0]) + smbs[0]->response_pdu_len =3D pdu_length; + if (!smbs[0] || !smbs[0]->receive) + length =3D standard_receive3(server, smbs[0]); else - length =3D mids[0]->receive(server, mids[0]); + length =3D smbs[0]->receive(server, smbs[0]); } =20 if (length < 0) { - for (i =3D 0; i < num_mids; i++) - if (mids[i]) - release_mid(server, mids[i]); + for (i =3D 0; i < num_smbs; i++) + if (smbs[i]) + release_mid(server, smbs[i]); continue; } =20 @@ -1376,9 +1376,9 @@ cifs_demultiplex_thread(void *p) =20 server->lstrp =3D jiffies; =20 - for (i =3D 0; i < num_mids; i++) { - if (mids[i] !=3D NULL) { - mids[i]->resp_buf_size =3D server->pdu_size; + for (i =3D 0; i < num_smbs; i++) { + if (smbs[i] !=3D NULL) { + smbs[i]->resp_buf_size =3D server->pdu_size; =20 if (bufs[i] !=3D NULL) { if (server->ops->is_network_name_deleted && @@ -1389,10 +1389,10 @@ cifs_demultiplex_thread(void *p) } } =20 - if (!mids[i]->multiRsp || mids[i]->multiEnd) - mid_execute_callback(server, mids[i]); + if (!smbs[i]->multiRsp || smbs[i]->multiEnd) + mid_execute_callback(server, smbs[i]); =20 - release_mid(server, mids[i]); + release_mid(server, smbs[i]); } else if (server->ops->is_oplock_break && server->ops->is_oplock_break(bufs[i], server)) { diff --git a/fs/smb/client/smb1maperror.c b/fs/smb/client/smb1maperror.c index 74530088d17d..c84f6256e146 100644 --- a/fs/smb/client/smb1maperror.c +++ b/fs/smb/client/smb1maperror.c @@ -172,16 +172,16 @@ map_smb_to_linux_error(char *buf, bool logErr) =20 int map_and_check_smb_error(struct TCP_Server_Info *server, - struct mid_q_entry *mid, bool logErr) + struct smb_message *smb, bool logErr) { int rc; - struct smb_hdr *smb =3D (struct smb_hdr *)mid->resp_buf; + struct smb_hdr *rhdr =3D (struct smb_hdr *)smb->resp_buf; =20 - rc =3D map_smb_to_linux_error((char *)smb, logErr); - if (rc =3D=3D -EACCES && !(smb->Flags2 & SMBFLG2_ERR_STATUS)) { + rc =3D map_smb_to_linux_error((char *)rhdr, logErr); + if (rc =3D=3D -EACCES && !(rhdr->Flags2 & SMBFLG2_ERR_STATUS)) { /* possible ERRBaduid */ - __u8 class =3D smb->Status.DosError.ErrorClass; - __u16 code =3D le16_to_cpu(smb->Status.DosError.Error); + __u8 class =3D rhdr->Status.DosError.ErrorClass; + __u16 code =3D le16_to_cpu(rhdr->Status.DosError.Error); =20 /* switch can be used to handle different errors */ if (class =3D=3D ERRSRV && code =3D=3D ERRbaduid) { diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index e198e3dda917..c1c16f6346fb 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -139,7 +139,7 @@ void reset_cifs_unix_caps(unsigned int xid, struct cifs= _tcon *tcon, */ static int send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct mid_q_entry *mid, + struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid) { struct smb_hdr *in_buf =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; @@ -156,7 +156,7 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_= Info *server, iov[0].iov_len =3D sizeof(struct smb_hdr) + 2; =20 cifs_server_lock(server); - rc =3D cifs_sign_rqst(&crqst, server, &mid->sequence_number); + rc =3D cifs_sign_rqst(&crqst, server, &smb->sequence_number); if (rc) { cifs_server_unlock(server); return rc; @@ -186,7 +186,7 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_= Info *server, */ static int send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct mid_q_entry *mid, + struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid) { struct smb_hdr *in_buf =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; @@ -212,12 +212,12 @@ send_lock_cancel(struct cifs_ses *ses, struct TCP_Ser= ver_Info *server, } =20 static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *= server, - struct smb_rqst *rqst, struct mid_q_entry *mid, + struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid) { - if (mid->sr_flags & CIFS_WINDOWS_LOCK) - return send_lock_cancel(ses, server, rqst, mid, xid); - return send_nt_cancel(ses, server, rqst, mid, xid); + if (smb->sr_flags & CIFS_WINDOWS_LOCK) + return send_lock_cancel(ses, server, rqst, smb, xid); + return send_nt_cancel(ses, server, rqst, smb, xid); } =20 static bool @@ -243,20 +243,20 @@ cifs_read_data_length(char *buf, bool in_remaining) le16_to_cpu(rsp->DataLength); } =20 -static struct mid_q_entry * +static struct smb_message * cifs_find_mid(struct TCP_Server_Info *server, char *buffer) { struct smb_hdr *buf =3D (struct smb_hdr *)buffer; - struct mid_q_entry *mid; + struct smb_message *smb; =20 spin_lock(&server->mid_queue_lock); - list_for_each_entry(mid, &server->pending_mid_q, qhead) { - if (compare_mid(mid->mid, buf) && - mid->mid_state =3D=3D MID_REQUEST_SUBMITTED && - le16_to_cpu(mid->command) =3D=3D buf->Command) { - smb_get_mid(mid); + list_for_each_entry(smb, &server->pending_mid_q, qhead) { + if (compare_mid(smb->mid, buf) && + smb->mid_state =3D=3D MID_REQUEST_SUBMITTED && + le16_to_cpu(smb->command) =3D=3D buf->Command) { + smb_get_mid(smb); spin_unlock(&server->mid_queue_lock); - return mid; + return smb; } } spin_unlock(&server->mid_queue_lock); @@ -290,7 +290,7 @@ cifs_get_credits_field(struct TCP_Server_Info *server, = const int optype) } =20 static unsigned int -cifs_get_credits(struct mid_q_entry *mid) +cifs_get_credits(struct smb_message *smb) { return 1; } @@ -343,7 +343,7 @@ cifs_get_next_mid(struct TCP_Server_Info *server) * did not time out). */ while (cur_mid !=3D last_mid) { - struct mid_q_entry *mid_entry; + struct smb_message *smb; unsigned int num_mids; =20 collision =3D false; @@ -352,10 +352,10 @@ cifs_get_next_mid(struct TCP_Server_Info *server) =20 num_mids =3D 0; spin_lock(&server->mid_queue_lock); - list_for_each_entry(mid_entry, &server->pending_mid_q, qhead) { + list_for_each_entry(smb, &server->pending_mid_q, qhead) { ++num_mids; - if (mid_entry->mid =3D=3D cur_mid && - mid_entry->mid_state =3D=3D MID_REQUEST_SUBMITTED) { + if (smb->mid =3D=3D cur_mid && + smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) { /* This mid is in use, try a different one */ collision =3D true; break; diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 5f522d359952..4ecf50b0922c 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -236,7 +236,7 @@ int cifs_verify_signature(struct smb_rqst *rqst, int map_smb_to_linux_error(char *buf, bool logErr); int smb1_init_maperror(void); int map_and_check_smb_error(struct TCP_Server_Info *server, - struct mid_q_entry *mid, bool logErr); + struct smb_message *smb, bool logErr); #if IS_ENABLED(CONFIG_SMB1_KUNIT_TESTS) extern const struct ntstatus_to_dos_err *ntstatus_to_dos_map_test; extern unsigned int ntstatus_to_dos_num; @@ -280,13 +280,13 @@ int CIFS_SessSetup(const unsigned int xid, struct cif= s_ses *ses, /* * smb1transport.c */ -struct mid_q_entry *cifs_setup_async_request(struct TCP_Server_Info *serve= r, +struct smb_message *cifs_setup_async_request(struct TCP_Server_Info *serve= r, struct smb_rqst *rqst); int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, char *in_buf, unsigned int in_len, int flags); -int cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *se= rver, +int cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, bool log_error); -struct mid_q_entry *cifs_setup_request(struct cifs_ses *ses, +struct smb_message *cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst); int SendReceive2(const unsigned int xid, struct cifs_ses *ses, @@ -296,7 +296,7 @@ int SendReceive(const unsigned int xid, struct cifs_ses= *ses, struct smb_hdr *in_buf, unsigned int in_len, struct smb_hdr *out_buf, int *pbytes_returned, const int flags); -bool cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *se= rver, +bool cifs_check_trans2(struct smb_message *smb, struct TCP_Server_Info *se= rver, char *buf, int malformed); int checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read, struct TCP_Server_Info *server); diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 53abb29fe71b..c2d211a62577 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -33,44 +33,44 @@ /* Max number of iovectors we can use off the stack when sending requests.= */ #define CIFS_MAX_IOV_SIZE 8 =20 -static struct mid_q_entry * +static struct smb_message * alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) { - struct mid_q_entry *temp; + struct smb_message *smb; =20 if (server =3D=3D NULL) { cifs_dbg(VFS, "%s: null TCP session\n", __func__); return NULL; } =20 - temp =3D mempool_alloc(&cifs_mid_pool, GFP_NOFS); - memset(temp, 0, sizeof(struct mid_q_entry)); - refcount_set(&temp->refcount, 1); - spin_lock_init(&temp->mid_lock); - temp->mid =3D get_mid(smb_buffer); - temp->pid =3D current->pid; - temp->command =3D cpu_to_le16(smb_buffer->Command); + smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); + memset(smb, 0, sizeof(struct smb_message)); + refcount_set(&smb->refcount, 1); + spin_lock_init(&smb->mid_lock); + smb->mid =3D get_mid(smb_buffer); + smb->pid =3D current->pid; + smb->command =3D cpu_to_le16(smb_buffer->Command); cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command); /* easier to use jiffies */ /* when mid allocated can be before when sent */ - temp->when_alloc =3D jiffies; + smb->when_alloc =3D jiffies; =20 /* * The default is for the mid to be synchronous, so the * default callback just wakes up the current task. */ get_task_struct(current); - temp->creator =3D current; - temp->callback =3D cifs_wake_up_task; - temp->callback_data =3D current; + smb->creator =3D current; + smb->callback =3D cifs_wake_up_task; + smb->callback_data =3D current; =20 atomic_inc(&mid_count); - temp->mid_state =3D MID_REQUEST_ALLOCATED; - return temp; + smb->mid_state =3D MID_REQUEST_ALLOCATED; + return smb; } =20 static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, - struct mid_q_entry **ppmidQ) + struct smb_message **ppmidQ) { spin_lock(&ses->ses_lock); if (ses->ses_status =3D=3D SES_NEW) { @@ -101,28 +101,28 @@ static int allocate_mid(struct cifs_ses *ses, struct = smb_hdr *in_buf, return 0; } =20 -struct mid_q_entry * +struct smb_message * cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *= rqst) { int rc; struct smb_hdr *hdr =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; - struct mid_q_entry *mid; + struct smb_message *smb; =20 /* enable signing if server requires it */ if (server->sign) hdr->Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; =20 - mid =3D alloc_mid(hdr, server); - if (mid =3D=3D NULL) + smb =3D alloc_mid(hdr, server); + if (smb =3D=3D NULL) return ERR_PTR(-ENOMEM); =20 - rc =3D cifs_sign_rqst(rqst, server, &mid->sequence_number); + rc =3D cifs_sign_rqst(rqst, server, &smb->sequence_number); if (rc) { - release_mid(server, mid); + release_mid(server, smb); return ERR_PTR(rc); } =20 - return mid; + return smb; } =20 /* @@ -153,12 +153,12 @@ SendReceiveNoRsp(const unsigned int xid, struct cifs_= ses *ses, } =20 int -cifs_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, +cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server, bool log_error) { - unsigned int len =3D mid->response_pdu_len; + unsigned int len =3D smb->response_pdu_len; =20 - dump_smb(mid->resp_buf, min_t(u32, 92, len)); + dump_smb(smb->resp_buf, min_t(u32, 92, len)); =20 /* convert the length into a more usable form */ if (server->sign) { @@ -167,11 +167,11 @@ cifs_check_receive(struct mid_q_entry *mid, struct TC= P_Server_Info *server, struct smb_rqst rqst =3D { .rq_iov =3D iov, .rq_nvec =3D ARRAY_SIZE(iov) }; =20 - iov[0].iov_base =3D mid->resp_buf; + iov[0].iov_base =3D smb->resp_buf; iov[0].iov_len =3D len; =20 rc =3D cifs_verify_signature(&rqst, server, - mid->sequence_number); + smb->sequence_number); if (rc) { cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d\= n", rc); @@ -184,26 +184,26 @@ cifs_check_receive(struct mid_q_entry *mid, struct TC= P_Server_Info *server, } =20 /* BB special case reconnect tid and uid here? */ - return map_and_check_smb_error(server, mid, log_error); + return map_and_check_smb_error(server, smb, log_error); } =20 -struct mid_q_entry * +struct smb_message * cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst) { int rc; struct smb_hdr *hdr =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; - struct mid_q_entry *mid; + struct smb_message *smb; =20 - rc =3D allocate_mid(ses, hdr, &mid); + rc =3D allocate_mid(ses, hdr, &smb); if (rc) return ERR_PTR(rc); - rc =3D cifs_sign_rqst(rqst, server, &mid->sequence_number); + rc =3D cifs_sign_rqst(rqst, server, &smb->sequence_number); if (rc) { - delete_mid(server, mid); + delete_mid(server, smb); return ERR_PTR(rc); } - return mid; + return smb; } =20 int @@ -411,22 +411,22 @@ coalesce_t2(char *second_buf, struct smb_hdr *target_= hdr, unsigned int *pdu_len) } =20 bool -cifs_check_trans2(struct mid_q_entry *mid, struct TCP_Server_Info *server, +cifs_check_trans2(struct smb_message *smb, struct TCP_Server_Info *server, char *buf, int malformed) { if (malformed) return false; if (check2ndT2(buf) <=3D 0) return false; - mid->multiRsp =3D true; - if (mid->resp_buf) { + smb->multiRsp =3D true; + if (smb->resp_buf) { /* merge response - fix up 1st*/ - malformed =3D coalesce_t2(buf, mid->resp_buf, &mid->response_pdu_len); + malformed =3D coalesce_t2(buf, smb->resp_buf, &smb->response_pdu_len); if (malformed > 0) return true; /* All parts received or packet is malformed. */ - mid->multiEnd =3D true; - dequeue_mid(server, mid, malformed); + smb->multiEnd =3D true; + dequeue_mid(server, smb, malformed); return true; } if (!server->large_buf) { @@ -434,8 +434,8 @@ cifs_check_trans2(struct mid_q_entry *mid, struct TCP_S= erver_Info *server, cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n"); } else { /* Have first buffer */ - mid->resp_buf =3D buf; - mid->large_buf =3D true; + smb->resp_buf =3D buf; + smb->large_buf =3D true; server->bigbuf =3D NULL; } return true; diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 6194d677b0ba..5c1d41baff7e 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -843,14 +843,14 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, _= _u64 persistent_fid, } =20 int -smb2_handle_cancelled_mid(struct mid_q_entry *mid, struct TCP_Server_Info = *server) +smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info = *server) { - struct smb2_hdr *hdr =3D mid->resp_buf; - struct smb2_create_rsp *rsp =3D mid->resp_buf; + struct smb2_hdr *hdr =3D smb->resp_buf; + struct smb2_create_rsp *rsp =3D smb->resp_buf; struct cifs_tcon *tcon; int rc; =20 - if ((mid->optype & CIFS_CP_CREATE_CLOSE_OP) || hdr->Command !=3D SMB2_CRE= ATE || + if ((smb->optype & CIFS_CP_CREATE_CLOSE_OP) || hdr->Command !=3D SMB2_CRE= ATE || hdr->Status !=3D STATUS_SUCCESS) return 0; =20 diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index b0b344724d2e..236eb560bdff 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -236,9 +236,9 @@ smb2_get_credits_field(struct TCP_Server_Info *server, = const int optype) } =20 static unsigned int -smb2_get_credits(struct mid_q_entry *mid) +smb2_get_credits(struct smb_message *smb) { - return mid->credits_received; + return smb->credits_received; } =20 static int @@ -399,10 +399,10 @@ smb2_revert_current_mid(struct TCP_Server_Info *serve= r, const unsigned int val) spin_unlock(&server->mid_counter_lock); } =20 -static struct mid_q_entry * +static struct smb_message * __smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue) { - struct mid_q_entry *mid; + struct smb_message *smb; struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; __u64 wire_mid =3D le64_to_cpu(shdr->MessageId); =20 @@ -412,30 +412,30 @@ __smb2_find_mid(struct TCP_Server_Info *server, char = *buf, bool dequeue) } =20 spin_lock(&server->mid_queue_lock); - list_for_each_entry(mid, &server->pending_mid_q, qhead) { - if ((mid->mid =3D=3D wire_mid) && - (mid->mid_state =3D=3D MID_REQUEST_SUBMITTED) && - (mid->command =3D=3D shdr->Command)) { - smb_get_mid(mid); + list_for_each_entry(smb, &server->pending_mid_q, qhead) { + if ((smb->mid =3D=3D wire_mid) && + (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) && + (smb->command =3D=3D shdr->Command)) { + smb_get_mid(smb); if (dequeue) { - list_del_init(&mid->qhead); - mid->deleted_from_q =3D true; + list_del_init(&smb->qhead); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); - return mid; + return smb; } } spin_unlock(&server->mid_queue_lock); return NULL; } =20 -static struct mid_q_entry * +static struct smb_message * smb2_find_mid(struct TCP_Server_Info *server, char *buf) { return __smb2_find_mid(server, buf, false); } =20 -static struct mid_q_entry * +static struct smb_message * smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf) { return __smb2_find_mid(server, buf, true); @@ -4721,7 +4721,7 @@ cifs_copy_bvecq_to_iter(struct bvecq *bq, size_t data= _size, } =20 static int -handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *mid, +handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb, char *buf, unsigned int buf_len, struct bvecq *buffer, unsigned int buffer_len, bool is_offloaded) { @@ -4731,7 +4731,7 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, unsigned int cur_off; unsigned int cur_page_idx; unsigned int pad_len; - struct cifs_io_subrequest *rdata =3D mid->callback_data; + struct cifs_io_subrequest *rdata =3D smb->callback_data; struct iov_iter iter; struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; size_t copied; @@ -4770,9 +4770,9 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, __func__, rdata->result); /* normal error on read response */ if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_RECEIVED; + smb->mid_state =3D MID_RESPONSE_RECEIVED; else - dequeue_mid(server, mid, false); + dequeue_mid(server, smb, false); return 0; } =20 @@ -4797,9 +4797,9 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, __func__, data_offset); rdata->result =3D smb_EIO1(smb_eio_trace_rx_overlong, data_offset); if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; else - dequeue_mid(server, mid, rdata->result); + dequeue_mid(server, smb, rdata->result); return 0; } =20 @@ -4820,9 +4820,9 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, __func__, data_offset); rdata->result =3D smb_EIO1(smb_eio_trace_rx_overpage, data_offset); if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; else - dequeue_mid(server, mid, rdata->result); + dequeue_mid(server, smb, rdata->result); return 0; } =20 @@ -4830,9 +4830,9 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, /* data_len is corrupt -- discard frame */ rdata->result =3D smb_EIO1(smb_eio_trace_rx_bad_datalen, data_len); if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; else - dequeue_mid(server, mid, rdata->result); + dequeue_mid(server, smb, rdata->result); return 0; } =20 @@ -4841,9 +4841,9 @@ handle_read_data(struct TCP_Server_Info *server, stru= ct mid_q_entry *mid, cur_off, &iter); if (rdata->result !=3D 0) { if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; else - dequeue_mid(server, mid, rdata->result); + dequeue_mid(server, smb, rdata->result); return 0; } rdata->got_bytes =3D buffer_len; @@ -4861,16 +4861,16 @@ handle_read_data(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid, WARN_ONCE(1, "buf can not contain only a part of read data"); rdata->result =3D smb_EIO(smb_eio_trace_rx_both_buf); if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_MALFORMED; + smb->mid_state =3D MID_RESPONSE_MALFORMED; else - dequeue_mid(server, mid, rdata->result); + dequeue_mid(server, smb, rdata->result); return 0; } =20 if (is_offloaded) - mid->mid_state =3D MID_RESPONSE_RECEIVED; + smb->mid_state =3D MID_RESPONSE_RECEIVED; else - dequeue_mid(server, mid, false); + dequeue_mid(server, smb, false); return 0; } =20 @@ -4888,7 +4888,7 @@ static void smb2_decrypt_offload(struct work_struct *= work) struct smb2_decrypt_work *dw =3D container_of(work, struct smb2_decrypt_work, decrypt); int rc; - struct mid_q_entry *mid; + struct smb_message *smb; struct iov_iter iter; =20 iov_iter_bvec_queue(&iter, ITER_DEST, dw->buffer, 0, 0, dw->len); @@ -4900,43 +4900,43 @@ static void smb2_decrypt_offload(struct work_struct= *work) } =20 dw->server->lstrp =3D jiffies; - mid =3D smb2_find_dequeue_mid(dw->server, dw->buf); - if (mid =3D=3D NULL) + smb =3D smb2_find_dequeue_mid(dw->server, dw->buf); + if (smb =3D=3D NULL) cifs_dbg(FYI, "mid not found\n"); else { - mid->decrypted =3D true; - rc =3D handle_read_data(dw->server, mid, dw->buf, + smb->decrypted =3D true; + rc =3D handle_read_data(dw->server, smb, dw->buf, dw->server->vals->read_rsp_size, dw->buffer, dw->len, true); if (rc >=3D 0) { #ifdef CONFIG_CIFS_STATS2 - mid->when_received =3D jiffies; + smb->when_received =3D jiffies; #endif if (dw->server->ops->is_network_name_deleted) dw->server->ops->is_network_name_deleted(dw->buf, dw->server); =20 - mid_execute_callback(dw->server, mid); + mid_execute_callback(dw->server, smb); } else { spin_lock(&dw->server->srv_lock); if (dw->server->tcpStatus =3D=3D CifsNeedReconnect) { spin_lock(&dw->server->mid_queue_lock); - mid->mid_state =3D MID_RETRY_NEEDED; + smb->mid_state =3D MID_RETRY_NEEDED; spin_unlock(&dw->server->mid_queue_lock); spin_unlock(&dw->server->srv_lock); - mid_execute_callback(dw->server, mid); + mid_execute_callback(dw->server, smb); } else { spin_lock(&dw->server->mid_queue_lock); - mid->mid_state =3D MID_REQUEST_SUBMITTED; - mid->deleted_from_q =3D false; - list_add_tail(&mid->qhead, + smb->mid_state =3D MID_REQUEST_SUBMITTED; + smb->deleted_from_q =3D false; + list_add_tail(&smb->qhead, &dw->server->pending_mid_q); spin_unlock(&dw->server->mid_queue_lock); spin_unlock(&dw->server->srv_lock); } } - release_mid(dw->server, mid); + release_mid(dw->server, smb); } =20 free_pages: @@ -4947,7 +4947,7 @@ static void smb2_decrypt_offload(struct work_struct *= work) =20 =20 static int -receive_encrypted_read(struct TCP_Server_Info *server, struct mid_q_entry = **mid, +receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message = **smb, int *num_mids) { char *buf =3D server->smallbuf; @@ -5031,13 +5031,13 @@ receive_encrypted_read(struct TCP_Server_Info *serv= er, struct mid_q_entry **mid, if (rc) goto free_pages; =20 - *mid =3D smb2_find_mid(server, buf); - if (*mid =3D=3D NULL) { + *smb =3D smb2_find_mid(server, buf); + if (*smb =3D=3D NULL) { cifs_dbg(FYI, "mid not found\n"); } else { cifs_dbg(FYI, "mid found\n"); - (*mid)->decrypted =3D true; - rc =3D handle_read_data(server, *mid, buf, + (*smb)->decrypted =3D true; + rc =3D handle_read_data(server, *smb, buf, server->vals->read_rsp_size, dw->buffer, dw->len, false); if (rc >=3D 0) { @@ -5060,7 +5060,7 @@ receive_encrypted_read(struct TCP_Server_Info *server= , struct mid_q_entry **mid, =20 static int receive_encrypted_standard(struct TCP_Server_Info *server, - struct mid_q_entry **mids, char **bufs, + struct smb_message **mids, char **bufs, int *num_mids) { int ret, length; @@ -5069,7 +5069,7 @@ receive_encrypted_standard(struct TCP_Server_Info *se= rver, unsigned int pdu_length =3D server->pdu_size; unsigned int buf_size; unsigned int next_cmd; - struct mid_q_entry *mid_entry; + struct smb_message *smb; int next_is_large; char *next_buffer =3D NULL; =20 @@ -5112,13 +5112,13 @@ receive_encrypted_standard(struct TCP_Server_Info *= server, memcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd); } =20 - mid_entry =3D smb2_find_mid(server, buf); - if (mid_entry =3D=3D NULL) + smb =3D smb2_find_mid(server, buf); + if (smb =3D=3D NULL) cifs_dbg(FYI, "mid not found\n"); else { cifs_dbg(FYI, "mid found\n"); - mid_entry->decrypted =3D true; - mid_entry->resp_buf_size =3D server->pdu_size; + smb->decrypted =3D true; + smb->resp_buf_size =3D server->pdu_size; } =20 if (*num_mids >=3D MAX_COMPOUND) { @@ -5126,12 +5126,12 @@ receive_encrypted_standard(struct TCP_Server_Info *= server, return -1; } bufs[*num_mids] =3D buf; - mids[(*num_mids)++] =3D mid_entry; + mids[(*num_mids)++] =3D smb; =20 - if (mid_entry && mid_entry->handle) - ret =3D mid_entry->handle(server, mid_entry); + if (smb && smb->handle) + ret =3D smb->handle(server, smb); else - ret =3D cifs_handle_standard(server, mid_entry); + ret =3D cifs_handle_standard(server, smb); =20 if (ret =3D=3D 0 && next_cmd) { pdu_length -=3D next_cmd; @@ -5159,7 +5159,7 @@ receive_encrypted_standard(struct TCP_Server_Info *se= rver, =20 static int smb3_receive_transform(struct TCP_Server_Info *server, - struct mid_q_entry **mids, char **bufs, int *num_mids) + struct smb_message **mids, char **bufs, int *num_mids) { char *buf =3D server->smallbuf; unsigned int pdu_length =3D server->pdu_size; @@ -5189,11 +5189,11 @@ smb3_receive_transform(struct TCP_Server_Info *serv= er, } =20 int -smb3_handle_read_data(struct TCP_Server_Info *server, struct mid_q_entry *= mid) +smb3_handle_read_data(struct TCP_Server_Info *server, struct smb_message *= smb) { char *buf =3D server->large_buf ? server->bigbuf : server->smallbuf; =20 - return handle_read_data(server, mid, buf, server->pdu_size, + return handle_read_data(server, smb, buf, server->pdu_size, NULL, 0, false); } =20 diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 2d9fe803682e..d4d2da2846e9 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4172,18 +4172,18 @@ SMB2_change_notify(const unsigned int xid, struct c= ifs_tcon *tcon, * FIXME: maybe we should consider checking that the reply matches request? */ static void -smb2_echo_callback(struct TCP_Server_Info *server, struct mid_q_entry *mid) +smb2_echo_callback(struct TCP_Server_Info *server, struct smb_message *smb) { - struct smb2_echo_rsp *rsp =3D (struct smb2_echo_rsp *)mid->resp_buf; + struct smb2_echo_rsp *rsp =3D (struct smb2_echo_rsp *)smb->resp_buf; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0 }; =20 - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED - || mid->mid_state =3D=3D MID_RESPONSE_MALFORMED) { + if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED + || smb->mid_state =3D=3D MID_RESPONSE_MALFORMED) { credits.value =3D le16_to_cpu(rsp->hdr.CreditRequest); credits.instance =3D server->reconnect_instance; } =20 - release_mid(server, mid); + release_mid(server, smb); add_credits(server, &credits, CIFS_ECHO_OP); } =20 @@ -4606,9 +4606,9 @@ smb2_new_read_req(void **buf, unsigned int *total_len, } =20 static void -smb2_readv_callback(struct TCP_Server_Info *server, struct mid_q_entry *mi= d) +smb2_readv_callback(struct TCP_Server_Info *server, struct smb_message *sm= b) { - struct cifs_io_subrequest *rdata =3D mid->callback_data; + struct cifs_io_subrequest *rdata =3D smb->callback_data; struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct smb2_hdr *shdr =3D (struct smb2_hdr *)rdata->iov[0].iov_base; @@ -4633,15 +4633,15 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct mid_q_entry *mid) rdata->server, server); =20 cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%zu/%zu\n", - __func__, mid->mid, mid->mid_state, rdata->result, + __func__, smb->mid, smb->mid_state, rdata->result, rdata->got_bytes, rdata->subreq.len - rdata->subreq.transferred); =20 - switch (mid->mid_state) { + switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: credits.value =3D le16_to_cpu(shdr->CreditRequest); credits.instance =3D server->reconnect_instance; /* result already set, check signature */ - if (server->sign && !mid->decrypted) { + if (server->sign && !smb->decrypted) { int rc; =20 iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); @@ -4688,7 +4688,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) default: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_unknown); rdata->result =3D smb_EIO1(smb_eio_trace_read_mid_state_unknown, - mid->mid_state); + smb->mid_state); break; } #ifdef CONFIG_CIFS_SMB_DIRECT @@ -4750,7 +4750,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct mid_q_entry *mid) rdata->subreq.transferred +=3D rdata->got_bytes; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); - release_mid(server, mid); + release_mid(server, smb); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_read_response_add); @@ -4946,11 +4946,11 @@ SMB2_read(const unsigned int xid, struct cifs_io_pa= rms *io_parms, * workqueue completion task. */ static void -smb2_writev_callback(struct TCP_Server_Info *server, struct mid_q_entry *m= id) +smb2_writev_callback(struct TCP_Server_Info *server, struct smb_message *s= mb) { - struct cifs_io_subrequest *wdata =3D mid->callback_data; + struct cifs_io_subrequest *wdata =3D smb->callback_data; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); - struct smb2_write_rsp *rsp =3D (struct smb2_write_rsp *)mid->resp_buf; + struct smb2_write_rsp *rsp =3D (struct smb2_write_rsp *)smb->resp_buf; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0, @@ -4966,11 +4966,11 @@ smb2_writev_callback(struct TCP_Server_Info *server= , struct mid_q_entry *mid) "wdata server %p !=3D mid server %p", wdata->server, server); =20 - switch (mid->mid_state) { + switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: credits.value =3D le16_to_cpu(rsp->hdr.CreditRequest); credits.instance =3D server->reconnect_instance; - result =3D smb2_check_receive(mid, server, 0); + result =3D smb2_check_receive(smb, server, 0); if (result !=3D 0) { if (is_replayable_error(result)) { trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_retry_needed); @@ -5021,7 +5021,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, = struct mid_q_entry *mid) default: trace_netfs_sreq(&wdata->subreq, netfs_sreq_trace_io_unknown); result =3D smb_EIO1(smb_eio_trace_write_mid_state_unknown, - mid->mid_state); + smb->mid_state); break; } #ifdef CONFIG_CIFS_SMB_DIRECT @@ -5070,7 +5070,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, = struct mid_q_entry *mid) wdata->replay =3D true; =20 cifs_write_subrequest_terminated(wdata, result ?: written); - release_mid(server, mid); + release_mid(server, smb); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_write_response_add); diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 1ceb95b907e6..5727e47733c8 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -38,19 +38,19 @@ __le16 *cifs_convert_path_to_utf16(const char *from, =20 int smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server); -int smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *se= rver, +int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, bool log_error); -struct mid_q_entry *smb2_setup_request(struct cifs_ses *ses, +struct smb_message *smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst); -struct mid_q_entry *smb2_setup_async_request(struct TCP_Server_Info *serve= r, +struct smb_message *smb2_setup_async_request(struct TCP_Server_Info *serve= r, struct smb_rqst *rqst); struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid); __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int opl= ock); bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *serv= er); int smb3_handle_read_data(struct TCP_Server_Info *server, - struct mid_q_entry *mid); + struct smb_message *smb); struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data, struct super_block *sb, const unsigned int xid, @@ -222,7 +222,7 @@ int SMB2_oplock_break(const unsigned int xid, struct ci= fs_tcon *tcon, __u8 oplock_level); int smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u64 persistent_f= id, __u64 volatile_fid); -int smb2_handle_cancelled_mid(struct mid_q_entry *mid, +int smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info *server); void smb2_cancelled_close_fid(struct work_struct *work); int SMB311_posix_qfs_info(const unsigned int xid, struct cifs_tcon *tcon, diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index e8eeff9e50d6..a28b66ead690 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -605,11 +605,11 @@ smb2_seq_num_into_buf(struct TCP_Server_Info *server, get_next_mid(server); } =20 -static struct mid_q_entry * +static struct smb_message * smb2_mid_entry_alloc(const struct smb2_hdr *shdr, struct TCP_Server_Info *server) { - struct mid_q_entry *temp; + struct smb_message *smb; unsigned int credits =3D le16_to_cpu(shdr->CreditCharge); =20 if (server =3D=3D NULL) { @@ -617,36 +617,36 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr, return NULL; } =20 - temp =3D mempool_alloc(&cifs_mid_pool, GFP_NOFS); - memset(temp, 0, sizeof(struct mid_q_entry)); - refcount_set(&temp->refcount, 1); - spin_lock_init(&temp->mid_lock); - temp->mid =3D le64_to_cpu(shdr->MessageId); - temp->credits =3D credits > 0 ? credits : 1; - temp->pid =3D current->pid; - temp->command =3D shdr->Command; /* Always LE */ - temp->when_alloc =3D jiffies; + smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); + memset(smb, 0, sizeof(*smb)); + refcount_set(&smb->refcount, 1); + spin_lock_init(&smb->mid_lock); + smb->mid =3D le64_to_cpu(shdr->MessageId); + smb->credits =3D credits > 0 ? credits : 1; + smb->pid =3D current->pid; + smb->command =3D shdr->Command; /* Always LE */ + smb->when_alloc =3D jiffies; =20 /* * The default is for the mid to be synchronous, so the * default callback just wakes up the current task. */ get_task_struct(current); - temp->creator =3D current; - temp->callback =3D cifs_wake_up_task; - temp->callback_data =3D current; + smb->creator =3D current; + smb->callback =3D cifs_wake_up_task; + smb->callback_data =3D current; =20 atomic_inc(&mid_count); - temp->mid_state =3D MID_REQUEST_ALLOCATED; + smb->mid_state =3D MID_REQUEST_ALLOCATED; trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId), le64_to_cpu(shdr->SessionId), - le16_to_cpu(shdr->Command), temp->mid); - return temp; + le16_to_cpu(shdr->Command), smb->mid); + return smb; } =20 static int smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb2_hdr *shdr, struct mid_q_entry **mid) + struct smb2_hdr *shdr, struct smb_message **smb) { switch (READ_ONCE(server->tcpStatus)) { case CifsExiting: @@ -678,31 +678,31 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_S= erver_Info *server, break; } =20 - *mid =3D smb2_mid_entry_alloc(shdr, server); - if (*mid =3D=3D NULL) + *smb =3D smb2_mid_entry_alloc(shdr, server); + if (*smb =3D=3D NULL) return -ENOMEM; spin_lock(&server->mid_queue_lock); - list_add_tail(&(*mid)->qhead, &server->pending_mid_q); + list_add_tail(&(*smb)->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); =20 return 0; } =20 int -smb2_check_receive(struct mid_q_entry *mid, struct TCP_Server_Info *server, +smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *server, bool log_error) { - unsigned int len =3D mid->resp_buf_size; + unsigned int len =3D smb->resp_buf_size; struct kvec iov[1]; struct smb_rqst rqst =3D { .rq_iov =3D iov, .rq_nvec =3D 1 }; =20 - iov[0].iov_base =3D (char *)mid->resp_buf; + iov[0].iov_base =3D (char *)smb->resp_buf; iov[0].iov_len =3D len; =20 - dump_smb(mid->resp_buf, min_t(u32, 80, len)); + dump_smb(smb->resp_buf, min_t(u32, 80, len)); /* convert the length into a more usable form */ - if (len > 24 && server->sign && !mid->decrypted) { + if (len > 24 && server->sign && !smb->decrypted) { int rc; =20 rc =3D smb2_verify_signature(&rqst, server); @@ -711,21 +711,21 @@ smb2_check_receive(struct mid_q_entry *mid, struct TC= P_Server_Info *server, rc); } =20 - return map_smb2_to_linux_error(mid->resp_buf, log_error); + return map_smb2_to_linux_error(smb->resp_buf, log_error); } =20 -struct mid_q_entry * +struct smb_message * smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst) { int rc; struct smb2_hdr *shdr =3D (struct smb2_hdr *)rqst->rq_iov[0].iov_base; - struct mid_q_entry *mid; + struct smb_message *smb; =20 smb2_seq_num_into_buf(server, shdr); =20 - rc =3D smb2_get_mid_entry(ses, server, shdr, &mid); + rc =3D smb2_get_mid_entry(ses, server, shdr, &smb); if (rc) { revert_current_mid_from_hdr(server, shdr); return ERR_PTR(rc); @@ -734,20 +734,20 @@ smb2_setup_request(struct cifs_ses *ses, struct TCP_S= erver_Info *server, rc =3D smb2_sign_rqst(rqst, server); if (rc) { revert_current_mid_from_hdr(server, shdr); - delete_mid(server, mid); + delete_mid(server, smb); return ERR_PTR(rc); } =20 - return mid; + return smb; } =20 -struct mid_q_entry * +struct smb_message * smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *= rqst) { int rc; struct smb2_hdr *shdr =3D (struct smb2_hdr *)rqst->rq_iov[0].iov_base; - struct mid_q_entry *mid; + struct smb_message *smb; =20 spin_lock(&server->srv_lock); if (server->tcpStatus =3D=3D CifsNeedNegotiate && @@ -759,8 +759,8 @@ smb2_setup_async_request(struct TCP_Server_Info *server= , struct smb_rqst *rqst) =20 smb2_seq_num_into_buf(server, shdr); =20 - mid =3D smb2_mid_entry_alloc(shdr, server); - if (mid =3D=3D NULL) { + smb =3D smb2_mid_entry_alloc(shdr, server); + if (smb =3D=3D NULL) { revert_current_mid_from_hdr(server, shdr); return ERR_PTR(-ENOMEM); } @@ -768,11 +768,11 @@ smb2_setup_async_request(struct TCP_Server_Info *serv= er, struct smb_rqst *rqst) rc =3D smb2_sign_rqst(rqst, server); if (rc) { revert_current_mid_from_hdr(server, shdr); - release_mid(server, mid); + release_mid(server, smb); return ERR_PTR(rc); } =20 - return mid; + return smb; } =20 int diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index be2f6b909c34..622f63779de0 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -31,39 +31,39 @@ #include "compress.h" =20 void -cifs_wake_up_task(struct TCP_Server_Info *server, struct mid_q_entry *mid) +cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb) { - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED) - mid->mid_state =3D MID_RESPONSE_READY; - wake_up_process(mid->callback_data); + if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) + smb->mid_state =3D MID_RESPONSE_READY; + wake_up_process(smb->callback_data); } =20 -void __release_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid= Entry) +void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb) { #ifdef CONFIG_CIFS_STATS2 __le16 command =3D server->vals->lock_cmd; - __u16 smb_cmd =3D le16_to_cpu(midEntry->command); + __u16 smb_cmd =3D le16_to_cpu(smb->command); unsigned long now; unsigned long roundtrip_time; #endif =20 - if (midEntry->resp_buf && (midEntry->wait_cancelled) && - (midEntry->mid_state =3D=3D MID_RESPONSE_RECEIVED || - midEntry->mid_state =3D=3D MID_RESPONSE_READY) && + if (smb->resp_buf && smb->wait_cancelled && + (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED || + smb->mid_state =3D=3D MID_RESPONSE_READY) && server->ops->handle_cancelled_mid) - server->ops->handle_cancelled_mid(midEntry, server); + server->ops->handle_cancelled_mid(smb, server); =20 - midEntry->mid_state =3D MID_FREE; + smb->mid_state =3D MID_FREE; atomic_dec(&mid_count); - if (midEntry->large_buf) - cifs_buf_release(midEntry->resp_buf); + if (smb->large_buf) + cifs_buf_release(smb->resp_buf); else - cifs_small_buf_release(midEntry->resp_buf); + cifs_small_buf_release(smb->resp_buf); #ifdef CONFIG_CIFS_STATS2 now =3D jiffies; - if (now < midEntry->when_alloc) + if (now < smb->when_alloc) cifs_server_dbg(VFS, "Invalid mid allocation time\n"); - roundtrip_time =3D now - midEntry->when_alloc; + roundtrip_time =3D now - smb->when_alloc; =20 if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) { if (atomic_read(&server->num_cmds[smb_cmd]) =3D=3D 0) { @@ -89,8 +89,8 @@ void __release_mid(struct TCP_Server_Info *server, struct= mid_q_entry *midEntry) * checks */ if ((slow_rsp_threshold !=3D 0) && - time_after(now, midEntry->when_alloc + (slow_rsp_threshold * HZ)) && - (midEntry->command !=3D command)) { + time_after(now, smb->when_alloc + (slow_rsp_threshold * HZ)) && + (smb->command !=3D command)) { /* * smb2slowcmd[NUMBER_OF_SMB2_COMMANDS] counts by command * NB: le16_to_cpu returns unsigned so can not be negative below @@ -98,35 +98,35 @@ void __release_mid(struct TCP_Server_Info *server, stru= ct mid_q_entry *midEntry) if (smb_cmd < NUMBER_OF_SMB2_COMMANDS) cifs_stats_inc(&server->smb2slowcmd[smb_cmd]); =20 - trace_smb3_slow_rsp(smb_cmd, midEntry->mid, midEntry->pid, - midEntry->when_sent, midEntry->when_received); + trace_smb3_slow_rsp(smb_cmd, smb->mid, smb->pid, + smb->when_sent, smb->when_received); if (cifsFYI & CIFS_TIMER) { pr_debug("slow rsp: cmd %d mid %llu", - midEntry->command, midEntry->mid); + smb->command, smb->mid); cifs_info("A: 0x%lx S: 0x%lx R: 0x%lx\n", - now - midEntry->when_alloc, - now - midEntry->when_sent, - now - midEntry->when_received); + now - smb->when_alloc, + now - smb->when_sent, + now - smb->when_received); } } #endif - put_task_struct(midEntry->creator); + put_task_struct(smb->creator); =20 - mempool_free(midEntry, &cifs_mid_pool); + mempool_free(smb, &smb_message_pool); } =20 void -delete_mid(struct TCP_Server_Info *server, struct mid_q_entry *mid) +delete_mid(struct TCP_Server_Info *server, struct smb_message *smb) { spin_lock(&server->mid_queue_lock); =20 - if (!mid->deleted_from_q) { - list_del_init(&mid->qhead); - mid->deleted_from_q =3D true; + if (!smb->deleted_from_q) { + list_del_init(&smb->qhead); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); =20 - release_mid(server, mid); + release_mid(server, smb); } =20 /* @@ -637,17 +637,17 @@ cifs_wait_mtu_credits(struct TCP_Server_Info *server,= size_t size, return 0; } =20 -int wait_for_response(struct TCP_Server_Info *server, struct mid_q_entry *= mid) +int wait_for_response(struct TCP_Server_Info *server, struct smb_message *= smb) { unsigned int sleep_state =3D TASK_KILLABLE; int error; =20 - if (mid->sr_flags & CIFS_INTERRUPTIBLE_WAIT) + if (smb->sr_flags & CIFS_INTERRUPTIBLE_WAIT) sleep_state =3D TASK_INTERRUPTIBLE; =20 error =3D wait_event_state(server->response_q, - mid->mid_state !=3D MID_REQUEST_SUBMITTED && - mid->mid_state !=3D MID_RESPONSE_RECEIVED, + smb->mid_state !=3D MID_REQUEST_SUBMITTED && + smb->mid_state !=3D MID_RESPONSE_RECEIVED, (sleep_state | TASK_FREEZABLE_UNSAFE)); if (error < 0) return -ERESTARTSYS; @@ -666,7 +666,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct = smb_rqst *rqst, const struct cifs_credits *exist_credits) { int rc; - struct mid_q_entry *mid; + struct smb_message *smb; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0 }; unsigned int instance; int optype; @@ -695,36 +695,36 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, return -EAGAIN; } =20 - mid =3D server->ops->setup_async_request(server, rqst); - if (IS_ERR(mid)) { + smb =3D server->ops->setup_async_request(server, rqst); + if (IS_ERR(smb)) { cifs_server_unlock(server); add_credits_and_wake_if(server, &credits, optype); - return PTR_ERR(mid); + return PTR_ERR(smb); } =20 - mid->sr_flags =3D flags; - mid->receive =3D receive; - mid->callback =3D callback; - mid->callback_data =3D cbdata; - mid->handle =3D handle; - mid->mid_state =3D MID_REQUEST_SUBMITTED; + smb->sr_flags =3D flags; + smb->receive =3D receive; + smb->callback =3D callback; + smb->callback_data =3D cbdata; + smb->handle =3D handle; + smb->mid_state =3D MID_REQUEST_SUBMITTED; =20 /* put it on the pending_mid_q */ spin_lock(&server->mid_queue_lock); - list_add_tail(&mid->qhead, &server->pending_mid_q); + list_add_tail(&smb->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); =20 /* * Need to store the time in mid before calling I/O. For call_async, * I/O response may come back and free the mid entry on another thread. */ - cifs_save_when_sent(mid); + cifs_save_when_sent(smb); rc =3D smb_send_rqst(server, 1, rqst, flags); =20 if (rc < 0) { - revert_current_mid(server, mid->credits); + revert_current_mid(server, smb->credits); server->sequence_number -=3D 2; - delete_mid(server, mid); + delete_mid(server, smb); } =20 cifs_server_unlock(server); @@ -736,15 +736,15 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, return rc; } =20 -int cifs_sync_mid_result(struct mid_q_entry *mid, struct TCP_Server_Info *= server) +int cifs_sync_mid_result(struct smb_message *smb, struct TCP_Server_Info *= server) { int rc =3D 0; =20 cifs_dbg(FYI, "%s: cmd=3D%d mid=3D%llu state=3D%d\n", - __func__, le16_to_cpu(mid->command), mid->mid, mid->mid_state); + __func__, le16_to_cpu(smb->command), smb->mid, smb->mid_state); =20 spin_lock(&server->mid_queue_lock); - switch (mid->mid_state) { + switch (smb->mid_state) { case MID_RESPONSE_READY: spin_unlock(&server->mid_queue_lock); return rc; @@ -758,52 +758,52 @@ int cifs_sync_mid_result(struct mid_q_entry *mid, str= uct TCP_Server_Info *server rc =3D -EHOSTDOWN; break; case MID_RC: - rc =3D mid->mid_rc; + rc =3D smb->mid_rc; break; default: - if (mid->deleted_from_q =3D=3D false) { - list_del_init(&mid->qhead); - mid->deleted_from_q =3D true; + if (smb->deleted_from_q =3D=3D false) { + list_del_init(&smb->qhead); + smb->deleted_from_q =3D true; } spin_unlock(&server->mid_queue_lock); cifs_server_dbg(VFS, "%s: invalid mid state mid=3D%llu state=3D%d\n", - __func__, mid->mid, mid->mid_state); - rc =3D smb_EIO1(smb_eio_trace_rx_sync_mid_invalid, mid->mid_state); + __func__, smb->mid, smb->mid_state); + rc =3D smb_EIO1(smb_eio_trace_rx_sync_mid_invalid, smb->mid_state); goto sync_mid_done; } spin_unlock(&server->mid_queue_lock); =20 sync_mid_done: - release_mid(server, mid); + release_mid(server, smb); return rc; } =20 static void -cifs_compound_callback(struct TCP_Server_Info *server, struct mid_q_entry = *mid) +cifs_compound_callback(struct TCP_Server_Info *server, struct smb_message = *smb) { struct cifs_credits credits =3D { - .value =3D server->ops->get_credits(mid), + .value =3D server->ops->get_credits(smb), .instance =3D server->reconnect_instance, }; =20 - add_credits(server, &credits, mid->optype); + add_credits(server, &credits, smb->optype); =20 - if (mid->mid_state =3D=3D MID_RESPONSE_RECEIVED) - mid->mid_state =3D MID_RESPONSE_READY; + if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) + smb->mid_state =3D MID_RESPONSE_READY; } =20 static void -cifs_compound_last_callback(struct TCP_Server_Info *server, struct mid_q_e= ntry *mid) +cifs_compound_last_callback(struct TCP_Server_Info *server, struct smb_mes= sage *smb) { - cifs_compound_callback(server, mid); - cifs_wake_up_task(server, mid); + cifs_compound_callback(server, smb); + cifs_wake_up_task(server, smb); } =20 static void -cifs_cancelled_callback(struct TCP_Server_Info *server, struct mid_q_entry= *mid) +cifs_cancelled_callback(struct TCP_Server_Info *server, struct smb_message= *smb) { - cifs_compound_callback(server, mid); - release_mid(server, mid); + cifs_compound_callback(server, smb); + release_mid(server, smb); } =20 /* @@ -866,8 +866,8 @@ compound_send_recv(const unsigned int xid, struct cifs_= ses *ses, int *resp_buf_type, struct kvec *resp_iov) { int i, j, optype, rc =3D 0; - struct mid_q_entry *mid[MAX_COMPOUND]; - bool cancelled_mid[MAX_COMPOUND] =3D {false}; + struct smb_message *smb[MAX_COMPOUND]; + bool cancelled_smb[MAX_COMPOUND] =3D {false}; struct cifs_credits credits[MAX_COMPOUND] =3D { { .value =3D 0, .instance =3D 0 } }; @@ -932,36 +932,36 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, } =20 for (i =3D 0; i < num_rqst; i++) { - mid[i] =3D server->ops->setup_request(ses, server, &rqst[i]); - if (IS_ERR(mid[i])) { + smb[i] =3D server->ops->setup_request(ses, server, &rqst[i]); + if (IS_ERR(smb[i])) { revert_current_mid(server, i); for (j =3D 0; j < i; j++) - delete_mid(server, mid[j]); + delete_mid(server, smb[j]); cifs_server_unlock(server); =20 /* Update # of requests on wire to server */ for (j =3D 0; j < num_rqst; j++) add_credits(server, &credits[j], optype); - return PTR_ERR(mid[i]); + return PTR_ERR(smb[i]); } =20 - mid[i]->sr_flags =3D flags; - mid[i]->mid_state =3D MID_REQUEST_SUBMITTED; - mid[i]->optype =3D optype; + smb[i]->sr_flags =3D flags; + smb[i]->mid_state =3D MID_REQUEST_SUBMITTED; + smb[i]->optype =3D optype; /* * Invoke callback for every part of the compound chain * to calculate credits properly. Wake up this thread only when * the last element is received. */ if (i < num_rqst - 1) - mid[i]->callback =3D cifs_compound_callback; + smb[i]->callback =3D cifs_compound_callback; else - mid[i]->callback =3D cifs_compound_last_callback; + smb[i]->callback =3D cifs_compound_last_callback; } rc =3D smb_send_rqst(server, num_rqst, rqst, flags); =20 for (i =3D 0; i < num_rqst; i++) - cifs_save_when_sent(mid[i]); + cifs_save_when_sent(smb[i]); =20 if (rc < 0) { revert_current_mid(server, num_rqst); @@ -1007,24 +1007,24 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, spin_unlock(&ses->ses_lock); =20 for (i =3D 0; i < num_rqst; i++) { - rc =3D wait_for_response(server, mid[i]); + rc =3D wait_for_response(server, smb[i]); if (rc !=3D 0) break; } if (rc !=3D 0) { for (; i < num_rqst; i++) { cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", - mid[i]->mid, le16_to_cpu(mid[i]->command)); - send_cancel(ses, server, &rqst[i], mid[i], xid); - spin_lock(&mid[i]->mid_lock); - mid[i]->wait_cancelled =3D true; - if (mid[i]->mid_state =3D=3D MID_REQUEST_SUBMITTED || - mid[i]->mid_state =3D=3D MID_RESPONSE_RECEIVED) { - mid[i]->callback =3D cifs_cancelled_callback; - cancelled_mid[i] =3D true; + smb[i]->mid, le16_to_cpu(smb[i]->command)); + send_cancel(ses, server, &rqst[i], smb[i], xid); + spin_lock(&smb[i]->mid_lock); + smb[i]->wait_cancelled =3D true; + if (smb[i]->mid_state =3D=3D MID_REQUEST_SUBMITTED || + smb[i]->mid_state =3D=3D MID_RESPONSE_RECEIVED) { + smb[i]->callback =3D cifs_cancelled_callback; + cancelled_smb[i] =3D true; credits[i].value =3D 0; } - spin_unlock(&mid[i]->mid_lock); + spin_unlock(&smb[i]->mid_lock); } } =20 @@ -1032,36 +1032,36 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, if (rc < 0) goto out; =20 - rc =3D cifs_sync_mid_result(mid[i], server); + rc =3D cifs_sync_mid_result(smb[i], server); if (rc !=3D 0) { /* mark this mid as cancelled to not free it below */ - cancelled_mid[i] =3D true; + cancelled_smb[i] =3D true; goto out; } =20 - if (!mid[i]->resp_buf || - mid[i]->mid_state !=3D MID_RESPONSE_READY) { - rc =3D smb_EIO1(smb_eio_trace_rx_mid_unready, mid[i]->mid_state); + if (!smb[i]->resp_buf || + smb[i]->mid_state !=3D MID_RESPONSE_READY) { + rc =3D smb_EIO1(smb_eio_trace_rx_mid_unready, smb[i]->mid_state); cifs_dbg(FYI, "Bad MID state?\n"); goto out; } =20 - rc =3D server->ops->check_receive(mid[i], server, + rc =3D server->ops->check_receive(smb[i], server, flags & CIFS_LOG_ERROR); =20 if (resp_iov) { - buf =3D (char *)mid[i]->resp_buf; + buf =3D (char *)smb[i]->resp_buf; resp_iov[i].iov_base =3D buf; - resp_iov[i].iov_len =3D mid[i]->resp_buf_size; + resp_iov[i].iov_len =3D smb[i]->resp_buf_size; =20 - if (mid[i]->large_buf) + if (smb[i]->large_buf) resp_buf_type[i] =3D CIFS_LARGE_BUFFER; else resp_buf_type[i] =3D CIFS_SMALL_BUFFER; =20 /* mark it so buf will not be freed by delete_mid */ if ((flags & CIFS_NO_RSP_BUF) =3D=3D 0) - mid[i]->resp_buf =3D NULL; + smb[i]->resp_buf =3D NULL; } } =20 @@ -1090,8 +1090,8 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, * wake this thread except for the very last PDU. */ for (i =3D 0; i < num_rqst; i++) { - if (!cancelled_mid[i]) - delete_mid(server, mid[i]); + if (!cancelled_smb[i]) + delete_mid(server, smb[i]); } =20 return rc; @@ -1134,38 +1134,38 @@ cifs_discard_remaining_data(struct TCP_Server_Info = *server) } =20 static int -__cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *m= id, +__cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *s= mb, bool malformed) { int length; =20 length =3D cifs_discard_remaining_data(server); - dequeue_mid(server, mid, malformed); - mid->resp_buf =3D server->smallbuf; + dequeue_mid(server, smb, malformed); + smb->resp_buf =3D server->smallbuf; server->smallbuf =3D NULL; return length; } =20 static int -cifs_readv_discard(struct TCP_Server_Info *server, struct mid_q_entry *mid) +cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb) { - struct cifs_io_subrequest *rdata =3D mid->callback_data; + struct cifs_io_subrequest *rdata =3D smb->callback_data; =20 - return __cifs_readv_discard(server, mid, rdata->result); + return __cifs_readv_discard(server, smb, rdata->result); } =20 int -cifs_readv_receive(struct TCP_Server_Info *server, struct mid_q_entry *mid) +cifs_readv_receive(struct TCP_Server_Info *server, struct smb_message *smb) { int length, len; unsigned int data_offset, data_len, end_off; - struct cifs_io_subrequest *rdata =3D mid->callback_data; + struct cifs_io_subrequest *rdata =3D smb->callback_data; char *buf =3D server->smallbuf; unsigned int buflen =3D server->pdu_size; bool use_rdma_mr =3D false; =20 cifs_dbg(FYI, "%s: mid=3D%llu offset=3D%llu bytes=3D%zu\n", - __func__, mid->mid, rdata->subreq.start, rdata->subreq.len); + __func__, smb->mid, rdata->subreq.start, rdata->subreq.len); =20 /* * read the rest of READ_RSP header (sans Data array), or whatever we @@ -1205,7 +1205,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid) cifs_dbg(FYI, "%s: server returned error %d\n", __func__, rdata->result); /* normal error on read response */ - return __cifs_readv_discard(server, mid, false); + return __cifs_readv_discard(server, smb, false); } =20 /* Is there enough to get to the rest of the READ_RSP header? */ @@ -1215,7 +1215,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid) server->vals->read_rsp_size); rdata->result =3D smb_EIO2(smb_eio_trace_read_rsp_short, server->total_read, server->vals->read_rsp_size); - return cifs_readv_discard(server, mid); + return cifs_readv_discard(server, smb); } =20 data_offset =3D server->ops->read_data_offset(buf); @@ -1234,7 +1234,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid) __func__, data_offset); rdata->result =3D smb_EIO1(smb_eio_trace_read_overlarge, data_offset); - return cifs_readv_discard(server, mid); + return cifs_readv_discard(server, smb); } =20 cifs_dbg(FYI, "%s: total_read=3D%u data_offset=3D%u\n", @@ -1262,7 +1262,7 @@ cifs_readv_receive(struct TCP_Server_Info *server, st= ruct mid_q_entry *mid) /* data_len is corrupt -- discard frame */ rdata->result =3D smb_EIO2(smb_eio_trace_read_rsp_malformed, end_off, buflen); - return cifs_readv_discard(server, mid); + return cifs_readv_discard(server, smb); } } =20 @@ -1289,10 +1289,10 @@ cifs_readv_receive(struct TCP_Server_Info *server, = struct mid_q_entry *mid) =20 /* discard anything left over */ if (server->total_read < buflen) - return cifs_readv_discard(server, mid); + return cifs_readv_discard(server, smb); =20 - dequeue_mid(server, mid, false); - mid->resp_buf =3D server->smallbuf; + dequeue_mid(server, smb, false); + smb->resp_buf =3D server->smallbuf; server->smallbuf =3D NULL; return length; } From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 5EB1D3AA4EF for ; Tue, 19 May 2026 10:22:48 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186169; cv=none; b=mM41vbzkQVJybzKgE0j2Nx6shwlnAAh+B2yiAfCAXlT62p+RD3Xk0bqn41xxVfZ0wmTAj3biTsseUzyp5JU5y34CG5vPGD7cZv2So9gXrI4INOVAAdJ+iAliy6wGX9+40HA/N0IZ0SpV0jIswbKauQiQD2nhDOWCBxj4fBPCKjc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186169; c=relaxed/simple; bh=6843LSSseiWRO/YvWwqFfuLv8LRbTBdUlgClovCTzwk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SxanPV3jkHLOjSS0E4aaWqWLaxsVrghSxkKVkV3bvW+TegS+gPeS1r/+BccEyiUn8D/PeKXIwHUIAJ7wsRW9tMkToPxUl9NNq1eNEO0btLKaBGIh8XuXySMmzw3VaHAABoytpTtMfe7Y2ftQbyZKzTATBsUGJPwEc+MfKvdiQFI= 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=IHD1/1Bd; arc=none smtp.client-ip=170.10.133.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="IHD1/1Bd" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186167; 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=sk/NPIZ4bepOiAna+HLp59qWh7ey7IGZ52zhJvITmmk=; b=IHD1/1BdhTFm9fyq1HQy3a6I+9+kQh7LXIZgd0uRL3rrvch8l7MQ47HGH+oaOTjDArZqyB 82E6y3+hNB+ck0NCfU3Jbwk/uAmMTO0LehfVlPusx3/VHfhvvpqfZxZeWCAF5XB32DrBsp WpsYZFEjPaykedOW4rILiZ0Op32pcs4= Received: from mx-prod-mc-06.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-548-8ZLrb77vOyydf7DKO_Y6gg-1; Tue, 19 May 2026 06:22:42 -0400 X-MC-Unique: 8ZLrb77vOyydf7DKO_Y6gg-1 X-Mimecast-MFC-AGG-ID: 8ZLrb77vOyydf7DKO_Y6gg_1779186160 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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A3B7518005B8; Tue, 19 May 2026 10:22:40 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 71D9D1956053; Tue, 19 May 2026 10:22:37 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 07/36] cifs: Add "Has dynamic part" flag form SMB2/3 StructureSize LSB Date: Tue, 19 May 2026 11:21:25 +0100 Message-ID: <20260519102158.592165-8-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" The LSB in the StructureSize that follows the smb2/3_hdr struct isn't really part of the length, but is rather a flag indicating that the operation structure is dynamic in size, so define a symbol for it. Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: Shyam Prasad N cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org --- fs/smb/common/smb2pdu.h | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index aeb0a245c532..dc5ec2643669 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -185,6 +185,7 @@ struct smb3_hdr_req { struct smb2_pdu { struct smb2_hdr hdr; __le16 StructureSize2; /* size of wct area (varies, request specific) */ +#define SMB2_STRUCT_HAS_DYNAMIC_PART 0x01 } __packed; =20 #define SMB2_ERROR_STRUCTURE_SIZE2 9 From nobody Mon May 25 02:42:24 2026 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 AF63B3E169E for ; Tue, 19 May 2026 10:22:50 +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=1779186172; cv=none; b=Xh/4S0vEsstyjYdzDHtQlap0Wu8lWtffKFdyiN8Y7BrSoSd66Bim1PDasQGxg60JSJktKW2SaV7l+Qj7otNk1njM7YPO3sHIi3Lg901Jo58P0nAARtLfj/2e6Dsd6hETtWTpcR38A9GnFr+zzsGMQoWTAIhDHwKumGb8eEBkIt0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186172; c=relaxed/simple; bh=UhHkba6ecwxOKwjX0G3243fhk9qA4cbp+p5Gvm4VN4w=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nAedILLrqPRWd56hkuk43eHOiFvgpMG1eO6k8o3CPLdxM2jyVsor4mSvB/PjUEQxf/JQHCc6zmngH23vutU+inGlxiMOhQm3q+YVNEn26sK/stZMM5eOc20pSn+Zy0T7S8CYv5KYraMgF4tmSXCgEnRzfqM/6+PR3rwYLfulL9Q= 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=W/8OH+dH; 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="W/8OH+dH" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186169; 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=SlQl2PQTwkn/zTd/X22L2cgRiCIJcRnEi+XfHWK1JC8=; b=W/8OH+dHhCxC2KshOHNWSBHmQI4o3U/sh95FrejQ7aO99TJrQoe+cOIbUGU2fUJDXOAhs2 nvFvodYyzS51k1ZRRGLtRXYNyOtNvuMX6+d511nZwWkXCJPZgw9M563DXi+ejiAbsG6b/A hl9WP5Ta5vtJbeZQrq3DyGcXTJJjvbk= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-93-iHxlfIn_MeeJGF2jiqmVmw-1; Tue, 19 May 2026 06:22:46 -0400 X-MC-Unique: iHxlfIn_MeeJGF2jiqmVmw-1 X-Mimecast-MFC-AGG-ID: iHxlfIn_MeeJGF2jiqmVmw_1779186165 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 135AB195605C; Tue, 19 May 2026 10:22:45 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 55F7E19560A2; Tue, 19 May 2026 10:22:42 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org Subject: [RFC PATCH 08/36] cifs: Add an enum to hold a trace value for the command/subcommand Date: Tue, 19 May 2026 11:21:26 +0100 Message-ID: <20260519102158.592165-9-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.12 Content-Type: text/plain; charset="utf-8" --- fs/smb/client/trace.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index b99ec5a417fa..ede61d8a192c 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -20,6 +20,9 @@ /* * Specify enums for tracing information. */ +#define smb_command_traces \ + E_(smb_unknown_command, "unknown-command") + #define smb_eio_traces \ EM(smb_eio_trace_compress_copy, "compress_copy") \ EM(smb_eio_trace_copychunk_inv_rsp, "copychunk_inv_rsp") \ @@ -211,6 +214,7 @@ #define EM(a, b) a, #define E_(a, b) a =20 +enum smb_command_trace { smb_command_traces } __mode(byte); enum smb_eio_trace { smb_eio_traces } __mode(byte); enum smb3_rw_credits_trace { smb3_rw_credits_traces } __mode(byte); enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); @@ -225,6 +229,7 @@ enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mod= e(byte); #define EM(a, b) TRACE_DEFINE_ENUM(a); #define E_(a, b) TRACE_DEFINE_ENUM(a); =20 +smb_command_traces; smb_eio_traces; smb3_rw_credits_traces; smb3_tcon_ref_traces; From nobody Mon May 25 02:42:24 2026 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 EDABF3A9D9F for ; Tue, 19 May 2026 10:22:55 +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=1779186178; cv=none; b=a/sKfgGVS/RcQV3SGta3GK+MRJ9rEO4fCrJKIwJvIXwmertBZKDm1WjQMJzHniUABtmcITH9AuVq+hZrIWrLsn0Kt7kEJG3MnjUiTOReA+I9e8aiY1ciDMHyT2AksL1ghOnt5HNOyHw8w7haZfDfGHQzA0ovhNnP1/Cn9k9s1Sk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186178; c=relaxed/simple; bh=IFI/NWmdMMC+KvK7r97V6VdqnXUhZU1xg+qh2gUWSJs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=s8CmSur9PsrpNQgjptLh+Hsig4I7Bds4oZ/k7VDntl3A61gDgyn4PMQJWH5Q/OcT4E/R/1ZXxZffFR6fw5s/8bc0QS93OyBe5Xy4ZHBTbTci6Jhrwpq5D905uRm05LkfKZK64cnyjrI8WEQMVsVNaPp+WNAl2m4OkJwIoteJck0= 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=YeiQsz9p; 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="YeiQsz9p" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186175; 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=1FKNP+/i6bUXYcLLW3klf3x7a+ni5hzdhBlCQcUPUeQ=; b=YeiQsz9p1zwKVsZZwLq2F3dhDtpgpVhEtsKA01RyZvW603wyRlOZcRLrzyiRFgzhGUuY7L 9maPDXXeqfMZW80r9vUhL2gF1IuHWVScPrYH9KD3oHfz+fonjgXvrurjzULzKDMcuQYkSg k55YA63VYBv3w6sohqrZ6EDtuiUYvzA= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-371-jmtsLVISM0CA9OLkZ2---g-1; Tue, 19 May 2026 06:22:51 -0400 X-MC-Unique: jmtsLVISM0CA9OLkZ2---g-1 X-Mimecast-MFC-AGG-ID: jmtsLVISM0CA9OLkZ2---g_1779186170 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 16518195609E; Tue, 19 May 2026 10:22:50 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BA41E180034E; Tue, 19 May 2026 10:22:46 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 09/36] cifs: Institute message managing struct Date: Tue, 19 May 2026 11:21:27 +0100 Message-ID: <20260519102158.592165-10-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Turn the smb_message struct into a message handling struct to aid in building an SMB message, queuing them and holding the resources and buffers. It has absorbed the mid_q_struct and now other fields are added. The idea is that the smb_message struct will be allocated and filled in much higher up (typically in the PDU encoding code) and passed down to the transport. In particular, the following fields: (*) ->next: This is used to link together messages into compounds and then walk through the message list. (*) ->credits: The credit requirements for the message. (*) ->request: Pointer to the smb_hdr struct for the request. (*) ->command_trace: An ID of the command type for use in tracing. (*) ->total_len: The total length of the request message, not including rfc1002 or transform headers. (*) ->response: Pointer to the smb_hdr struct for the response. (*) ->rqst, ->resp_buf_type, ->resp_iov: The old request info stuff. Functions are provided to get and put refs upon the struct and also to drop all the refs on a compound string of structs. 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/cifsglob.h | 104 ++++++++++++++++++++++++---------- fs/smb/client/cifsproto.h | 11 ++-- fs/smb/client/connect.c | 6 +- fs/smb/client/smb1ops.c | 2 +- fs/smb/client/smb1transport.c | 2 +- fs/smb/client/smb2ops.c | 2 +- fs/smb/client/smb2transport.c | 4 +- fs/smb/client/transport.c | 42 +++++++++++++- 8 files changed, 127 insertions(+), 46 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index a5e12a2eefdd..0f876feb0dbf 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1701,40 +1701,82 @@ typedef void (*mid_callback_t)(struct TCP_Server_In= fo *srv, struct smb_message * typedef int (*mid_handle_t)(struct TCP_Server_Info *server, struct smb_message *smb); =20 -/* one of these for every pending CIFS request to the server */ +/* + * Definition of an SMB request message to be transmitted. These may be + * chained together and will automatically be turned into compound message= s if + * they are. + * + * +-----------------------+ + * | NetBIOS/padding | + * +-----------------------+ <--- smb->request + pre_offset + * | (Transform header) | + * +-----------------------+ <--- smb->request + * | SMB2 Header | } } + * +-----------------------+ } header_size } + * | Req/Rsp struct | } } + * +-----------------------+ <--- smb->request + ext_offset } protocol_size + * | | } + * | Extra protocol data | } + * | | } + * +-----------------------+ <--- smb->request + smb->data_offset + * | | + * | Data Payload | data_size + * | | + * +-----------------------+ + * + * + * If the data is to be RDMA'd, it will be kept separate from the protocol. + */ struct smb_message { - struct list_head qhead; /* mids waiting on reply from this server */ - refcount_t refcount; - __u64 mid; /* multiplex id */ - __u16 credits; /* number of credits consumed by this mid */ - __u16 credits_received; /* number of credits from the response */ - __u32 pid; /* process id */ - __u32 sequence_number; /* for CIFS signing */ - unsigned int sr_flags; /* Flags passed to send_recv() */ - unsigned long when_alloc; /* when mid was created */ + struct smb_message *next; /* Next message in compound */ + struct cifs_credits credits; /* Credit requirements for this message */ + void *request; /* Pointer to request message body */ + refcount_t ref; + bool sensitive; /* Request contains sensitive data */ + bool cancelled; /* T if cancelled */ + unsigned int sr_flags; /* Flags passed to send_recv() */ + + /* Queue state */ + struct list_head qhead; /* mids waiting on reply from this server */ + __u64 mid; /* multiplex id */ + __u16 credits_consumed; /* number of credits consumed by this op */ + __u16 credits_received; /* number of credits from the response */ + __u32 pid; /* process id */ + __u32 sequence_number; /* for CIFS signing */ + unsigned long when_alloc; /* when mid was created */ #ifdef CONFIG_CIFS_STATS2 - unsigned long when_sent; /* time when smb send finished */ - unsigned long when_received; /* when demux complete (taken off wire) */ + unsigned long when_sent; /* time when smb send finished */ + unsigned long when_received; /* when demux complete (taken off wire) */ #endif - mid_receive_t receive; /* call receive callback */ - mid_callback_t callback; /* call completion callback */ - mid_handle_t handle; /* call handle mid callback */ - void *callback_data; /* general purpose pointer for callback */ - struct task_struct *creator; - void *resp_buf; /* pointer to received SMB header */ - unsigned int resp_buf_size; - u32 response_pdu_len; - int mid_state; /* wish this were enum but can not pass to wait_event */ - int mid_rc; /* rc for MID_RC */ - __le16 command; /* smb command code */ - unsigned int optype; /* operation type */ - spinlock_t mid_lock; - bool wait_cancelled:1; /* Cancelled while waiting for response */ - bool deleted_from_q:1; /* Whether Mid has been dequeued frem pending_mid= _q */ - bool large_buf:1; /* if valid response, is pointer to large buf */ - bool multiRsp:1; /* multiple trans2 responses for one request */ - bool multiEnd:1; /* both received */ - bool decrypted:1; /* decrypted entry */ + mid_receive_t receive; /* call receive callback */ + mid_callback_t callback; /* call completion callback */ + mid_handle_t handle; /* call handle mid callback */ + void *callback_data; /* general purpose pointer for callback */ + struct task_struct *creator; + void *resp_buf; /* pointer to received SMB header */ + unsigned int resp_buf_size; + int mid_state; /* wish this were enum but can not pass to wait_event */ + int mid_rc; /* rc for MID_RC */ + unsigned int optype; /* operation type */ + spinlock_t mid_lock; + bool wait_cancelled:1; /* Cancelled while waiting for response */ + bool deleted_from_q:1; /* Mid has been dequeued from pending_mid_q */ + bool large_buf:1; /* if valid response, is pointer to large buf */ + bool multiRsp:1; /* multiple trans2 responses for one request */ + bool multiEnd:1; /* both received */ + bool decrypted:1; /* decrypted entry */ + + /* Request details */ + u8 command_trace; /* enum smb_command_trace - Command trace ID */ + __le16 command; /* smb command code */ + s16 pre_offset; /* Offset of pre-headers from ->body (negative) */ + unsigned int total_len; /* Total length of from hdr_offset onwards */ + /* Response */ + u32 response_pdu_len; /* Size of response PDU */ + /* Compat with old code */ + struct smb_rqst rqst; + int *resp_buf_type; + struct kvec *resp_iov; }; =20 struct close_cancelled_open { diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index f88ae04af85d..9c60fffcf53d 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -81,6 +81,10 @@ char *cifs_build_path_to_root(struct smb3_fs_context *ct= x, struct cifs_tcon *tcon, int add_treename); char *cifs_build_devname(char *nodename, const char *prepath); void delete_mid(struct TCP_Server_Info *server, struct smb_message *smb); +struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gf= p); +void smb_get_message(struct smb_message *smb); +void smb_put_message(struct smb_message *smb); +void smb_put_messages(struct smb_message *smb); void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb= ); void cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb); @@ -470,14 +474,9 @@ static inline bool dfs_src_pathname_equal(const char *= s1, const char *s2) return true; } =20 -static inline void smb_get_mid(struct smb_message *smb) -{ - refcount_inc(&smb->refcount); -} - static inline void release_mid(struct TCP_Server_Info *server, struct smb_= message *smb) { - if (refcount_dec_and_test(&smb->refcount)) + if (refcount_dec_and_test(&smb->ref)) __release_mid(server, smb); } =20 diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 97de3ae68d7a..3d7e279ba149 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -327,7 +327,7 @@ cifs_abort_connection(struct TCP_Server_Info *server) cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { - smb_get_mid(smb); + smb_get_message(smb); if (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) smb->mid_state =3D MID_RETRY_NEEDED; list_move(&smb->qhead, &retry_list); @@ -884,7 +884,7 @@ is_smb_response(struct TCP_Server_Info *server, unsigne= d char type) */ spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { - smb_get_mid(smb); + smb_get_message(smb); list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; } @@ -1103,7 +1103,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { smb =3D list_entry(tmp, struct smb_message, qhead); cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid); - smb_get_mid(smb); + smb_get_message(smb); smb->mid_state =3D MID_SHUTDOWN; list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index c1c16f6346fb..df74975374ee 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -254,7 +254,7 @@ cifs_find_mid(struct TCP_Server_Info *server, char *buf= fer) if (compare_mid(smb->mid, buf) && smb->mid_state =3D=3D MID_REQUEST_SUBMITTED && le16_to_cpu(smb->command) =3D=3D buf->Command) { - smb_get_mid(smb); + smb_get_message(smb); spin_unlock(&server->mid_queue_lock); return smb; } diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index c2d211a62577..f38fe262c7ea 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -45,7 +45,7 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Se= rver_Info *server) =20 smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); memset(smb, 0, sizeof(struct smb_message)); - refcount_set(&smb->refcount, 1); + refcount_set(&smb->ref, 1); spin_lock_init(&smb->mid_lock); smb->mid =3D get_mid(smb_buffer); smb->pid =3D current->pid; diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 236eb560bdff..f39074d0e4a0 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -416,7 +416,7 @@ __smb2_find_mid(struct TCP_Server_Info *server, char *b= uf, bool dequeue) if ((smb->mid =3D=3D wire_mid) && (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) && (smb->command =3D=3D shdr->Command)) { - smb_get_mid(smb); + smb_get_message(smb); if (dequeue) { list_del_init(&smb->qhead); smb->deleted_from_q =3D true; diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index a28b66ead690..f5b676802ce7 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -619,10 +619,10 @@ smb2_mid_entry_alloc(const struct smb2_hdr *shdr, =20 smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); memset(smb, 0, sizeof(*smb)); - refcount_set(&smb->refcount, 1); + refcount_set(&smb->ref, 1); spin_lock_init(&smb->mid_lock); smb->mid =3D le64_to_cpu(shdr->MessageId); - smb->credits =3D credits > 0 ? credits : 1; + smb->credits_consumed =3D credits > 0 ? credits : 1; smb->pid =3D current->pid; smb->command =3D shdr->Command; /* Always LE */ smb->when_alloc =3D jiffies; diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 622f63779de0..3ea52cf4a64b 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -30,6 +30,46 @@ #include "smbdirect.h" #include "compress.h" =20 +struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gf= p) +{ + struct smb_message *smb; + + smb =3D mempool_alloc(&smb_message_pool, gfp); + if (smb) { + memset(smb, 0, sizeof(*smb)); + refcount_set(&smb->ref, 1); + smb->command_trace =3D cmd; + } + return smb; +} + +void smb_get_message(struct smb_message *smb) +{ + refcount_inc(&smb->ref); +} + +/* + * Drop a ref on a message. This does not touch the chained messages. + */ +void smb_put_message(struct smb_message *smb) +{ + if (refcount_dec_and_test(&smb->ref)) + mempool_free(smb, &smb_message_pool); +} + +/* + * Dispose of a chain of compound messages. + */ +void smb_put_messages(struct smb_message *smb) +{ + struct smb_message *next; + + for (; smb; smb =3D next) { + next =3D smb->next; + smb_put_message(smb); + } +} + void cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb) { @@ -722,7 +762,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct = smb_rqst *rqst, rc =3D smb_send_rqst(server, 1, rqst, flags); =20 if (rc < 0) { - revert_current_mid(server, smb->credits); + revert_current_mid(server, smb->credits_consumed); server->sequence_number -=3D 2; delete_mid(server, smb); } From nobody Mon May 25 02:42:24 2026 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 901D93E169E for ; Tue, 19 May 2026 10:23:01 +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=1779186183; cv=none; b=UCj32Ht9rmKAk7lbwE74YtXg0Zp5AZh3UG+Bu61rEr7T/stcYLOKnlofPNa6ONGxZYs1V4CiBUmM8azB8CKUcoL0ksq2aU514UPYuA2lZSkmEYbqkfWLDAOZSH+Ko5+Zl3si3qVmzpJ6olvxbaSbg8wAdTdn/lrIUGlC7wnkXYg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186183; c=relaxed/simple; bh=dOt7tvoRaTPjVMCowEPEy627fiSaBdDeltsTvaQzODU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Q3/xpSQKZklL58Bap88Gdrvb94ELsqt/JP0I/IjlWR0U3Vb4kChwQWafnu+HbiGBL8WQiuoOaJkngCdM1yTAbKZqXK7lIvhJAQsTT5l6t0jPIIJ02KujZZu3uMGOZ0J1/23sRDnwzNw2B0VsW8BhY70WHS7kwLFttz0P1ORLeD8= 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=TzwS3k8u; 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="TzwS3k8u" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186180; 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=FHv0wA8qYdfuCzR7/8BZb1BosqZySnrazKlwIjeZxDg=; b=TzwS3k8uATN1+/eWO8oRGH+Ug07u1ziXIvxQn7ug9foo6tG8Eu6iDYh4DYYF/XUAKhQQNY 8mf7vT/SRsymYI0yugpO4v+PeLsZvE4/7i/EnZF/BdRdB8j+dGgS6DXLibm2AO+oPUAYZC wgxKU7tQmgVud6bx6fVRE0sQCIf+mc0= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-543-Lt3Qo-O-Odi2YXiWNN1wKA-1; Tue, 19 May 2026 06:22:56 -0400 X-MC-Unique: Lt3Qo-O-Odi2YXiWNN1wKA-1 X-Mimecast-MFC-AGG-ID: Lt3Qo-O-Odi2YXiWNN1wKA_1779186175 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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id EA465195605C; Tue, 19 May 2026 10:22:54 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C01B61956053; Tue, 19 May 2026 10:22:51 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 10/36] cifs: Split crypt_message() into encrypt and decrypt variants Date: Tue, 19 May 2026 11:21:28 +0100 Message-ID: <20260519102158.592165-11-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" Split crypt_message() into encrypt and decrypt variants so that the encrypt variant can be substantially changed. 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/smb2ops.c | 103 +++++++++++++++++++++++++++++++++------- 1 file changed, 87 insertions(+), 16 deletions(-) diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index f39074d0e4a0..10bb0fe6b77b 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4458,16 +4458,17 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __= u64 ses_id, int enc, u8 *key) =20 return -EAGAIN; } + /* - * Encrypt or decrypt @rqst message. @rqst[0] has the following format: + * Encrypt @rqst message. @rqst[0] has the following format: * iov[0] - transform header (associate data), * iov[1-N] - SMB2 header and pages - data to encrypt. * On success return encrypted data in iov[1-N] and pages, leave iov[0] * untouched. */ static int -crypt_message(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst, int enc, struct crypto_aead *tfm) +encrypt_message(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, struct crypto_aead *tfm) { struct smb2_transform_hdr *tr_hdr =3D (struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; @@ -4482,10 +4483,10 @@ crypt_message(struct TCP_Server_Info *server, int n= um_rqst, unsigned int crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); void *creq; =20 - rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), enc, key); + rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 1, key); if (rc) { - cifs_server_dbg(FYI, "%s: Could not get %scryption key. sid: 0x%llx\n", = __func__, - enc ? "en" : "de", le64_to_cpu(tr_hdr->SessionId)); + cifs_server_dbg(FYI, "%s: Could not get encryption key. sid: 0x%llx\n", + __func__, le64_to_cpu(tr_hdr->SessionId)); return rc; } =20 @@ -4510,11 +4511,6 @@ crypt_message(struct TCP_Server_Info *server, int nu= m_rqst, if (IS_ERR(creq)) return PTR_ERR(creq); =20 - if (!enc) { - memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); - crypt_len +=3D SMB2_SIGNATURE_SIZE; - } - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); @@ -4530,16 +4526,91 @@ crypt_message(struct TCP_Server_Info *server, int n= um_rqst, aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, crypto_req_done, &wait); =20 - rc =3D crypto_wait_req(enc ? crypto_aead_encrypt(req) - : crypto_aead_decrypt(req), &wait); + rc =3D crypto_wait_req(crypto_aead_encrypt(req), &wait); =20 - if (!rc && enc) + if (!rc) memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); =20 kfree_sensitive(creq); return rc; } =20 +/* + * Decrypt @rqst message. @rqst[0] has the following format: + * iov[0] - transform header (associate data), + * iov[1-N] - SMB2 header and pages - data to decrypt. + * On success return encrypted data in iov[1-N] and pages, leave iov[0] + * untouched. + */ +static int +decrypt_message(struct TCP_Server_Info *server, int num_rqst, + struct smb_rqst *rqst, struct crypto_aead *tfm) +{ + struct smb2_transform_hdr *tr_hdr =3D + (struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; + unsigned int assoc_data_len =3D sizeof(struct smb2_transform_hdr) - 20; + int rc =3D 0; + struct scatterlist *sg; + u8 sign[SMB2_SIGNATURE_SIZE] =3D {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; + struct aead_request *req; + u8 *iv; + DECLARE_CRYPTO_WAIT(wait); + unsigned int crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); + void *creq; + + rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 0, key); + if (rc) { + cifs_server_dbg(FYI, "%s: Could not get decryption key. sid: 0x%llx\n", + __func__, le64_to_cpu(tr_hdr->SessionId)); + return rc; + } + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_CCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); + else + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); + + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); + return rc; + } + + rc =3D crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); + return rc; + } + + creq =3D smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg); + if (IS_ERR(creq)) + return PTR_ERR(creq); + + memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); + crypt_len +=3D SMB2_SIGNATURE_SIZE; + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); + else { + iv[0] =3D 3; + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); + } + + aead_request_set_tfm(req, tfm); + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &wait); + + rc =3D crypto_wait_req(crypto_aead_decrypt(req), &wait); + + kfree_sensitive(creq); + return rc; +} + /* * Copy data from an iterator to the pages in a bvec queue buffer. */ @@ -4618,7 +4689,7 @@ smb3_init_transform_rq(struct TCP_Server_Info *server= , int num_rqst, /* fill the 1st iov with a transform header */ fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type); =20 - rc =3D crypt_message(server, num_rqst, new_rq, 1, server->secmech.enc); + rc =3D encrypt_message(server, num_rqst, new_rq, server->secmech.enc); cifs_dbg(FYI, "Encrypt message returned %d\n", rc); if (rc) goto err_free; @@ -4680,7 +4751,7 @@ decrypt_raw_data(struct TCP_Server_Info *server, char= *buf, tfm =3D server->secmech.dec; } =20 - rc =3D crypt_message(server, 1, &rqst, 0, tfm); + rc =3D decrypt_message(server, 1, &rqst, tfm); cifs_dbg(FYI, "Decrypt message returned %d\n", rc); =20 if (is_offloaded) From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 079C04B8DC2 for ; Tue, 19 May 2026 10:23:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186189; cv=none; b=s5hd8Ir8WybUogVootCkzAtjgZLv7cK2KbsM+IKP/BUaHDSJETVPFtO1knG8VXABXfD+jabV5ITGUGG6j5CcGnsw+VNw9xZecA+BQfFlPUWGPK+zYzsyZ9Zc1LwJoz2R0jyJ/wDCCDbf6OvMT0AlrUI5h54MDD8c8oR4x3q7Suc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186189; c=relaxed/simple; bh=9YxXtvgJSvdCslocEAs4652Pqh9Vf6UnqI00hCiqxxA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=U2Rjyl2yB1lNcTWRlnVupuz2XpijSYNluJTessXgQnZptahfxh+/pLJjCyCKQQo+Rao2MXrPixXmQTFx7EMrXGP/b3HIvJ94Yw0mVR2Xdc91hvSrherHbnlmyTbZMdotqdpjvxi4fWJfW6ybnpfFitHYtkxD9Li9Oy2yz5hjhoU= 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=agur8R9N; arc=none smtp.client-ip=170.10.133.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="agur8R9N" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186187; 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=/nBDRAQ3XzH+HF+bEEOesEricXOP8KyYW6ngtqFP4G0=; b=agur8R9NHgzuS9hBPmECBvUUEM1PrATr36D7rF3IF0qcZR29OXOOOG1hf9ZnwUMANsODLn GnrOXI2cVwMYW0ArSbfiPyAPKE6DG+HTN/QQ4rB3Zx+5ji9lofxY6lOl4L9XcLO+i0tRv/ qpvEHJ5NdLK5RSEMqWDNFf+s3rXB80I= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-532-HMG1UIXwPSGNWata3TI6dg-1; Tue, 19 May 2026 06:23:01 -0400 X-MC-Unique: HMG1UIXwPSGNWata3TI6dg-1 X-Mimecast-MFC-AGG-ID: HMG1UIXwPSGNWata3TI6dg_1779186180 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C62A8195608E; Tue, 19 May 2026 10:22:59 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 9DFAB18004A3; Tue, 19 May 2026 10:22:56 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 11/36] cifs: Add new AEAD alloc and setup routines that draw from an iterator Date: Tue, 19 May 2026 11:21:29 +0100 Message-ID: <20260519102158.592165-12-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 Content-Type: text/plain; charset="utf-8" Add new AEAD alloc and setup routines that solely use an iterator to supply the buffers rather than disassembling an smb_rqst struct. 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/smb2transport.c | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index f5b676802ce7..9df3a0b530e2 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -812,3 +812,72 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *serv= er) =20 return 0; } + +/* + * Allocate the context info needed for the encryption operation, along wi= th a + * scatterlist to point to the buffer. + */ +static void *smb2_aead_req_alloc_new(struct crypto_aead *tfm, const struct= iov_iter *iter, + u8 **iv, + struct aead_request **req, struct sg_table *sgt, + unsigned int *num_sgs, size_t *sensitive_size) +{ + unsigned int req_size =3D sizeof(**req) + crypto_aead_reqsize(tfm); + unsigned int iv_size =3D crypto_aead_ivsize(tfm); + unsigned int len; + u8 *p; + + *num_sgs =3D iov_iter_npages(iter, INT_MAX); + + len =3D iv_size; + len +=3D crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); + len =3D ALIGN(len, crypto_tfm_ctx_alignment()); + len +=3D req_size; + len =3D ALIGN(len, __alignof__(struct scatterlist)); + len +=3D array_size(*num_sgs + 2, sizeof(struct scatterlist)); + *sensitive_size =3D len; + + p =3D kvzalloc(len, GFP_NOFS); + if (!p) + return ERR_PTR(-ENOMEM); + + *iv =3D (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1); + *req =3D (struct aead_request *)PTR_ALIGN(*iv + iv_size, + crypto_tfm_ctx_alignment()); + sgt->sgl =3D (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size, + __alignof__(struct scatterlist)); + return p; +} + +/* + * Set up for doing a crypto operation, building a scatterlist from the + * supplied iterator. + */ +static void *smb2_get_aead_req_new(struct crypto_aead *tfm, const struct i= ov_iter *iter, + const u8 *sig, u8 **iv, + struct aead_request **req, struct scatterlist **sgl, + size_t *sensitive_size) +{ + struct sg_table sgtable =3D {}; + struct iov_iter tmp =3D *iter; + unsigned int num_sgs; + ssize_t rc; + void *p; + + p =3D smb2_aead_req_alloc_new(tfm, iter, iv, req, &sgtable, + &num_sgs, sensitive_size); + if (IS_ERR(p)) + return ERR_CAST(p); + + sg_init_marker(sgtable.sgl, num_sgs + 2); + + rc =3D extract_iter_to_sg(&tmp, iov_iter_count(iter), &sgtable, num_sgs, = 0); + sgtable.orig_nents =3D sgtable.nents + 1; + if (rc < 0) + return ERR_PTR(rc); + + cifs_sg_set_buf(&sgtable, sig, SMB2_SIGNATURE_SIZE); + sg_mark_end(&sgtable.sgl[sgtable.nents - 1]); + *sgl =3D sgtable.sgl; + return p; +} From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 863AD4A33E7 for ; Tue, 19 May 2026 10:23:11 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186200; cv=none; b=eloSNSiFhBL66e2w9ipaQFgVQtvDK/uDWizFnMJjbUwduK0Qz6QeaJosjJZDjoIhbnzzgdelxxRZ3NLNfkIvm1vjsDsPQnMOv/aEXwgk5S4XLTdh5zkl7PnSo8pXs9FfO6kjJ/Th1s6H5v9BBxeP5gaW7nbUE3OII4f14ys6ZFc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186200; c=relaxed/simple; bh=WpMPvBXRpRlyaFOIn7pGROjWpXLTkwH63VnXk7H4SmY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q1w2YCZHv0vy7137Vm0qejkwofhZjo6h9qdBGRfgzMdK6wnPEAozV7t/DqE5UXyEj+Tc3zYvp2t2zhq/yi4NM2yapMh+HGVjnEFhlNQu6Vt3CZL2vQLASuJNmjj+VwsOuQ2ioMrx7X4A0jhuWI/FhgAhj3Gp1hi1sVde/r1c5is= 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=iUmkz2Ye; arc=none smtp.client-ip=170.10.133.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="iUmkz2Ye" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186190; 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=1QLUiNP479wpDDQvLt9kbWq0kp4zn1TXVy2Kv7wqRYg=; b=iUmkz2YeVPumzRY1DYW0ByIzMcvLl4xdqsfaH17lZD7oQD+rLg/ukgXCnCnqeEoxA1tUNV RoaUccWCwKCfobdHpPe8m8QK7LDKMu840Yz7HrwQCb0t7Bn//15vh7wWWeSaDOt1uuE+yG Fc0dQjBaiozC+KES0bcoGei6+K0Srl0= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-682-6tebxjjxMWSTDV6lh2lAbg-1; Tue, 19 May 2026 06:23:07 -0400 X-MC-Unique: 6tebxjjxMWSTDV6lh2lAbg-1 X-Mimecast-MFC-AGG-ID: 6tebxjjxMWSTDV6lh2lAbg_1779186185 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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6DA2019560A2; Tue, 19 May 2026 10:23:05 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6A9851955D84; Tue, 19 May 2026 10:23:01 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 12/36] cifs: [WIP] Rewrite base Rx to put data off the socket into a bvecq Date: Tue, 19 May 2026 11:21:30 +0100 Message-ID: <20260519102158.592165-13-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" [!] Note: This patch is a WIP and doesn't support RDMA yet Rewrite base Rx to splice incoming data buffers directly the socket into a bvec-queue based receive queue and then use iov_iter functions to take it apart. It can also be decrypted within those buffers. Non-blocking splice is used to get as many data segments as are available and can be spliced into the empty slots of the bvecq passed to TCP. Since the splice doesn't wait, ->sk_data_ready() is used to sense new PDUs becoming available. For the case of RDMA, the smbdirect reassembly should just add buffers to the receive queue. We can then offer the iterator to the individual PDU decoders and they can use copy_from_iter() to extract data. Special handling is provided for any smb_message that wants it (e.g. unencrypted READs), such that the headers are copied into heap objects and then the rest is copied directly from the receive queue into the target buffer. This is done incrementally so that reads aren't held up whilst until all the data is received; further, spent receive buffers are discarded as soon as possible to prevent holding on to DMA buffer space. 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/cifs_debug.c | 38 +- fs/smb/client/cifs_debug.h | 3 +- fs/smb/client/cifsglob.h | 106 ++-- fs/smb/client/cifsproto.h | 21 +- fs/smb/client/cifssmb.c | 35 +- fs/smb/client/connect.c | 616 ++++++++----------- fs/smb/client/smb1debug.c | 55 +- fs/smb/client/smb1encrypt.c | 111 ++++ fs/smb/client/smb1maperror.c | 7 +- fs/smb/client/smb1misc.c | 20 +- fs/smb/client/smb1ops.c | 44 +- fs/smb/client/smb1pdu.h | 62 +- fs/smb/client/smb1proto.h | 43 +- fs/smb/client/smb1transport.c | 1042 ++++++++++++++++++++++++++------- fs/smb/client/smb2inode.c | 2 +- fs/smb/client/smb2maperror.c | 3 +- fs/smb/client/smb2misc.c | 358 +++++------ fs/smb/client/smb2ops.c | 908 ++++------------------------ fs/smb/client/smb2pdu.c | 67 ++- fs/smb/client/smb2proto.h | 25 +- fs/smb/client/smb2transport.c | 633 +++++++++++++++++++- fs/smb/client/trace.h | 63 ++ fs/smb/client/transport.c | 221 +------ fs/smb/common/smb2pdu.h | 30 + 24 files changed, 2473 insertions(+), 2040 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 2d0d26ee57ce..47dadab67440 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -28,49 +28,13 @@ #include "cached_dir.h" =20 void -cifs_dump_mem(char *label, void *data, int length) +cifs_dump_mem(const char *label, void *data, int length) { pr_debug("%s: dump of %d bytes of data at 0x%p\n", label, length, data); print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4, data, length, true); } =20 -void cifs_dump_mids(struct TCP_Server_Info *server) -{ -#ifdef CONFIG_CIFS_DEBUG2 - struct smb_message *smb; - - if (server =3D=3D NULL) - return; - - cifs_dbg(VFS, "Dump pending requests:\n"); - spin_lock(&server->mid_queue_lock); - list_for_each_entry(smb, &server->pending_mid_q, qhead) { - cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", - smb->mid_state, - le16_to_cpu(smb->command), - smb->pid, - smb->callback_data, - smb->mid); -#ifdef CONFIG_CIFS_STATS2 - cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", - smb->large_buf, - smb->resp_buf, - smb->when_received, - jiffies); -#endif /* STATS2 */ - cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n", - smb->multiRsp, smb->multiEnd); - if (smb->resp_buf) { - server->ops->dump_detail(smb->resp_buf, - smb->response_pdu_len, server); - cifs_dump_mem("existing buf: ", smb->resp_buf, 62); - } - } - spin_unlock(&server->mid_queue_lock); -#endif /* CONFIG_CIFS_DEBUG2 */ -} - #ifdef CONFIG_PROC_FS static void cifs_debug_tcon(struct seq_file *m, struct cifs_tcon *tcon) { diff --git a/fs/smb/client/cifs_debug.h b/fs/smb/client/cifs_debug.h index 00650929a133..fbc3ab351e5c 100644 --- a/fs/smb/client/cifs_debug.h +++ b/fs/smb/client/cifs_debug.h @@ -14,8 +14,7 @@ =20 #define pr_fmt(fmt) "CIFS: " fmt =20 -void cifs_dump_mem(char *label, void *data, int length); -void cifs_dump_mids(struct TCP_Server_Info *server); +void cifs_dump_mem(const char *label, void *data, int length); extern bool traceSMB; /* flag which enables the function below */ void dump_smb(void *buf, int smb_buf_length); #define CIFS_INFO 0x01 diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 0f876feb0dbf..7187e304c42e 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -35,6 +35,9 @@ #define CIFS_PORT 445 #define RFC1001_PORT 139 =20 +/* Drop the connection to not overload the server */ +#define MAX_STATUS_IO_TIMEOUT 5 + /* * The sizes of various internal tables and strings */ @@ -331,35 +334,16 @@ struct smb_version_operations { __u64 (*get_next_mid)(struct TCP_Server_Info *); void (*revert_current_mid)(struct TCP_Server_Info *server, const unsigned int val); - /* data offset from read response message */ - unsigned int (*read_data_offset)(char *); - /* - * Data length from read response message - * When in_remaining is true, the returned data length is in - * message field DataRemaining for out-of-band data read (e.g through - * Memory Registration RDMA write in SMBD). - * Otherwise, the returned data length is in message field DataLength. - */ - unsigned int (*read_data_length)(char *, bool in_remaining); - /* map smb to linux error */ - int (*map_error)(char *, bool); - /* find mid corresponding to the response message */ - struct smb_message *(*find_mid)(struct TCP_Server_Info *server, char *buf= ); - void (*dump_detail)(void *buf, size_t buf_len, struct TCP_Server_Info *pt= cp_info); + /* Finish receiving a PDU and decrypt and decompress and parse it. */ + int (*receive_pdu)(struct TCP_Server_Info *server, unsigned int len); void (*clear_stats)(struct cifs_tcon *); void (*print_stats)(struct seq_file *m, struct cifs_tcon *); void (*dump_share_caps)(struct seq_file *, struct cifs_tcon *); /* verify the message */ - int (*check_message)(char *buf, unsigned int pdu_len, unsigned int len, - struct TCP_Server_Info *server); - bool (*is_oplock_break)(char *, struct TCP_Server_Info *); int (*handle_cancelled_mid)(struct smb_message *smb, struct TCP_Server_In= fo *server); void (*downgrade_oplock)(struct TCP_Server_Info *server, struct cifsInodeInfo *cinode, __u32 oplock, __u16 epoch, bool *purge_cache); - /* process transaction2 response */ - bool (*check_trans2)(struct smb_message *smb, struct TCP_Server_Info *ser= ver, - char *buf, int malformed); /* check if we need to negotiate */ bool (*need_neg)(struct TCP_Server_Info *); /* negotiate to the server */ @@ -508,10 +492,6 @@ struct smb_version_operations { struct cifs_fid *); /* calculate a size of SMB message */ unsigned int (*calc_smb_size)(void *buf); - /* check for STATUS_PENDING and process the response if yes */ - bool (*is_status_pending)(char *buf, struct TCP_Server_Info *server); - /* check for STATUS_NETWORK_SESSION_EXPIRED */ - bool (*is_session_expired)(char *); /* send oplock break response */ int (*oplock_response)(struct cifs_tcon *tcon, __u64 persistent_fid, __u64 volatile_fid, __u16 net_fid, @@ -593,9 +573,6 @@ struct smb_version_operations { /* init transform (compress/encrypt) request */ int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst, struct smb_rqst *, struct smb_rqst *); - int (*is_transform_hdr)(void *buf); - int (*receive_transform)(struct TCP_Server_Info *, - struct smb_message **smb, char **, int *); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(struct TCP_Server_Info *server, char *buf, @@ -619,10 +596,6 @@ struct smb_version_operations { struct fiemap_extent_info *, u64, u64); /* version specific llseek implementation */ loff_t (*llseek)(struct file *, struct cifs_tcon *, loff_t, int); - /* Check for STATUS_IO_TIMEOUT */ - bool (*is_status_io_timeout)(char *buf); - /* Check for STATUS_NETWORK_NAME_DELETED */ - bool (*is_network_name_deleted)(char *buf, struct TCP_Server_Info *srv); struct reparse_data_buffer * (*get_reparse_point_buffer)(const struct kve= c *rsp_iov, u32 *plen); struct inode * (*create_reparse_inode)(struct cifs_open_info_data *data, @@ -690,6 +663,15 @@ struct TCP_Server_Info { struct socket *ssocket; struct sockaddr_storage dstaddr; struct sockaddr_storage srcaddr; /* locally bind to this IP */ + void (*rx_old_data_ready)(struct sock *sock); + void (*rx_old_error_report)(struct sock *sock); + wait_queue_head_t rx_waitq; /* Wait for data ready */ + struct netfs_rxqueue rx_queue; /* Rx queue grabbed from socket */ + atomic_t num_io_timeout; /* Number of I/O timeout responses received */ + unsigned long flags; +#define SMB_SERVER_NEED_RECONNECT 0 /* Reconnect required */ +#define SMB_SERVER_SESSION_RECONNECT 1 /* Session reconnect required */ +#define SMB_SERVER_DATA_READY 2 /* Data ready notification given */ #ifdef CONFIG_NET_NS struct net *net; #endif @@ -755,7 +737,6 @@ struct TCP_Server_Info { bool sec_kerberos; /* supports plain Kerberos */ bool sec_mskerberos; /* supports legacy MS Kerberos */ bool sec_iakerb; /* supports pass-through auth for Kerberos (krb5 proxy)= */ - bool large_buf; /* is current buffer large? */ /* use SMBD connection instead of socket */ bool rdma; /* point to the SMBD connection if RDMA is used instead of socket */ @@ -763,9 +744,6 @@ struct TCP_Server_Info { struct delayed_work echo; /* echo ping workqueue job */ char *smallbuf; /* pointer to current "small" buffer */ char *bigbuf; /* pointer to current "big" buffer */ - /* Total size of this PDU. Only valid from cifs_demultiplex_thread */ - unsigned int pdu_size; - unsigned int total_read; /* total amount of data read in this pass */ atomic_t in_send; /* requests trying to send */ atomic_t num_waiters; /* blocked waiting to get in sendrecv */ #ifdef CONFIG_CIFS_STATS2 @@ -1669,21 +1647,6 @@ static inline void cifs_stats_bytes_read(struct cifs= _tcon *tcon, } =20 =20 -/* - * This is the prototype for the mid receive function. This function is for - * receiving the rest of the SMB frame, starting with the WordCount (which= is - * just after the MID in struct smb_hdr). Note: - * - * - This will be called by cifsd, with no locks held. - * - The mid will still be on the pending_mid_q. - * - mid->resp_buf will point to the current buffer. - * - * Returns zero on a successful receive, or an error. The receive state in - * the TCP_Server_Info will also be updated. - */ -typedef int (*mid_receive_t)(struct TCP_Server_Info *server, - struct smb_message *msg); - /* * This is the prototype for the mid callback function. This is called onc= e the * mid has been received off of the socket. When creating one, take special @@ -1694,13 +1657,6 @@ typedef int (*mid_receive_t)(struct TCP_Server_Info = *server, */ typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct smb_mes= sage *smb); =20 -/* - * This is the protopyte for mid handle function. This is called once the = mid - * has been recognized after decryption of the message. - */ -typedef int (*mid_handle_t)(struct TCP_Server_Info *server, - struct smb_message *smb); - /* * Definition of an SMB request message to be transmitted. These may be * chained together and will automatically be turned into compound message= s if @@ -1748,13 +1704,9 @@ struct smb_message { unsigned long when_sent; /* time when smb send finished */ unsigned long when_received; /* when demux complete (taken off wire) */ #endif - mid_receive_t receive; /* call receive callback */ mid_callback_t callback; /* call completion callback */ - mid_handle_t handle; /* call handle mid callback */ void *callback_data; /* general purpose pointer for callback */ struct task_struct *creator; - void *resp_buf; /* pointer to received SMB header */ - unsigned int resp_buf_size; int mid_state; /* wish this were enum but can not pass to wait_event */ int mid_rc; /* rc for MID_RC */ unsigned int optype; /* operation type */ @@ -1765,6 +1717,8 @@ struct smb_message { bool multiRsp:1; /* multiple trans2 responses for one request */ bool multiEnd:1; /* both received */ bool decrypted:1; /* decrypted entry */ + bool sig_checked:1; /* T if sig already checked */ + bool copy_to_bufs:1; /* Copy to prepared buffer in response_iter */ =20 /* Request details */ u8 command_trace; /* enum smb_command_trace - Command trace ID */ @@ -1772,11 +1726,17 @@ struct smb_message { s16 pre_offset; /* Offset of pre-headers from ->body (negative) */ unsigned int total_len; /* Total length of from hdr_offset onwards */ /* Response */ - u32 response_pdu_len; /* Size of response PDU */ + //u32 response_pdu_len; /* Size of response PDU */ + void *response; /* Protocol part of response */ + u32 resp_len; /* Size of response */ + u32 resp_data_len; /* Length of response data */ + u32 resp_data_offset; /* Offset of response data (or 0) */ + __le32 status; /* Completion status */ + short error; /* Linux error */ + struct iov_iter response_iter; /* Data part of response */ + struct bvecq *response_data; /* Storage for response data (or NULL) */ /* Compat with old code */ struct smb_rqst rqst; - int *resp_buf_type; - struct kvec *resp_iov; }; =20 struct close_cancelled_open { @@ -2436,4 +2396,20 @@ static inline int cifs_open_create_options(unsigned = int oflags, int opts) =20 #define ALIGN8(x) ALIGN((x), 8) =20 +/* + * Received message handling context. + */ +struct cifs_receive { + void *response; /* Response buffer */ + unsigned char resp_buf_type; /* Type of response buffer (CIFS_*_BUFFER) */ + bool malformed:1; /* Message is malformed */ + short error; /* Error code */ + unsigned int msg_len; /* Size of current (sub-)message */ + unsigned int hdr_len; /* Length of header */ + unsigned int data_offset; /* Offset of data part */ + unsigned int data_len; /* Length of data part */ + unsigned int calc_len; /* Calculated length */ + unsigned int extracted; /* How much of msg_len had been extracted */ +}; + #endif /* _CIFS_GLOB_H */ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 9c60fffcf53d..8dedfd677f8d 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -88,17 +88,14 @@ void smb_put_messages(struct smb_message *smb); void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb= ); void cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb); -int cifs_handle_standard(struct TCP_Server_Info *server, - struct smb_message *smb); char *smb3_fs_context_fullpath(const struct smb3_fs_context *ctx, char dir= sep); int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); -int cifs_discard_remaining_data(struct TCP_Server_Info *server); int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, - mid_receive_t receive, mid_callback_t callback, - mid_handle_t handle, void *cbdata, const int flags, - const struct cifs_credits *exist_credits); + mid_callback_t callback, void *cbdata, const int flags, + const struct cifs_credits *exist_credits, + struct iov_iter *resp_buf); struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses); int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst, @@ -227,12 +224,7 @@ unsigned int setup_special_user_owner_ACE(struct smb_a= ce *pntace); =20 void dequeue_mid(struct TCP_Server_Info *server, struct smb_message *smb, bool malformed); -int cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, - unsigned int to_read); -ssize_t cifs_discard_from_socket(struct TCP_Server_Info *server, - size_t to_read); -int cifs_read_iter_from_socket(struct TCP_Server_Info *server, - struct iov_iter *iter, unsigned int to_read); +bool allocate_buffers(struct TCP_Server_Info *server); int cifs_setup_cifs_sb(struct cifs_sb_info *cifs_sb); void cifs_mount_put_conns(struct cifs_mount_ctx *mnt_ctx); int cifs_mount_get_session(struct cifs_mount_ctx *mnt_ctx); @@ -609,4 +601,9 @@ find_readable_file(struct cifsInodeInfo *cinode, unsign= ed int find_flags) return __find_readable_file(cinode, find_flags, 0); } =20 +int smb_rxqueue_refill(struct TCP_Server_Info *server, struct netfs_rxqueu= e *rxq, + size_t min_size); +int smb_rxqueue_consume(struct TCP_Server_Info *server, struct netfs_rxque= ue *rxq, + size_t amount); + #endif /* _CIFSPROTO_H */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 25f6289ee72f..c537cc3e66c8 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -336,6 +336,8 @@ static int validate_t2(struct smb_t2_rsp *pSMB) { unsigned int total_size; =20 + return 0; /* Checking now done in reception routine. */ + /* check for plausible wct */ if (pSMB->hdr.WordCount < 10) goto vt2_err; @@ -428,7 +430,7 @@ CIFSSMBNegotiate(const unsigned int xid, SMB_NEGOTIATE_RSP *pSMBr; unsigned int in_len; int rc =3D 0; - int bytes_returned; + int bytes_returned =3D 0; int i; u16 count; =20 @@ -768,8 +770,8 @@ CIFSSMBEcho(struct TCP_Server_Info *server) iov[0].iov_len =3D in_len; iov[0].iov_base =3D smb; =20 - rc =3D cifs_call_async(server, &rqst, NULL, cifs_echo_callback, NULL, - server, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL); + rc =3D cifs_call_async(server, &rqst, cifs_echo_callback, server, + CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL, NULL); if (rc) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 @@ -1466,8 +1468,11 @@ cifs_readv_callback(struct TCP_Server_Info *server, = struct smb_message *smb) struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct inode *inode =3D &ictx->inode; - struct smb_rqst rqst =3D { .rq_iov =3D rdata->iov, - .rq_nvec =3D 1}; + struct kvec iov =3D { + .iov_base =3D smb->response, + .iov_len =3D smb->resp_len, + }; + struct smb_rqst rqst =3D { .rq_iov =3D &iov, .rq_nvec =3D 1 }; struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0, @@ -1489,12 +1494,13 @@ cifs_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: /* result already set, check signature */ + rdata->got_bytes =3D smb->resp_data_len; if (server->sign) { int rc =3D 0; =20 - iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); + iov_iter_truncate(&rqst.rq_iter, smb->resp_data_len); rc =3D cifs_verify_signature(&rqst, server, - smb->sequence_number); + smb->sequence_number); if (rc) cifs_dbg(VFS, "SMB signature verification returned error =3D %d\n", rc); @@ -1585,6 +1591,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct smb_rqst rqst =3D { .rq_iov =3D rdata->iov, .rq_nvec =3D 1 }; + struct iov_iter iter; unsigned int in_len; =20 cifs_dbg(FYI, "%s: offset=3D%llu bytes=3D%zu\n", @@ -1636,8 +1643,12 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) tcon->tid, tcon->ses->Suid, rdata->subreq.start, rdata->subreq.len); =20 - rc =3D cifs_call_async(tcon->ses->server, &rqst, cifs_readv_receive, - cifs_readv_callback, NULL, rdata, 0, NULL); + iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, + rdata->subreq.content.bvecq, rdata->subreq.content.slot, + rdata->subreq.content.offset, rdata->subreq.len); + + rc =3D cifs_call_async(tcon->ses->server, &rqst, + cifs_readv_callback, rdata, 0, NULL, &iter); =20 if (rc =3D=3D 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); @@ -1889,7 +1900,7 @@ cifs_writev_callback(struct TCP_Server_Info *server, = struct smb_message *smb) { struct cifs_io_subrequest *wdata =3D smb->callback_data; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); - WRITE_RSP *rsp =3D (WRITE_RSP *)smb->resp_buf; + WRITE_RSP *rsp =3D (WRITE_RSP *)smb->response; struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0, @@ -2030,8 +2041,8 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) iov[0].iov_len +=3D 4; /* pad bigger by four bytes */ } =20 - rc =3D cifs_call_async(tcon->ses->server, &rqst, NULL, - cifs_writev_callback, NULL, wdata, 0, NULL); + rc =3D cifs_call_async(tcon->ses->server, &rqst, + cifs_writev_callback, wdata, 0, NULL, NULL); /* Can't touch wdata if rc =3D=3D 0 */ if (rc =3D=3D 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 3d7e279ba149..4a3ebbd6d71b 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -29,8 +29,10 @@ #include #include #include +#include #include #include +#include #include "cifsglob.h" #include "cifsproto.h" #include "cifs_unicode.h" @@ -54,9 +56,6 @@ #define TLINK_ERROR_EXPIRE (1 * HZ) #define TLINK_IDLE_EXPIRE (600 * HZ) =20 -/* Drop the connection to not overload the server */ -#define MAX_STATUS_IO_TIMEOUT 5 - static int ip_connect(struct TCP_Server_Info *server); static int generic_ip_connect(struct TCP_Server_Info *server); static void tlink_rb_insert(struct rb_root *root, struct tcon_link *new_tl= ink); @@ -66,6 +65,33 @@ static struct mchan_mount *mchan_mount_alloc(struct cifs= _ses *ses); static void mchan_mount_free(struct mchan_mount *mchan_mount); static void mchan_mount_work_fn(struct work_struct *work); =20 +static void smb_tcp_data_ready(struct sock *sk) +{ + struct TCP_Server_Info *server =3D READ_ONCE(sk->sk_user_data); + + trace_sk_data_ready(sk); + trace_smb3_data_ready(0); + if (!server) + return; + + set_bit(SMB_SERVER_DATA_READY, &server->flags); + smp_mb__after_atomic(); + wake_up(&server->rx_waitq); + server->rx_old_data_ready(sk); +} + +static void smb_tcp_error_report(struct sock *sk) +{ + struct TCP_Server_Info *server =3D READ_ONCE(sk->sk_user_data); + + if (!server) + return; + set_bit(SMB_SERVER_DATA_READY, &server->flags); + smp_mb__after_atomic(); + wake_up(&server->rx_waitq); + server->rx_old_error_report(sk); +} + /* * Resolve hostname and set ip addr in tcp ses. Useful for hostnames that = may * get their ip addresses changed at some point. @@ -310,6 +336,15 @@ cifs_abort_connection(struct TCP_Server_Info *server) kernel_sock_shutdown(server->ssocket, SHUT_WR); cifs_dbg(FYI, "Post shutdown state: 0x%x Flags: 0x%lx\n", server->ssocke= t->state, server->ssocket->flags); + + kernel_sock_shutdown(server->ssocket, SHUT_RD); + wake_up(&server->rx_waitq); + + server->ssocket->sk->sk_data_ready =3D server->rx_old_data_ready; + server->ssocket->sk->sk_error_report =3D server->rx_old_error_report; + smp_wmb(); + server->ssocket->sk->sk_user_data =3D NULL; + sock_release(server->ssocket); server->ssocket =3D NULL; } else if (cifs_rdma_enabled(server)) { @@ -322,6 +357,8 @@ cifs_abort_connection(struct TCP_Server_Info *server) server->session_key.len =3D 0; server->lstrp =3D jiffies; =20 + netfs_rxqueue_discard(&server->rx_queue, server->rx_queue.qsize); + /* mark submitted MIDs for retry and issue callback */ INIT_LIST_HEAD(&retry_list); cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); @@ -638,7 +675,7 @@ cifs_echo_request(struct work_struct *work) queue_delayed_work(cifsiod_wq, &server->echo, server->echo_interval); } =20 -static bool +bool allocate_buffers(struct TCP_Server_Info *server) { if (!server->bigbuf) { @@ -649,9 +686,6 @@ allocate_buffers(struct TCP_Server_Info *server) /* retry will check if exiting */ return false; } - } else if (server->large_buf) { - /* we are reusing a dirty large buf, clear its start */ - memset(server->bigbuf, 0, HEADER_SIZE(server)); } =20 if (!server->smallbuf) { @@ -662,10 +696,6 @@ allocate_buffers(struct TCP_Server_Info *server) /* retry will check if exiting */ return false; } - /* beginning of smb buffer is cleared in our buf_get */ - } else { - /* if existing small buf clear beginning */ - memset(server->smallbuf, 0, HEADER_SIZE(server)); } =20 return true; @@ -728,103 +758,10 @@ zero_credits(struct TCP_Server_Info *server) return false; } =20 -static int -cifs_readv_from_socket(struct TCP_Server_Info *server, struct msghdr *smb_= msg) -{ - int length =3D 0; - int total_read; - - for (total_read =3D 0; msg_data_left(smb_msg); total_read +=3D length) { - try_to_freeze(); - - /* reconnect if no credits and no requests in flight */ - if (zero_credits(server)) { - cifs_reconnect(server, false); - return -ECONNABORTED; - } - - if (server_unresponsive(server)) - return -ECONNABORTED; - if (cifs_rdma_enabled(server) && server->smbd_conn) - length =3D smbd_recv(server->smbd_conn, smb_msg); - else - length =3D sock_recvmsg(server->ssocket, smb_msg, 0); - - spin_lock(&server->srv_lock); - if (server->tcpStatus =3D=3D CifsExiting) { - spin_unlock(&server->srv_lock); - return -ESHUTDOWN; - } - - if (server->tcpStatus =3D=3D CifsNeedReconnect) { - spin_unlock(&server->srv_lock); - cifs_reconnect(server, false); - return -ECONNABORTED; - } - spin_unlock(&server->srv_lock); - - if (length =3D=3D -ERESTARTSYS || - length =3D=3D -EAGAIN || - length =3D=3D -EINTR) { - /* - * Minimum sleep to prevent looping, allowing socket - * to clear and app threads to set tcpStatus - * CifsNeedReconnect if server hung. - */ - usleep_range(1000, 2000); - length =3D 0; - continue; - } - - if (length <=3D 0) { - cifs_dbg(FYI, "Received no data or error: %d\n", length); - cifs_reconnect(server, false); - return -ECONNABORTED; - } - } - return total_read; -} - -int -cifs_read_from_socket(struct TCP_Server_Info *server, char *buf, - unsigned int to_read) -{ - struct msghdr smb_msg =3D {}; - struct kvec iov =3D {.iov_base =3D buf, .iov_len =3D to_read}; - - iov_iter_kvec(&smb_msg.msg_iter, ITER_DEST, &iov, 1, to_read); - - return cifs_readv_from_socket(server, &smb_msg); -} - -ssize_t -cifs_discard_from_socket(struct TCP_Server_Info *server, size_t to_read) -{ - struct msghdr smb_msg =3D {}; - - /* - * iov_iter_discard already sets smb_msg.type and count and iov_offset - * and cifs_readv_from_socket sets msg_control and msg_controllen - * so little to initialize in struct msghdr - */ - iov_iter_discard(&smb_msg.msg_iter, ITER_DEST, to_read); - - return cifs_readv_from_socket(server, &smb_msg); -} - -int -cifs_read_iter_from_socket(struct TCP_Server_Info *server, struct iov_iter= *iter, - unsigned int to_read) +static bool smb_decode_rfc1002(struct TCP_Server_Info *server, u32 rfc1002= _hdr) { - struct msghdr smb_msg =3D { .msg_iter =3D *iter }; + u8 type =3D rfc1002_hdr >> 24; =20 - iov_iter_truncate(&smb_msg.msg_iter, to_read); - return cifs_readv_from_socket(server, &smb_msg); -} - -static bool -is_smb_response(struct TCP_Server_Info *server, unsigned char type) -{ /* * The first byte big endian of the length field, * is actually not part of the length but the type @@ -850,7 +787,8 @@ is_smb_response(struct TCP_Server_Info *server, unsigne= d char type) * exclusively in ip_rfc1001_connect() function. */ cifs_server_dbg(VFS, "RFC 1002 positive session response (unexpected)\n"= ); - cifs_reconnect(server, true); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + set_bit(SMB_SERVER_SESSION_RECONNECT, &server->flags); break; case RFC1002_NEGATIVE_SESSION_RESPONSE: /* @@ -934,16 +872,20 @@ is_smb_response(struct TCP_Server_Info *server, unsig= ned char type) msleep(2000); } else { cifs_server_dbg(VFS, "RFC 1002 negative session response (unexpected)\n= "); - cifs_reconnect(server, true); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + set_bit(SMB_SERVER_SESSION_RECONNECT, &server->flags); } break; case RFC1002_RETARGET_SESSION_RESPONSE: cifs_server_dbg(VFS, "RFC 1002 retarget session response (unexpected)\n"= ); - cifs_reconnect(server, true); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + set_bit(SMB_SERVER_SESSION_RECONNECT, &server->flags); break; default: cifs_server_dbg(VFS, "RFC 1002 unknown response type 0x%x\n", type); - cifs_reconnect(server, true); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + set_bit(SMB_SERVER_SESSION_RECONNECT, &server->flags); + break; } =20 return false; @@ -974,41 +916,6 @@ dequeue_mid(struct TCP_Server_Info *server, struct smb= _message *smb, bool malfor } } =20 -static unsigned int -smb2_get_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) -{ - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buffer; - - /* - * SMB1 does not use credits. - */ - if (is_smb1(server)) - return 0; - - return le16_to_cpu(shdr->CreditRequest); -} - -static void -handle_mid(struct smb_message *smb, struct TCP_Server_Info *server, - char *buf, int malformed) -{ - if (server->ops->check_trans2 && - server->ops->check_trans2(smb, server, buf, malformed)) - return; - smb->credits_received =3D smb2_get_credits_from_hdr(buf, server); - smb->resp_buf =3D buf; - smb->large_buf =3D server->large_buf; - /* Was previous buf put in mpx struct for multi-rsp? */ - if (!smb->multiRsp) { - /* smb buffer will be freed by user thread */ - if (server->large_buf) - server->bigbuf =3D NULL; - else - server->smallbuf =3D NULL; - } - dequeue_mid(server, smb, malformed); -} - int cifs_enable_signing(struct TCP_Server_Info *server, bool mnt_sign_required) { @@ -1090,6 +997,14 @@ clean_demultiplex_info(struct TCP_Server_Info *server) if (cifs_rdma_enabled(server)) smbd_destroy(server); if (server->ssocket) { + kernel_sock_shutdown(server->ssocket, SHUT_RD); + wake_up(&server->rx_waitq); + + server->ssocket->sk->sk_data_ready =3D server->rx_old_data_ready; + server->ssocket->sk->sk_error_report =3D server->rx_old_error_report; + smp_wmb(); + server->ssocket->sk->sk_user_data =3D NULL; + sock_release(server->ssocket); server->ssocket =3D NULL; } @@ -1149,120 +1064,210 @@ clean_demultiplex_info(struct TCP_Server_Info *se= rver) mempool_resize(cifs_req_poolp, length + cifs_min_rcv); } =20 -static int -standard_receive3(struct TCP_Server_Info *server, struct smb_message *smb) +/* + * Splice buffers from a socket. + */ +static int smb_splice_from_socket(struct TCP_Server_Info *server, struct b= vecq *bq) { int length; - char *buf =3D server->smallbuf; - unsigned int pdu_length =3D server->pdu_size; =20 - /* make sure this will fit in a large buffer */ - if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { - cifs_server_dbg(VFS, "SMB response too long (%u bytes)\n", pdu_length); - cifs_reconnect(server, true); - return -ECONNABORTED; - } + try_to_freeze(); =20 - /* switch to large buffer if too big for a small one */ - if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { - server->large_buf =3D true; - memcpy(server->bigbuf, buf, server->total_read); - buf =3D server->bigbuf; +#if 0 + /* reconnect if no credits and no requests in flight */ + if (zero_credits(server)) { + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + return -ECONNABORTED; } +#endif =20 - /* now read the rest */ - length =3D cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, - pdu_length - MID_HEADER_SIZE(server)); + if (server_unresponsive(server)) + return -ECONNABORTED; =20 - if (length < 0) - return length; - server->total_read +=3D length; +#if 0 + if (cifs_rdma_enabled(server) && server->smbd_conn) + length =3D smbd_recv(server->smbd_conn, smb_msg); + else +#endif + length =3D netfs_tcp_splice_to_bvecq(server->ssocket, bq, INT_MAX); + trace_smb3_tcp_splice(length); =20 - dump_smb(buf, server->total_read); + spin_lock(&server->srv_lock); + if (server->tcpStatus =3D=3D CifsExiting) { + spin_unlock(&server->srv_lock); + return -ESHUTDOWN; + } =20 - return cifs_handle_standard(server, smb); + if (server->tcpStatus =3D=3D CifsNeedReconnect) { + spin_unlock(&server->srv_lock); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + return -ECONNABORTED; + } + spin_unlock(&server->srv_lock); + return length; } =20 -int -cifs_handle_standard(struct TCP_Server_Info *server, struct smb_message *s= mb) +/* + * Refill the receive queue. Whilst the peer may send PDUs in separate TCP + * packets, it's possible that the local NIC may join them back together if + * doing receive offload. + * + * If min_size is 0, it will splice anything it can quickly and immediately + * grab out of the queue, but it will not wait. + */ +int smb_rxqueue_refill(struct TCP_Server_Info *server, struct netfs_rxqueu= e *rxq, + size_t min_size) { - char *buf =3D server->large_buf ? server->bigbuf : server->smallbuf; - int rc; - - /* - * We know that we received enough to get to the MID as we - * checked the pdu_length earlier. Now check to see - * if the rest of the header is OK. - * - * 48 bytes is enough to display the header and a little bit - * into the payload for debugging purposes. - */ - rc =3D server->ops->check_message(buf, server->pdu_size, - server->total_read, server); - if (rc) - cifs_dump_mem("Bad SMB: ", buf, - min_t(unsigned int, server->total_read, 48)); + struct bvecq *add_to =3D rxq->add_to; + unsigned int got =3D 0; + size_t qsize =3D rxq->qsize; + int rc =3D 0; =20 - if (server->ops->is_session_expired && - server->ops->is_session_expired(buf)) { - cifs_reconnect(server, true); - return -1; + if (!rxq->refillable) { + WARN_ON(min_size > qsize); + return 0; } + if (qsize >=3D min_size && min_size > 0) + return 0; =20 - if (server->ops->is_status_pending && - server->ops->is_status_pending(buf, server)) - return -1; + do { + if (!add_to || add_to->nr_slots =3D=3D add_to->max_slots) { + struct bvecq *b; + unsigned int nr_bv =3D (2048 - sizeof(*add_to)) / sizeof(add_to->bv[0]); + + b =3D netfs_alloc_rx_bvecq(nr_bv); + b->prev =3D add_to; + if (!add_to) + rxq->take_from =3D b; + else + add_to->next =3D b; + add_to =3D b; + } =20 - if (!smb) - return rc; + rc =3D smb_splice_from_socket(server, add_to); + if (rc > 0) { + qsize +=3D rc; + got +=3D rc; + rc =3D 0; + continue; + } =20 - handle_mid(smb, server, buf, rc); + switch (rc) { + case -EAGAIN: + case -EINTR: + case -ERESTARTSYS: + wait_event_killable(server->rx_waitq, + test_bit(SMB_SERVER_DATA_READY, &server->flags)); + clear_bit(SMB_SERVER_DATA_READY, &server->flags); + rc =3D 0; + continue; + default: + cifs_dbg(FYI, "Received no data or error: %d\n", rc); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + rc =3D -ECONNABORTED; + goto out; + } + } while (qsize < min_size); + +out: + rxq->add_to =3D add_to; + rxq->qsize =3D qsize; + if (min_size =3D=3D 0) + rc =3D got > 0 ? 0 : rc; + else + rc =3D qsize >=3D min_size ? 0 : rc; + return rc; +} + +/* + * Consume received data by receiving it and then discarding it. + */ +int smb_rxqueue_consume(struct TCP_Server_Info *server, + struct netfs_rxqueue *rxq, size_t amount) +{ + while (amount) { + size_t part =3D umin(amount, rxq->qsize); + int rc; + + amount -=3D part; + netfs_rxqueue_discard(rxq, part); + + if (!amount) + break; + + rc =3D smb_rxqueue_refill(server, rxq, 1); + if (rc < 0) + return rc; + } return 0; } =20 -static void -smb2_add_credits_from_hdr(char *buffer, struct TCP_Server_Info *server) +/* + * Receive a PDU from a socket and place it into a bvec queue. This is th= en + * decrypted and handed off for distribution to the reply decoders. + */ +static void smb_receive_pdu(struct TCP_Server_Info *server) { - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buffer; - int scredits, in_flight; + struct netfs_rxqueue *rxq =3D &server->rx_queue; + unsigned int pdu_len; + __be32 rfc1002_be32; + u32 rfc1002_hdr; + int rc; =20 - /* - * SMB1 does not use credits. - */ - if (is_smb1(server)) + /* TODO: If smbdirect, decant the reassembly queue into the bvecq. */ + + rxq->refillable =3D true; + rxq->pdu_remain =3D 4; + rxq->msg_id =3D 0; + + /* Read the RFC1002 header. */ + rc =3D smb_rxqueue_refill(server, rxq, 4); + if (rc < 0) return; =20 - if (shdr->CreditRequest) { - spin_lock(&server->req_lock); - server->credits +=3D le16_to_cpu(shdr->CreditRequest); - scredits =3D server->credits; - in_flight =3D server->in_flight; - spin_unlock(&server->req_lock); - wake_up(&server->request_q); + /* Extract the RFC1002 header. */ + if (netfs_rxqueue_read(rxq, &rfc1002_be32, 0, sizeof(rfc1002_be32)) !=3D + sizeof(rfc1002_be32)) { + cifs_dbg(FYI, "copy_from_iter() failed\n"); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + return; + } + + rfc1002_hdr =3D be32_to_cpu(rfc1002_be32); + pdu_len =3D rfc1002_hdr & 0xffffff; + netfs_rxqueue_discard(rxq, 4); + + rxq->pdu_remain =3D pdu_len; =20 - trace_smb3_hdr_credits(server->current_mid, - server->conn_id, server->hostname, scredits, - le16_to_cpu(shdr->CreditRequest), in_flight); - cifs_server_dbg(FYI, "%s: added %u credits total=3D%d\n", - __func__, le16_to_cpu(shdr->CreditRequest), - scredits); + trace_smb3_rx_pdu(rxq); + + if (smb_decode_rfc1002(server, rfc1002_hdr)) { + /* Normal session message. */ + cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_len); + + rc =3D server->ops->receive_pdu(server, pdu_len); + if (rc < 0) + cifs_dbg(FYI, "->receive_pdu() =3D %d\n", rc); + + if (rxq->pdu_remain) + cifs_dbg(FYI, "PDU not wholly consumed (%x)\n", + rxq->pdu_remain); } -} =20 + if (rxq->pdu_remain) + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); +} =20 +/* + * TCP message receive loop. + */ static int cifs_demultiplex_thread(void *p) { - int i, num_smbs, length; struct TCP_Server_Info *server =3D p; - unsigned int pdu_length; - unsigned int next_offset; - char *buf =3D NULL; struct task_struct *task_to_wake =3D NULL; - struct smb_message *smbs[MAX_COMPOUND]; - char *bufs[MAX_COMPOUND]; - unsigned int noreclaim_flag, num_io_timeout =3D 0; - bool pending_reconnect =3D false; + unsigned int noreclaim_flag; + int length; =20 noreclaim_flag =3D memalloc_noreclaim_save(); cifs_dbg(FYI, "Demultiplex PID: %d\n", task_pid_nr(current)); @@ -1280,152 +1285,15 @@ cifs_demultiplex_thread(void *p) if (!allocate_buffers(server)) continue; =20 - server->large_buf =3D false; - buf =3D server->smallbuf; - pdu_length =3D 4; /* enough to get RFC1001 header */ - - length =3D cifs_read_from_socket(server, buf, pdu_length); - if (length < 0) - continue; - - server->total_read =3D 0; - - /* - * The right amount was read from socket - 4 bytes, - * so we can now interpret the length field. - */ - pdu_length =3D be32_to_cpup(((__be32 *)buf)) & 0xffffff; - - cifs_dbg(FYI, "RFC1002 header 0x%x\n", pdu_length); - if (!is_smb_response(server, buf[0])) - continue; - - pending_reconnect =3D false; -next_pdu: - server->pdu_size =3D pdu_length; - - /* make sure we have enough to get to the MID */ - if (server->pdu_size < MID_HEADER_SIZE(server)) { - cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", - server->pdu_size); - cifs_reconnect(server, true); - continue; - } - - /* read down to the MID */ - length =3D cifs_read_from_socket(server, buf, - MID_HEADER_SIZE(server)); - if (length < 0) - continue; - server->total_read +=3D length; - - if (server->ops->next_header) { - if (server->ops->next_header(server, buf, &next_offset)) { - cifs_dbg(VFS, "%s: malformed response (next_offset=3D%u)\n", - __func__, next_offset); - cifs_reconnect(server, true); - continue; - } - if (next_offset) - server->pdu_size =3D next_offset; - } - - memset(smbs, 0, sizeof(smbs)); - memset(bufs, 0, sizeof(bufs)); - num_smbs =3D 0; - - if (server->ops->is_transform_hdr && - server->ops->receive_transform && - server->ops->is_transform_hdr(buf)) { - length =3D server->ops->receive_transform(server, - smbs, - bufs, - &num_smbs); - } else { - smbs[0] =3D server->ops->find_mid(server, buf); - bufs[0] =3D buf; - num_smbs =3D 1; - - if (smbs[0]) - smbs[0]->response_pdu_len =3D pdu_length; - if (!smbs[0] || !smbs[0]->receive) - length =3D standard_receive3(server, smbs[0]); - else - length =3D smbs[0]->receive(server, smbs[0]); - } - - if (length < 0) { - for (i =3D 0; i < num_smbs; i++) - if (smbs[i]) - release_mid(server, smbs[i]); - continue; - } - - if (server->ops->is_status_io_timeout && - server->ops->is_status_io_timeout(buf)) { - num_io_timeout++; - if (num_io_timeout > MAX_STATUS_IO_TIMEOUT) { - cifs_server_dbg(VFS, - "Number of request timeouts exceeded %d. Reconnecting", - MAX_STATUS_IO_TIMEOUT); - - pending_reconnect =3D true; - num_io_timeout =3D 0; - } - } - - server->lstrp =3D jiffies; - - for (i =3D 0; i < num_smbs; i++) { - if (smbs[i] !=3D NULL) { - smbs[i]->resp_buf_size =3D server->pdu_size; - - if (bufs[i] !=3D NULL) { - if (server->ops->is_network_name_deleted && - server->ops->is_network_name_deleted(bufs[i], - server)) { - cifs_server_dbg(FYI, - "Share deleted. Reconnect needed"); - } - } - - if (!smbs[i]->multiRsp || smbs[i]->multiEnd) - mid_execute_callback(server, smbs[i]); - - release_mid(server, smbs[i]); - } else if (server->ops->is_oplock_break && - server->ops->is_oplock_break(bufs[i], - server)) { - smb2_add_credits_from_hdr(bufs[i], server); - cifs_dbg(FYI, "Received oplock break\n"); - } else { - cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids= %d\n", - atomic_read(&mid_count)); - cifs_dump_mem("Received Data is: ", bufs[i], - HEADER_SIZE(server)); - smb2_add_credits_from_hdr(bufs[i], server); -#ifdef CONFIG_CIFS_DEBUG2 - if (server->ops->dump_detail) - server->ops->dump_detail(bufs[i], pdu_length, - server); - cifs_dump_mids(server); -#endif /* CIFS_DEBUG2 */ - } - } - - if (pdu_length > server->pdu_size) { - if (!allocate_buffers(server)) - continue; - pdu_length -=3D server->pdu_size; - server->total_read =3D 0; - server->large_buf =3D false; - buf =3D server->smallbuf; - goto next_pdu; - } + smb_receive_pdu(server); =20 /* do this reconnect at the very end after processing all MIDs */ - if (pending_reconnect) - cifs_reconnect(server, true); + if (test_and_clear_bit(SMB_SERVER_NEED_RECONNECT, &server->flags)) { + bool mark_sess =3D test_and_clear_bit(SMB_SERVER_SESSION_RECONNECT, + &server->flags); + cifs_reconnect(server, mark_sess); + } + cond_resched(); =20 } /* end while !EXITING */ =20 @@ -1800,6 +1668,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, spin_unlock(&cifs_tcp_ses_lock); tcp_ses->primary_server =3D primary_server; } + init_waitqueue_head(&tcp_ses->rx_waitq); init_waitqueue_head(&tcp_ses->response_q); init_waitqueue_head(&tcp_ses->request_q); INIT_LIST_HEAD(&tcp_ses->pending_mid_q); @@ -3425,6 +3294,13 @@ generic_ip_connect(struct TCP_Server_Info *server) } trace_smb3_connect_done(server->hostname, server->conn_id, &server->dstad= dr); =20 + server->ssocket->sk->sk_user_data =3D server; + smp_wmb(); + server->rx_old_data_ready =3D server->ssocket->sk->sk_data_ready; + server->rx_old_error_report =3D server->ssocket->sk->sk_error_report; + server->ssocket->sk->sk_data_ready =3D smb_tcp_data_ready; + server->ssocket->sk->sk_error_report =3D smb_tcp_error_report; + /* * Establish RFC1001 NetBIOS session when it was explicitly requested * by mount option -o nbsessinit, or when connecting to default RFC1001 diff --git a/fs/smb/client/smb1debug.c b/fs/smb/client/smb1debug.c index e2d013e751e5..048fe6303bc1 100644 --- a/fs/smb/client/smb1debug.c +++ b/fs/smb/client/smb1debug.c @@ -9,17 +9,58 @@ #include "smb1proto.h" #include "cifs_debug.h" =20 -void cifs_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *s= erver) -{ #ifdef CONFIG_CIFS_DEBUG2 - struct smb_hdr *smb =3D buf; +void cifs_dump_detail(struct TCP_Server_Info *server, const struct cifs_re= ceive *recv) +{ + const union smb1_response_hdr *h =3D recv->response; + const struct smb_hdr *smb =3D &h->hdr; =20 cifs_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Flgs2: 0x%x Mid: %d Pid: %d = Wct: %d\n", smb->Command, smb->Status.CifsError, smb->Flags, smb->Flags2, smb->Mid, smb->Pid, smb->WordCount); - if (!server->ops->check_message(buf, buf_len, server->total_read, server)= ) { - cifs_dbg(VFS, "smb buf %p len %u\n", smb, - server->ops->calc_smb_size(smb)); + if (recv->malformed) + cifs_dbg(VFS, "smb buf %p len %u\n", smb, recv->calc_len); +} + +void cifs_dump_mids(struct TCP_Server_Info *server) +{ + struct smb_message *smb; + + if (server =3D=3D NULL) + return; + + cifs_dbg(VFS, "Dump pending requests:\n"); + spin_lock(&server->mid_queue_lock); + list_for_each_entry(smb, &server->pending_mid_q, qhead) { + struct cifs_receive recv =3D { + .response =3D smb->response, + .msg_len =3D smb->resp_len, + .error =3D smb->error, + .data_len =3D smb->resp_data_len, + .data_offset =3D smb->resp_data_offset, + }; + + cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", + smb->mid_state, + le16_to_cpu(smb->command), + smb->pid, + smb->callback_data, + smb->mid); +#ifdef CONFIG_CIFS_STATS2 + cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", + smb->large_buf, + smb->response, + smb->when_received, + jiffies); +#endif /* STATS2 */ + cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n", + smb->multiRsp, smb->multiEnd); + if (recv.response) { + cifs_dump_detail(server, &recv); + cifs_dump_mem("existing buf: ", recv.response, 62); + } } -#endif /* CONFIG_CIFS_DEBUG2 */ + spin_unlock(&server->mid_queue_lock); } + +#endif /* CONFIG_CIFS_DEBUG2 */ diff --git a/fs/smb/client/smb1encrypt.c b/fs/smb/client/smb1encrypt.c index bf10fdeeedca..819c736c26e9 100644 --- a/fs/smb/client/smb1encrypt.c +++ b/fs/smb/client/smb1encrypt.c @@ -10,12 +10,34 @@ */ =20 #include +#include #include #include #include "cifsproto.h" #include "smb1proto.h" #include "cifs_debug.h" =20 +static size_t cifs_md5_step(void *iter_base, size_t progress, size_t len, + void *priv, void *priv2) +{ + struct md5_ctx *ctx =3D priv; + + md5_update(ctx, iter_base, len); + return 0; +} + +static int cifs_md5_iter(struct iov_iter *iter, size_t maxsize, + struct md5_ctx *ctx) +{ + size_t did; + + did =3D iterate_and_advance_kernel(iter, maxsize, ctx, NULL, + cifs_md5_step); + if (did !=3D maxsize) + return smb_EIO2(smb_eio_trace_md5_iter, did, maxsize); + return 0; +} + /* * Calculate and return the CIFS signature based on the mac key and SMB PD= U. * The 16 byte signature must be allocated by the caller. Note we only use= the @@ -138,3 +160,92 @@ int cifs_verify_signature(struct smb_rqst *rqst, return 0; =20 } + +/* + * Calculate and return the CIFS signature based on the mac key and SMB PD= U. + * The 16 byte signature must be allocated by the caller. Note we only use= the + * 1st eight bytes and that the smb header signature field on input contai= ns + * the sequence number before this function is called. Also, this function + * should be called with the server->srv_mutex held. + */ +static int cifs_calc_trans_signature(struct TCP_Server_Info *server, + struct cifs_receive *recv, + struct iov_iter *message, + char *signature) +{ + struct iov_iter iter; + struct md5_ctx ctx; + struct kvec kv[1] =3D { + [0].iov_len =3D recv->extracted, + [0].iov_base =3D recv->response, + }; + size_t did; + int rc; + + md5_init(&ctx); + md5_update(&ctx, server->session_key.response, server->session_key.len); + + iov_iter_kvec(&iter, ITER_SOURCE, kv, 3, recv->extracted); + + did =3D iterate_kvec(&iter, recv->extracted, &ctx, NULL, cifs_md5_step); + if (did !=3D recv->extracted) + return smb_EIO2(smb_eio_trace_md5_iter, did, recv->extracted); + + iter =3D *message; + rc =3D cifs_md5_iter(&iter, recv->msg_len - recv->extracted, &ctx); + if (rc < 0) + return rc; + + md5_final(&ctx, signature); + return 0; +} + +/* + * Verify the signature on a Trans/Trans2/NTTrans packet that's incomplete= ly + * extracted from the Rx queue. We need to do this in the I/O thread unle= ss we + * want to punt the entire reassembly process to cifs_check_receive() as + * reassembly will corrupt the signatures. + */ +int cifs_verify_trans_signature(struct TCP_Server_Info *server, + struct cifs_receive *recv, + struct netfs_rxqueue *rxq, + __u32 expected_sequence_number) +{ + union smb1_response_hdr *h =3D recv->response; + struct iov_iter iter; + struct smb_hdr *cifs_pdu =3D &h->hdr; + char what_we_think_sig_should_be[20]; + char server_response_sig[8]; + int rc; + + /* BB what if signatures are supposed to be on for session but + server does not send one? BB */ + + /* Do not need to verify session setups with signature "BSRSPYL " */ + if (memcmp(cifs_pdu->Signature.SecuritySignature, "BSRSPYL ", 8) =3D=3D 0) + cifs_dbg(FYI, "dummy signature received for smb command 0x%x\n", + cifs_pdu->Command); + + /* save off the original signature so we can modify the smb and check + its signature against what the server sent */ + memcpy(server_response_sig, cifs_pdu->Signature.SecuritySignature, 8); + cifs_pdu->Signature.Sequence.SequenceNumber =3D + cpu_to_le32(expected_sequence_number); + cifs_pdu->Signature.Sequence.Reserved =3D 0; + + iov_iter_bvec_queue(&iter, ITER_SOURCE, rxq->take_from, + rxq->take_slot, rxq->take_offset, + umin(rxq->qsize, rxq->pdu_remain)); + + cifs_server_lock(server); + rc =3D cifs_calc_trans_signature(server, recv, &iter, + what_we_think_sig_should_be); + cifs_server_unlock(server); + + if (rc) + return rc; + + if (memcmp(server_response_sig, what_we_think_sig_should_be, 8) !=3D 0) + return -EACCES; + return 0; +} diff --git a/fs/smb/client/smb1maperror.c b/fs/smb/client/smb1maperror.c index c84f6256e146..e44a51039776 100644 --- a/fs/smb/client/smb1maperror.c +++ b/fs/smb/client/smb1maperror.c @@ -97,9 +97,8 @@ search_mapping_table_ERRSRV(__u16 smb_err) } =20 int -map_smb_to_linux_error(char *buf, bool logErr) +map_smb_to_linux_error(const struct smb_hdr *smb, bool logErr) { - struct smb_hdr *smb =3D (struct smb_hdr *)buf; int rc =3D -EIO; /* if transport error smb error may not be set */ __u8 smberrclass; __u16 smberrcode; @@ -175,9 +174,9 @@ map_and_check_smb_error(struct TCP_Server_Info *server, struct smb_message *smb, bool logErr) { int rc; - struct smb_hdr *rhdr =3D (struct smb_hdr *)smb->resp_buf; + struct smb_hdr *rhdr =3D (struct smb_hdr *)smb->response; =20 - rc =3D map_smb_to_linux_error((char *)rhdr, logErr); + rc =3D map_smb_to_linux_error(rhdr, logErr); if (rc =3D=3D -EACCES && !(rhdr->Flags2 & SMBFLG2_ERR_STATUS)) { /* possible ERRBaduid */ __u8 class =3D rhdr->Status.DosError.ErrorClass; diff --git a/fs/smb/client/smb1misc.c b/fs/smb/client/smb1misc.c index ba56023010d8..357850e9691f 100644 --- a/fs/smb/client/smb1misc.c +++ b/fs/smb/client/smb1misc.c @@ -63,10 +63,11 @@ header_assemble(struct smb_hdr *buffer, char smb_comman= d, } =20 bool -is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv) +smb1_is_valid_oplock_break(union smb1_response_hdr *buf, unsigned int pdu_= len, + struct TCP_Server_Info *srv) { - struct smb_hdr *buf =3D (struct smb_hdr *)buffer; - struct smb_com_lock_req *pSMB =3D (struct smb_com_lock_req *)buf; + struct smb_hdr *hdr =3D &buf->hdr; + struct smb_com_lock_req *pSMB =3D &buf->oplock_break; struct TCP_Server_Info *pserver; struct cifs_ses *ses; struct cifs_tcon *tcon; @@ -76,13 +77,12 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_I= nfo *srv) cifs_dbg(FYI, "Checking for oplock break or dnotify response\n"); if ((pSMB->hdr.Command =3D=3D SMB_COM_NT_TRANSACT) && (pSMB->hdr.Flags & SMBFLG_RESPONSE)) { - struct smb_com_transaction_change_notify_rsp *pSMBr =3D - (struct smb_com_transaction_change_notify_rsp *)buf; + struct smb_com_transaction_change_notify_rsp *pSMBr =3D &buf->change; struct file_notify_information *pnotify; __u32 data_offset =3D 0; - size_t len =3D srv->total_read - srv->pdu_size; + size_t len =3D pdu_len; =20 - if (get_bcc(buf) > sizeof(struct file_notify_information)) { + if (get_bcc(hdr) > sizeof(struct file_notify_information)) { data_offset =3D le32_to_cpu(pSMBr->DataOffset); =20 if (data_offset > @@ -141,7 +141,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_I= nfo *srv) if (cifs_ses_exiting(ses)) continue; list_for_each_entry(tcon, &ses->tcon_list, tcon_list) { - if (tcon->tid !=3D buf->Tid) + if (tcon->tid !=3D hdr->Tid) continue; =20 cifs_stats_inc(&tcon->stats.cifs_stats.num_oplock_brks); @@ -183,7 +183,7 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_I= nfo *srv) unsigned int smbCalcSize(void *buf) { - struct smb_hdr *ptr =3D buf; - return (sizeof(struct smb_hdr) + (2 * ptr->WordCount) + + const struct smb_hdr *ptr =3D buf; + return (sizeof(*ptr) + (2 * ptr->WordCount) + 2 /* size of the bcc field */ + get_bcc(ptr)); } diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index df74975374ee..042d44788321 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -175,7 +175,7 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_= Info *server, cifs_server_unlock(server); =20 cifs_dbg(FYI, "issued NT_CANCEL for mid %u, rc =3D %d\n", - get_mid(in_buf), rc); + le16_to_cpu(in_buf->Mid), rc); =20 return rc; } @@ -226,34 +226,17 @@ cifs_compare_fids(struct cifsFileInfo *ob1, struct ci= fsFileInfo *ob2) return ob1->fid.netfid =3D=3D ob2->fid.netfid; } =20 -static unsigned int -cifs_read_data_offset(char *buf) -{ - READ_RSP *rsp =3D (READ_RSP *)buf; - return le16_to_cpu(rsp->DataOffset); -} - -static unsigned int -cifs_read_data_length(char *buf, bool in_remaining) +struct smb_message * +cifs_find_mid(struct TCP_Server_Info *server, const struct smb_hdr *shdr) { - READ_RSP *rsp =3D (READ_RSP *)buf; - /* It's a bug reading remaining data for SMB1 packets */ - WARN_ON(in_remaining); - return (le16_to_cpu(rsp->DataLengthHigh) << 16) + - le16_to_cpu(rsp->DataLength); -} - -static struct smb_message * -cifs_find_mid(struct TCP_Server_Info *server, char *buffer) -{ - struct smb_hdr *buf =3D (struct smb_hdr *)buffer; struct smb_message *smb; + u16 mid =3D le16_to_cpu(shdr->Mid); =20 spin_lock(&server->mid_queue_lock); list_for_each_entry(smb, &server->pending_mid_q, qhead) { - if (compare_mid(smb->mid, buf) && + if (smb->mid =3D=3D mid && smb->mid_state =3D=3D MID_REQUEST_SUBMITTED && - le16_to_cpu(smb->command) =3D=3D buf->Command) { + smb->command =3D=3D shdr->Command) { smb_get_message(smb); spin_unlock(&server->mid_queue_lock); return smb; @@ -1342,10 +1325,9 @@ cifs_make_node(unsigned int xid, struct inode *inode, } } =20 -static bool -cifs_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) +bool +cifs_is_network_name_deleted(const struct smb_hdr *shdr, struct TCP_Server= _Info *server) { - struct smb_hdr *shdr =3D (struct smb_hdr *)buf; struct TCP_Server_Info *pserver; struct cifs_ses *ses; struct cifs_tcon *tcon; @@ -1388,6 +1370,7 @@ struct smb_version_operations smb1_operations =3D { .compare_fids =3D cifs_compare_fids, .setup_request =3D cifs_setup_request, .setup_async_request =3D cifs_setup_async_request, + .receive_pdu =3D smb1_receive_pdu, .check_receive =3D cifs_check_receive, .add_credits =3D cifs_add_credits, .set_credits =3D cifs_set_credits, @@ -1395,17 +1378,9 @@ struct smb_version_operations smb1_operations =3D { .get_credits =3D cifs_get_credits, .wait_mtu_credits =3D cifs_wait_mtu_credits, .get_next_mid =3D cifs_get_next_mid, - .read_data_offset =3D cifs_read_data_offset, - .read_data_length =3D cifs_read_data_length, - .map_error =3D map_smb_to_linux_error, - .find_mid =3D cifs_find_mid, - .check_message =3D checkSMB, - .dump_detail =3D cifs_dump_detail, .clear_stats =3D cifs_clear_stats, .print_stats =3D cifs_print_stats, - .is_oplock_break =3D is_valid_oplock_break, .downgrade_oplock =3D cifs_downgrade_oplock, - .check_trans2 =3D cifs_check_trans2, .need_neg =3D cifs_need_neg, .negotiate =3D cifs_negotiate, .negotiate_wsize =3D smb1_negotiate_wsize, @@ -1468,7 +1443,6 @@ struct smb_version_operations smb1_operations =3D { .get_acl_by_fid =3D get_cifs_acl_by_fid, .set_acl =3D set_cifs_acl, .make_node =3D cifs_make_node, - .is_network_name_deleted =3D cifs_is_network_name_deleted, }; =20 struct smb_version_values smb1_values =3D { diff --git a/fs/smb/client/smb1pdu.h b/fs/smb/client/smb1pdu.h index 7584e94d9b2b..afd857e9e6ce 100644 --- a/fs/smb/client/smb1pdu.h +++ b/fs/smb/client/smb1pdu.h @@ -424,7 +424,7 @@ typedef struct smb_negotiate_rsp { #define CAP_EXTENDED_SECURITY 0x80000000 =20 typedef union smb_com_session_setup_andx { - struct { /* request format */ + struct smb1_session_req { /* request format */ struct smb_hdr hdr; /* wct =3D 12 */ __u8 AndXCommand; __u8 AndXReserved; @@ -443,7 +443,7 @@ typedef union smb_com_session_setup_andx { } __packed req; /* NTLM request format (with extended security */ =20 - struct { /* request format */ + struct smb1_session_no_secext_req { /* request format */ struct smb_hdr hdr; /* wct =3D 13 */ __u8 AndXCommand; __u8 AndXReserved; @@ -466,7 +466,7 @@ typedef union smb_com_session_setup_andx { } __packed req_no_secext; /* NTLM request format (without extended security */ =20 - struct { /* default (NTLM) response format */ + struct smb1_session_rsp { /* default (NTLM) response format */ struct smb_hdr hdr; /* wct =3D 4 */ __u8 AndXCommand; __u8 AndXReserved; @@ -481,7 +481,7 @@ typedef union smb_com_session_setup_andx { } __packed resp; /* NTLM response (with or without extended sec) */ =20 - struct { /* request format */ + struct smb1_old_session_req { /* request format */ struct smb_hdr hdr; /* wct =3D 10 */ __u8 AndXCommand; __u8 AndXReserved; @@ -500,7 +500,7 @@ typedef union smb_com_session_setup_andx { /* STRING NativeLanMan */ } __packed old_req; /* pre-NTLM (LANMAN2.1) req format */ =20 - struct { /* default (NTLM) response format */ + struct smb1_old_session_rsp { /* default (NTLM) response format */ struct smb_hdr hdr; /* wct =3D 3 */ __u8 AndXCommand; __u8 AndXReserved; @@ -668,7 +668,7 @@ typedef union smb_com_tree_disconnect { /* as an altern= ative can use flag on struct smb_hdr hdr; /* wct =3D 0 */ __u16 ByteCount; /* bcc =3D 0 */ } __packed req; - struct { + struct smb1_tree_disconnect_rsp { struct smb_hdr hdr; /* wct =3D 0 */ __u16 ByteCount; /* bcc =3D 0 */ } __packed resp; @@ -2342,4 +2342,54 @@ typedef struct file_chattr_info { } __packed FILE_CHATTR_INFO; /* ext attributes (chattr, chflags) level 0x= 206 */ #endif /* POSIX */ =20 +union smb1_response_hdr { + __be32 rfc1002; + struct smb_hdr hdr; + struct { + struct smb_hdr hdr; + union { + u8 short_bcc; + __le16 bcc; + }; + } __packed trivial_rsp; + struct smb_negotiate_rsp neg; + struct smb1_session_rsp session; + struct smb1_old_session_rsp old_session; + struct smb_com_tconx_rsp tconx; + struct smb_com_tconx_rsp_ext tconx_ext; + struct smb_com_echo_rsp echo; + struct smb_com_logoff_andx_rsp logoff; + struct smb1_tree_disconnect_rsp tdis; + struct smb_com_close_rsp close; + struct smb_com_open_rsp open; + struct smb_com_open_rsp_ext open_ext; + struct smb_com_openx_rsp openx; + struct smb_com_write_rsp write; + struct smb_com_read_rsp read; + struct smb_com_lock_rsp lock; + struct smb_com_copy_rsp copy; + struct smb_com_rename_rsp rename; + struct smb_com_delete_file_rsp del_file; + struct smb_com_delete_directory_rsp rmdir; + struct smb_com_create_directory_rsp mkdir; + struct smb_com_query_information_rsp qinfo; + struct smb_com_setattr_rsp setattr; + struct smb_com_ntransact_rsp ntransact; + struct smb_com_transaction_ioctl_rsp ioctl; + struct smb_com_transaction_change_notify_rsp change; + struct smb_t2_rsp trans2; + struct smb_com_transaction2_qpi_rsp qpi; + struct smb_com_transaction2_spi_rsp spi; + struct smb_com_transaction2_sfi_rsp sfi; + struct smb_t2_qfi_rsp qfi; + struct smb_com_transaction2_ffirst_rsp ffirst; + struct smb_com_transaction2_ffirst_rsp_parms ffirst_parms; + struct smb_com_transaction2_fnext_rsp fnext; + struct smb_com_transaction2_fnext_rsp_parms fnext_parms; + struct smb_com_transaction_qfsi_rsp qfsi; + struct smb_com_transaction2_setfsi_rsp setfsi; + struct smb_com_transaction_get_dfs_refer_rsp get_dfs_referral; + struct smb_com_lock_req oplock_break; +}; + #endif /* _SMB1PDU_H */ diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 4ecf50b0922c..b2ad0ef64051 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -218,8 +218,9 @@ int CIFSSMBSetEA(const unsigned int xid, struct cifs_tc= on *tcon, /* * smb1debug.c */ -void cifs_dump_detail(void *buf, size_t buf_len, - struct TCP_Server_Info *server); +void cifs_dump_detail(struct TCP_Server_Info *server, + const struct cifs_receive *recv); +void cifs_dump_mids(struct TCP_Server_Info *server); =20 /* * smb1encrypt.c @@ -229,11 +230,15 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_= Server_Info *server, int cifs_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server, __u32 expected_sequence_number); +int cifs_verify_trans_signature(struct TCP_Server_Info *server, + struct cifs_receive *recv, + struct netfs_rxqueue *rxq, + __u32 expected_sequence_number); =20 /* * smb1maperror.c */ -int map_smb_to_linux_error(char *buf, bool logErr); +int map_smb_to_linux_error(const struct smb_hdr *smb, bool logErr); int smb1_init_maperror(void); int map_and_check_smb_error(struct TCP_Server_Info *server, struct smb_message *smb, bool logErr); @@ -257,7 +262,9 @@ search_mapping_table_ERRSRV_test(__u16 smb_err); */ unsigned int header_assemble(struct smb_hdr *buffer, char smb_command, const struct cifs_tcon *treeCon, int word_count); -bool is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv); +bool +smb1_is_valid_oplock_break(union smb1_response_hdr *buf, unsigned int pdu_= len, + struct TCP_Server_Info *srv); unsigned int smbCalcSize(void *buf); =20 /* @@ -284,6 +291,7 @@ struct smb_message *cifs_setup_async_request(struct TCP= _Server_Info *server, struct smb_rqst *rqst); int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, char *in_buf, unsigned int in_len, int flags); +int checkSMB(const struct TCP_Server_Info *server, struct cifs_receive *re= cv); int cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, bool log_error); struct smb_message *cifs_setup_request(struct cifs_ses *ses, @@ -296,30 +304,13 @@ int SendReceive(const unsigned int xid, struct cifs_s= es *ses, struct smb_hdr *in_buf, unsigned int in_len, struct smb_hdr *out_buf, int *pbytes_returned, const int flags); -bool cifs_check_trans2(struct smb_message *smb, struct TCP_Server_Info *se= rver, - char *buf, int malformed); -int checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read, - struct TCP_Server_Info *server); - - -static inline __u16 -get_mid(const struct smb_hdr *smb) -{ - return le16_to_cpu(smb->Mid); -} - -static inline bool -compare_mid(__u16 mid, const struct smb_hdr *smb) -{ - return mid =3D=3D le16_to_cpu(smb->Mid); -} =20 #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ =20 /* given a pointer to an smb_hdr, retrieve a void pointer to the ByteCount= */ static inline void * -BCC(struct smb_hdr *smb) +BCC(const struct smb_hdr *smb) { return (void *)smb + sizeof(*smb) + 2 * smb->WordCount; } @@ -329,9 +320,9 @@ BCC(struct smb_hdr *smb) =20 /* get the unconverted ByteCount for a SMB packet and return it */ static inline __u16 -get_bcc(struct smb_hdr *hdr) +get_bcc(const struct smb_hdr *hdr) { - __le16 *bc_ptr =3D (__le16 *)BCC(hdr); + const __le16 *bc_ptr =3D (__le16 *)BCC(hdr); =20 return get_unaligned_le16(bc_ptr); } @@ -345,6 +336,10 @@ put_bcc(__u16 count, struct smb_hdr *hdr) put_unaligned_le16(count, bc_ptr); } =20 +struct smb_message *cifs_find_mid(struct TCP_Server_Info *server, const st= ruct smb_hdr *shdr); +bool cifs_is_network_name_deleted(const struct smb_hdr *shdr, struct TCP_S= erver_Info *server); +int smb1_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); + #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ =20 #endif /* _SMB1PROTO_H */ diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index f38fe262c7ea..776d615f69d3 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -34,7 +34,7 @@ #define CIFS_MAX_IOV_SIZE 8 =20 static struct smb_message * -alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_Server_Info *server) +alloc_mid(const struct smb_hdr *shdr, struct TCP_Server_Info *server) { struct smb_message *smb; =20 @@ -47,13 +47,13 @@ alloc_mid(const struct smb_hdr *smb_buffer, struct TCP_= Server_Info *server) memset(smb, 0, sizeof(struct smb_message)); refcount_set(&smb->ref, 1); spin_lock_init(&smb->mid_lock); - smb->mid =3D get_mid(smb_buffer); - smb->pid =3D current->pid; - smb->command =3D cpu_to_le16(smb_buffer->Command); - cifs_dbg(FYI, "For smb_command %d\n", smb_buffer->Command); + smb->mid =3D le16_to_cpu(shdr->Mid); + smb->pid =3D current->pid; + smb->command =3D cpu_to_le16(shdr->Command); + cifs_dbg(FYI, "For smb_command %d\n", shdr->Command); /* easier to use jiffies */ /* when mid allocated can be before when sent */ - smb->when_alloc =3D jiffies; + smb->when_alloc =3D jiffies; =20 /* * The default is for the mid to be synchronous, so the @@ -156,18 +156,18 @@ int cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server, bool log_error) { - unsigned int len =3D smb->response_pdu_len; + unsigned int len =3D smb->resp_len; =20 - dump_smb(smb->resp_buf, min_t(u32, 92, len)); + dump_smb(smb->response, min_t(u32, 92, len)); =20 /* convert the length into a more usable form */ - if (server->sign) { + if (server->sign && !smb->sig_checked) { struct kvec iov[1]; int rc =3D 0; struct smb_rqst rqst =3D { .rq_iov =3D iov, .rq_nvec =3D ARRAY_SIZE(iov) }; =20 - iov[0].iov_base =3D smb->resp_buf; + iov[0].iov_base =3D smb->response; iov[0].iov_len =3D len; =20 rc =3D cifs_verify_signature(&rqst, server, @@ -270,194 +270,447 @@ SendReceive(const unsigned int xid, struct cifs_ses= *ses, return rc; } =20 +struct smb1_reassembly_section { + u32 asm_off; /* Offset within reassembled PDU */ + u16 asm_dis; /* Offset within reassembly section */ + u16 asm_cnt; /* Filled amount of reassembly section */ + u16 asm_len; /* Fully reassembled length */ + u16 seg_off; /* Segment offset within PDU */ + u16 seg_len; /* Segment len */ + char type; +}; + +struct smb1_reassembly { + u16 area_offset; + struct smb1_reassembly_section params, data; +}; + /* - return codes: - 0 not a transact2, or all data present - >0 transact2 with that much data missing - -EINVAL invalid transact2 + * Check the basic structure of a trans2-class message. + * + * | SMB1 hdr + * | Trans2 resp hdr } Accounted in WCT + * | Setup words[] } + * | BCC + * | Padding/Reserved2 } Accounted in BCC + * | content[] } */ -static int -check2ndT2(char *buf) +static bool smb1_trans2_check(const union smb1_response_hdr *h, + const struct cifs_receive *recv, + struct smb1_reassembly *t2) { - struct smb_hdr *pSMB =3D (struct smb_hdr *)buf; - struct smb_t2_rsp *pSMBt; - int remaining; - __u16 total_data_size, data_in_this_rsp; - - if (pSMB->Command !=3D SMB_COM_TRANSACTION2) - return 0; - - /* check for plausible wct, bcc and t2 data and parm sizes */ - /* check for parm and data offset going beyond end of smb */ - if (pSMB->WordCount !=3D 10) { /* coalesce_t2 depends on this */ - cifs_dbg(FYI, "Invalid transact2 word count\n"); - return -EINVAL; + const struct trans2_resp *t2_rsp =3D &h->trans2.t2_rsp; + const struct smb_hdr *shdr =3D &h->trans2.hdr; + unsigned int expected_bcc; + unsigned int area_offset =3D recv->hdr_len; + unsigned int area_len =3D get_bcc(shdr); + unsigned int area_top =3D area_offset + area_len; + + t2->area_offset =3D area_offset; + t2->params.asm_len =3D get_unaligned_le16(&t2_rsp->TotalParameterCount); + t2->params.asm_dis =3D get_unaligned_le16(&t2_rsp->ParameterDisplacement); + t2->params.seg_len =3D get_unaligned_le16(&t2_rsp->ParameterCount); + t2->params.seg_off =3D get_unaligned_le16(&t2_rsp->ParameterOffset); + t2->data.asm_len =3D get_unaligned_le16(&t2_rsp->TotalDataCount); + t2->data.asm_dis =3D get_unaligned_le16(&t2_rsp->DataDisplacement); + t2->data.seg_len =3D get_unaligned_le16(&t2_rsp->DataCount); + t2->data.seg_off =3D get_unaligned_le16(&t2_rsp->DataOffset); + + t2->params.asm_off =3D 0; + t2->params.asm_cnt =3D 0; + t2->params.type =3D 'P'; + t2->data.asm_off =3D 0; + t2->data.asm_cnt =3D 0; + t2->data.type =3D 'D'; + + if (t2->params.seg_len + t2->data.seg_len > area_len) + goto bad; + + if (t2->params.seg_len > 0) { + if (t2->params.seg_off < t2->area_offset || + t2->params.seg_off + t2->params.seg_len > area_top || + t2->params.asm_dis + t2->params.seg_len > t2->params.asm_len) + goto bad; } =20 - pSMBt =3D (struct smb_t2_rsp *)pSMB; + if (t2->data.seg_len > 0) { + if (t2->data.seg_off < t2->area_offset || + t2->data.seg_off + t2->data.seg_len > area_top || + t2->data.asm_dis + t2->data.seg_len > t2->data.asm_len) + goto bad; + } + if (t2->data.seg_len > 0 && + t2->params.seg_len > 0) { + /* Must not overlap. */ + if (t2->params.seg_off =3D=3D t2->data.seg_off) + goto bad; + if (t2->params.seg_off < t2->data.seg_off && + t2->params.seg_off + t2->params.seg_len > t2->data.seg_off) + goto bad; + if (t2->data.seg_off < t2->params.seg_off && + t2->data.seg_off + t2->data.seg_len > t2->params.seg_off) + goto bad; + } + expected_bcc =3D t2->params.asm_len + t2->data.asm_len; + if (expected_bcc > USHRT_MAX) { + cifs_dbg(FYI, "trans2: Expected BCC too large (%u)\n", expected_bcc); + return false; + } + if (t2->data.asm_len > CIFSMaxBufSize) { + cifs_dbg(VFS, "trans2: TotalDataSize %u is over maximum buffer %u\n", + t2->data.asm_len, CIFSMaxBufSize); + return false; + } + return true; =20 - total_data_size =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); - data_in_this_rsp =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); +bad: + cifs_dbg(FYI, "trans2: Bad resp layout: area %x-%x\n", + t2->area_offset, area_top); + cifs_dbg(FYI, "trans2: Params: len=3D%x/%x off=3D%x dis=3D%x\n", + t2->params.seg_len, t2->params.asm_len, + t2->params.seg_off, t2->params.asm_dis); + cifs_dbg(FYI, "trans2: Data: len=3D%x/%x off=3D%x dis=3D%x\n", + t2->data.seg_len, t2->data.asm_len, + t2->data.seg_off, t2->data.asm_dis); + return false; +} =20 - if (total_data_size =3D=3D data_in_this_rsp) - return 0; - else if (total_data_size < data_in_this_rsp) { - cifs_dbg(FYI, "total data %d smaller than data in frame %d\n", - total_data_size, data_in_this_rsp); - return -EINVAL; +/* + * Check follow-on messages for a Trans2 message. + */ +static int smb1_trans2_check2(struct TCP_Server_Info *server, + struct smb_message *smb, + struct cifs_receive *recv, + struct smb1_reassembly *t2) +{ + union smb1_response_hdr *target_h =3D smb->response; + struct smb_t2_rsp *target =3D &target_h->trans2; + int remaining_params, remaining_data; + unsigned int total_params, total_data; + + total_params =3D get_unaligned_le16(&target->t2_rsp.TotalParameterC= ount); + total_data =3D get_unaligned_le16(&target->t2_rsp.TotalDataCount); + t2->params.asm_cnt =3D get_unaligned_le16(&target->t2_rsp.ParameterCount); + t2->data.asm_cnt =3D get_unaligned_le16(&target->t2_rsp.DataCount); + + cifs_dbg(FYI, "trans2: params=3D%x/%x/%x data=3D%x/%x/%x\n", + t2->params.seg_len, t2->params.asm_cnt, t2->params.asm_len, + t2->data.seg_len, t2->data.asm_cnt, t2->data.asm_len); + + if (t2->params.asm_len !=3D total_params) + cifs_dbg(FYI, "trans2: Inconsistent TotalParameterCount %u!=3D%u\n", + t2->params.asm_len, total_params); + + if (t2->data.asm_len !=3D total_data) + cifs_dbg(FYI, "trans2: Inconsistent TotalDataCount %u!=3D%u\n", + t2->params.asm_len, total_data); + + remaining_params =3D t2->params.asm_len - t2->params.asm_cnt; + remaining_data =3D t2->data.asm_len - t2->data.asm_cnt; + + if (remaining_params < 0 || remaining_data < 0) { + pr_warn("trans2: Server sent too much: params=3D%u/%u data=3D%u/%u\n", + t2->params.asm_cnt, t2->params.asm_len, + t2->data.asm_cnt, t2->data.asm_len); + return -EPROTO; } =20 - remaining =3D total_data_size - data_in_this_rsp; - - cifs_dbg(FYI, "missing %d bytes from transact2, check next response\n", - remaining); - if (total_data_size > CIFSMaxBufSize) { - cifs_dbg(VFS, "TotalDataSize %d is over maximum buffer %d\n", - total_data_size, CIFSMaxBufSize); - return -EINVAL; + if (t2->params.seg_len > remaining_params || + t2->data.seg_len > remaining_data) { + pr_warn("trans2: Excessive addition: params=3D%u/%u/%u data=3D%u/%u/%u\n= ", + t2->params.seg_len, t2->params.asm_cnt, t2->params.asm_len, + t2->data.seg_len, t2->data.asm_cnt, t2->data.asm_len); + return -EPROTO; } - return remaining; + + return 0; } =20 -static int -coalesce_t2(char *second_buf, struct smb_hdr *target_hdr, unsigned int *pd= u_len) +/* + * Allocate an appropriately sized buffer for a reassembled Trans2 reply. + */ +static int smb1_trans2_alloc(struct TCP_Server_Info *server, + struct smb_message *smb, + struct cifs_receive *recv, + struct smb1_reassembly *t2) { - struct smb_t2_rsp *pSMBs =3D (struct smb_t2_rsp *)second_buf; - struct smb_t2_rsp *pSMBt =3D (struct smb_t2_rsp *)target_hdr; - char *data_area_of_tgt; - char *data_area_of_src; - int remaining; - unsigned int byte_count, total_in_tgt; - __u16 tgt_total_cnt, src_total_cnt, total_in_src; + union smb1_response_hdr *h =3D recv->response; + struct trans2_resp *rsp =3D &h->trans2.t2_rsp; + struct smb_hdr *shdr =3D &h->trans2.hdr; + unsigned int reasm_len; + u16 bcc; + + reasm_len =3D t2->area_offset; + /* Might need 1 byte of padding before the params */ + reasm_len +=3D t2->params.asm_len; + /* Might need 2 bytes of padding before the data */ + reasm_len +=3D t2->data.asm_len; + + if (reasm_len <=3D MAX_CIFS_SMALL_BUFFER_SIZE) { + /* Stick with the small buffer we're already using. */ + smb->response =3D server->smallbuf; + smb->resp_len =3D reasm_len; + server->smallbuf =3D NULL; + } else if (reasm_len <=3D CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) { + /* Switch to a large buffer. */ + smb->response =3D server->bigbuf; + smb->resp_len =3D reasm_len; + smb->large_buf =3D true; + memcpy(server->bigbuf, server->smallbuf, recv->extracted); + server->bigbuf =3D NULL; + recv->resp_buf_type =3D CIFS_LARGE_BUFFER; + } else { + /* Too big - could decant into a list of pages. */ + smb->error =3D -EMSGSIZE; + cifs_dbg(FYI, "%s: Message too big\n", __func__); + return -EMSGSIZE; + } =20 - src_total_cnt =3D get_unaligned_le16(&pSMBs->t2_rsp.TotalDataCount); - tgt_total_cnt =3D get_unaligned_le16(&pSMBt->t2_rsp.TotalDataCount); + h =3D smb->response; + shdr =3D &h->trans2.hdr; + rsp =3D &h->trans2.t2_rsp; =20 - if (tgt_total_cnt !=3D src_total_cnt) - cifs_dbg(FYI, "total data count of primary and secondary t2 differ sourc= e=3D%hu target=3D%hu\n", - src_total_cnt, tgt_total_cnt); + /* Fix up the BCC to the anticipated full amount. */ + bcc =3D t2->params.asm_len + t2->data.asm_len; + put_bcc(bcc, shdr); =20 - total_in_tgt =3D get_unaligned_le16(&pSMBt->t2_rsp.DataCount); + /* Lay out the parameter and data blocks appropriately. */ + rsp->ParameterOffset =3D cpu_to_le16(recv->hdr_len); + rsp->DataOffset =3D cpu_to_le16(recv->hdr_len + t2->params.asm_len); =20 - remaining =3D tgt_total_cnt - total_in_tgt; + recv->msg_len =3D reasm_len; + return 0; +} =20 - if (remaining < 0) { - cifs_dbg(FYI, "Server sent too much data. tgt_total_cnt=3D%hu total_in_t= gt=3D%u\n", - tgt_total_cnt, total_in_tgt); - return -EPROTO; - } +static bool smb1_trans2_extract(struct smb_message *smb, + struct cifs_receive *recv, + struct smb1_reassembly_section *a, + struct netfs_rxqueue *rxq) +{ + size_t got; =20 - if (remaining =3D=3D 0) { - /* nothing to do, ignore */ - cifs_dbg(FYI, "no more data remains\n"); - return 0; - } + if (a->seg_len =3D=3D 0) + return true; =20 - total_in_src =3D get_unaligned_le16(&pSMBs->t2_rsp.DataCount); - if (remaining < total_in_src) - cifs_dbg(FYI, "transact2 2nd response contains too much data\n"); + got =3D netfs_rxqueue_read(rxq, smb->response + a->asm_off, + a->seg_off, a->seg_len); + if (got !=3D a->seg_len) { + cifs_dbg(FYI, "trans2: copy_from_iter failed (%u bytes)\n", + rxq->qsize); + return false; + } + return true; +} =20 - /* find end of first SMB data area */ - data_area_of_tgt =3D (char *)&pSMBt->hdr.Protocol + - get_unaligned_le16(&pSMBt->t2_rsp.DataOffset); +/* + * Receive a Trans2-class message. These are potentially multipart and may + * need assembly. + * + * Returns 0 if the message is complete (for good or bad), 1 if further da= ta is + * expected and a negative error code otherwise. + */ +static int smb1_trans2_receive(struct TCP_Server_Info *server, + struct smb_message *smb, + struct cifs_receive *recv, + struct netfs_rxqueue *rxq) +{ + union smb1_response_hdr *target_h; + union smb1_response_hdr *h =3D recv->response; + struct smb1_reassembly t2; + struct trans2_resp *target; + int rc; =20 - /* validate target area */ - data_area_of_src =3D (char *)&pSMBs->hdr.Protocol + - get_unaligned_le16(&pSMBs->t2_rsp.DataOffset); + if (server->sign) { + rc =3D cifs_verify_trans_signature(server, recv, rxq, + smb->sequence_number); + if (rc < 0) { + cifs_dbg(FYI, "Signature check failed\n"); + } + smb->sig_checked =3D true; + } =20 - data_area_of_tgt +=3D total_in_tgt; + if (h->hdr.Status.CifsError !=3D 0 && + h->hdr.WordCount =3D=3D 0) { + smb->response =3D server->smallbuf; + smb->resp_len =3D recv->msg_len; + server->smallbuf =3D NULL; + return 0; + } =20 - total_in_tgt +=3D total_in_src; - /* is the result too big for the field? */ - if (total_in_tgt > USHRT_MAX) { - cifs_dbg(FYI, "coalesced DataCount too large (%u)\n", - total_in_tgt); - return -EPROTO; + if (!smb1_trans2_check(h, recv, &t2)) { + cifs_dbg(FYI, "Invalid transact2 layout\n"); + return -EINVAL; } - put_unaligned_le16(total_in_tgt, &pSMBt->t2_rsp.DataCount); =20 - /* fix up the BCC */ - byte_count =3D get_bcc(target_hdr); - byte_count +=3D total_in_src; - /* is the result too big for the field? */ - if (byte_count > USHRT_MAX) { - cifs_dbg(FYI, "coalesced BCC too large (%u)\n", byte_count); - return -EPROTO; + if (t2.params.seg_len < t2.params.asm_len || + t2.data.seg_len < t2.data.asm_len) { + smb->multiRsp =3D true; + cifs_dbg(FYI, "Trans2 incomplete (%u/%u, %u/%u), check next response\n", + t2.params.seg_len, t2.params.asm_len, + t2.data.seg_len, t2.data.asm_len); } - put_bcc(byte_count, target_hdr); =20 - byte_count =3D *pdu_len; - byte_count +=3D total_in_src; - /* don't allow buffer to overflow */ - if (byte_count > CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) { - cifs_dbg(FYI, "coalesced BCC exceeds buffer size (%u)\n", - byte_count); - return -ENOBUFS; + if (!smb->response) { + rc =3D smb1_trans2_alloc(server, smb, recv, &t2); + if (rc < 0) + return rc; + } else { + /* Check follow-on message. */ + rc =3D smb1_trans2_check2(server, smb, recv, &t2); + if (rc < 0) + return rc; } - *pdu_len =3D byte_count; =20 - /* copy second buffer into end of first buffer */ - memcpy(data_area_of_tgt, data_area_of_src, total_in_src); + /* Perform the reassembly. */ + target_h =3D smb->response; + target =3D &target_h->trans2.t2_rsp; + t2.params.asm_off =3D le16_to_cpup(&target->ParameterOffset) + t2.params.= asm_dis; + t2.data.asm_off =3D le16_to_cpup(&target->DataOffset) + t2.data.as= m_dis; =20 - if (remaining !=3D total_in_src) { - /* more responses to go */ - cifs_dbg(FYI, "waiting for more secondary responses\n"); - return 1; - } + if (!smb1_trans2_extract(smb, recv, &t2.params, rxq) || + !smb1_trans2_extract(smb, recv, &t2.data, rxq)) + return smb_EIO(smb_eio_trace_rx_trans2_extract); =20 - /* we are done */ - cifs_dbg(FYI, "found the last secondary response\n"); - return 0; + t2.params.asm_cnt +=3D t2.params.seg_len; + t2.data.asm_cnt +=3D t2.data.seg_len; + target->ParameterCount =3D cpu_to_le16(t2.params.asm_cnt); + target->DataCount =3D cpu_to_le16(t2.data.asm_cnt); + + /* All parts received or packet is malformed. */ + if (t2.params.asm_cnt =3D=3D t2.params.asm_len && + t2.data.asm_cnt =3D=3D t2.data.asm_len) { + smb->multiEnd =3D true; + return 0; + } + return 1; } =20 -bool -cifs_check_trans2(struct smb_message *smb, struct TCP_Server_Info *server, - char *buf, int malformed) +/* + * Check the size of the response header and extract the data area size. + */ +static bool smb1_check_response(struct cifs_receive *recv) { - if (malformed) - return false; - if (check2ndT2(buf) <=3D 0) - return false; - smb->multiRsp =3D true; - if (smb->resp_buf) { - /* merge response - fix up 1st*/ - malformed =3D coalesce_t2(buf, smb->resp_buf, &smb->response_pdu_len); - if (malformed > 0) - return true; - /* All parts received or packet is malformed. */ - smb->multiEnd =3D true; - dequeue_mid(server, smb, malformed); + const union smb1_response_hdr *h =3D recv->response; + const struct smb_hdr *shdr =3D &h->hdr; + unsigned bcc; + + if (shdr->Status.CifsError !=3D 0) return true; + + /* Assume, by default, that the data area is beyond the BCC-covered area.= */ + bcc =3D get_bcc(shdr); + if (recv->extracted + bcc < recv->msg_len) { + recv->data_offset =3D recv->extracted + bcc; + recv->data_len =3D recv->msg_len; } - if (!server->large_buf) { - /*FIXME: switch to already allocated largebuf?*/ - cifs_dbg(VFS, "1st trans2 resp needs bigbuf\n"); - } else { - /* Have first buffer */ - smb->resp_buf =3D buf; - smb->large_buf =3D true; - server->bigbuf =3D NULL; + + switch (shdr->Command) { + /* Trivial responses with WCT=3D0 and BCC=3D0 */ + case SMB_COM_CREATE_DIRECTORY: + case SMB_COM_DELETE_DIRECTORY: + case SMB_COM_CLOSE: + case SMB_COM_FLUSH: + case SMB_COM_DELETE: + case SMB_COM_RENAME: + case SMB_COM_SETATTR: + case SMB_COM_FIND_CLOSE2: + case SMB_COM_TREE_DISCONNECT: + case SMB_COM_NT_RENAME: + if (recv->hdr_len < sizeof(struct smb_hdr) + 2) + goto too_short; + break; + /* Trivial AndX responses with WCT=3D2 and BCC=3D0 */ + case SMB_COM_LOCKING_ANDX: + if (recv->hdr_len < sizeof(struct smb_hdr) + 6) + goto too_short; + break; + case SMB_COM_QUERY_INFORMATION: + if (recv->hdr_len < sizeof(struct smb_com_query_information_rsp)) + goto too_short; + break; + case SMB_COM_COPY: + if (recv->hdr_len < sizeof(struct smb_com_copy_rsp)) + goto too_short; + break; + case SMB_COM_ECHO: + if (recv->hdr_len < sizeof(struct smb_com_echo_rsp)) + goto too_short; + break; + case SMB_COM_OPEN_ANDX: + case SMB_COM_NT_CREATE_ANDX: + if (recv->hdr_len < sizeof(struct smb_com_open_rsp)) + goto too_short; + break; + case SMB_COM_READ_ANDX: + if (recv->hdr_len < sizeof(struct smb_com_read_rsp)) + goto too_short; + recv->data_offset =3D le16_to_cpu(h->read.DataOffset); + recv->data_len =3D le16_to_cpu(h->read.DataLengthHigh) << 16; + recv->data_len +=3D le16_to_cpu(h->read.DataLength); + break; + case SMB_COM_WRITE_ANDX: + if (recv->hdr_len < sizeof(struct smb_com_write_rsp)) + goto too_short; + break; + case SMB_COM_NEGOTIATE: + if (recv->hdr_len < offsetof(struct smb_negotiate_rsp, ByteCount)) + goto too_short; + break; + case SMB_COM_SESSION_SETUP_ANDX: + if (recv->hdr_len < sizeof(struct smb1_old_session_rsp)) + goto too_short; + break; + case SMB_COM_LOGOFF_ANDX: + if (recv->hdr_len < sizeof(struct smb_com_logoff_andx_rsp)) + goto too_short; + break; + case SMB_COM_TREE_CONNECT_ANDX: + if (recv->hdr_len < sizeof(struct smb_com_tconx_rsp)) + goto too_short; + break; + case SMB_COM_TRANSACTION2: + if (recv->hdr_len < sizeof(struct smb_t2_rsp)) + goto too_short; + break; + case SMB_COM_NT_TRANSACT: + if (recv->hdr_len < sizeof(struct smb_com_ntransact_rsp)) + goto too_short; + break; + case SMB_COM_TRANSACTION2_SECONDARY: + case SMB_COM_NT_TRANSACT_SECONDARY: + case SMB_COM_NT_CANCEL: + default: + cifs_dbg(VFS, "Unsupported command reply (%x)\n", shdr->Command); + break; } + return true; +too_short: + cifs_dbg(VFS, "Header too short (%x) for command (%x)\n", + recv->hdr_len, shdr->Command); + return false; } =20 -static int -check_smb_hdr(struct smb_hdr *smb) +static bool +check_smb_hdr(struct cifs_receive *recv) { + union smb1_response_hdr *h =3D recv->response; + struct smb_hdr *smb =3D &h->hdr; + /* does it have the right SMB "signature" ? */ if (*(__le32 *) smb->Protocol !=3D SMB1_PROTO_NUMBER) { cifs_dbg(VFS, "Bad protocol string signature header 0x%x\n", *(unsigned int *)smb->Protocol); - return 1; + return false; } =20 /* if it's a response then accept */ if (smb->Flags & SMBFLG_RESPONSE) - return 0; + return true; =20 /* only one valid case where server sends us request */ if (smb->Command =3D=3D SMB_COM_LOCKING_ANDX) - return 0; + return true; =20 /* * Windows NT server returns error response (e.g. STATUS_DELETE_PENDING @@ -465,90 +718,99 @@ check_smb_hdr(struct smb_hdr *smb) * for some TRANS2 requests without the RESPONSE flag set in header. */ if (smb->Command =3D=3D SMB_COM_TRANSACTION2 && smb->Status.CifsError != =3D 0) - return 0; + return true; =20 cifs_dbg(VFS, "Server sent request, not response. mid=3D%u\n", - get_mid(smb)); - return 1; + le16_to_cpu(smb->Mid)); + return false; } =20 -int -checkSMB(char *buf, unsigned int pdu_len, unsigned int total_read, - struct TCP_Server_Info *server) +/* + * Try and fix up a message that's too short even to contain a full BCC wo= rd + * and nothing else after the header. + */ +static int smb1_fix_up_short_header(struct cifs_receive *recv) { - struct smb_hdr *smb =3D (struct smb_hdr *)buf; - __u32 rfclen =3D pdu_len; - __u32 clc_len; /* calculated length */ - cifs_dbg(FYI, "checkSMB Length: 0x%x, smb_buf_length: 0x%x\n", - total_read, rfclen); - - /* is this frame too small to even get to a BCC? */ - if (total_read < 2 + sizeof(struct smb_hdr)) { - if ((total_read >=3D sizeof(struct smb_hdr) - 1) - && (smb->Status.CifsError !=3D 0)) { - /* it's an error return */ - smb->WordCount =3D 0; - /* some error cases do not return wct and bcc */ - return 0; - } else if ((total_read =3D=3D sizeof(struct smb_hdr) + 1) && - (smb->WordCount =3D=3D 0)) { - char *tmp =3D (char *)smb; - /* Need to work around a bug in two servers here */ - /* First, check if the part of bcc they sent was zero */ - if (tmp[sizeof(struct smb_hdr)] =3D=3D 0) { - /* some servers return only half of bcc - * on simple responses (wct, bcc both zero) - * in particular have seen this on - * ulogoffX and FindClose. This leaves - * one byte of bcc potentially uninitialized - */ - /* zero rest of bcc */ - tmp[sizeof(struct smb_hdr)+1] =3D 0; - return 0; - } - cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n"); - return smb_EIO1(smb_eio_trace_rx_inv_bcc, tmp[sizeof(struct smb_hdr)]); - } else { - cifs_dbg(VFS, "Length less than smb header size\n"); - return smb_EIO2(smb_eio_trace_rx_too_short, - total_read, smb->WordCount); + union smb1_response_hdr *h =3D recv->response; + + cifs_dbg(FYI, "%s: rfc1002 len: 0x%x\n", __func__, recv->msg_len); + + if (recv->msg_len < sizeof(struct smb_hdr) - 1) { + cifs_dbg(VFS, "Length less than smb header size\n"); + return smb_EIO1(smb_eio_trace_rx_too_short, recv->msg_len); + } + + if (h->hdr.Status.CifsError !=3D 0) { + /* It's an error return (some error cases do not return wct and + * bcc). + */ + goto reset_wct_and_bcc; + } + + if (recv->msg_len =3D=3D sizeof(struct smb_hdr) + 1 && + h->hdr.WordCount =3D=3D 0) { + /* Need to work around a bug in two servers here */ + /* First, check if the part of bcc they sent was zero */ + if (h->trivial_rsp.short_bcc =3D=3D 0) { + /* some servers return only half of bcc + * on simple responses (wct, bcc both zero) + * in particular have seen this on + * ulogoffX and FindClose. This leaves + * one byte of bcc potentially uninitialized + */ + goto reset_wct_and_bcc; } - } else if (total_read < sizeof(*smb) + 2 * smb->WordCount) { - cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n", - __func__, smb->WordCount); - return smb_EIO2(smb_eio_trace_rx_check_rsp, - total_read, 2 + sizeof(struct smb_hdr)); + cifs_dbg(VFS, "rcvd invalid byte count (bcc)\n"); + return smb_EIO1(smb_eio_trace_rx_inv_bcc, h->trivial_rsp.short_bcc); } =20 - /* otherwise, there is enough to get to the BCC */ - if (check_smb_hdr(smb)) - return smb_EIO1(smb_eio_trace_rx_rfc1002_magic, *(u32 *)smb->Protocol); - clc_len =3D smbCalcSize(smb); + cifs_dbg(VFS, "Length less than smb header size\n"); + return smb_EIO2(smb_eio_trace_rx_too_short, + recv->msg_len, le16_to_cpu(h->hdr.WordCount)); + +reset_wct_and_bcc: + h->trivial_rsp.hdr.WordCount =3D 0; + h->trivial_rsp.bcc =3D 0; + recv->msg_len =3D sizeof(h->trivial_rsp); + recv->hdr_len =3D recv->msg_len; + recv->extracted =3D recv->msg_len; + return 0; +} + +int +checkSMB(const struct TCP_Server_Info *server, struct cifs_receive *recv) +{ + union smb1_response_hdr *h =3D recv->response; + struct smb_hdr *smb =3D &h->hdr; =20 - if (rfclen !=3D total_read) { - cifs_dbg(VFS, "Length read does not match RFC1001 length %d/%d\n", - rfclen, total_read); + cifs_dbg(FYI, "checkSMB rfc1002 len: 0x%x\n", recv->msg_len); + + /* otherwise, there is enough to get to the BCC */ + if (!smb1_check_response(recv)) return smb_EIO2(smb_eio_trace_rx_check_rsp, - total_read, rfclen); - } + h->hdr.Command, + (le16_to_cpu(h->hdr.WordCount) << 16) | + h->trivial_rsp.short_bcc); =20 - if (rfclen !=3D clc_len) { - __u16 mid =3D get_mid(smb); + recv->calc_len =3D smbCalcSize(smb); + if (recv->msg_len !=3D recv->calc_len) { + __u16 mid =3D le16_to_cpu(smb->Mid); /* check if bcc wrapped around for large read responses */ - if ((rfclen > 64 * 1024) && (rfclen > clc_len)) { + if ((recv->msg_len > 64 * 1024) && + (recv->msg_len > recv->calc_len)) { /* check if lengths match mod 64K */ - if (((rfclen) & 0xFFFF) =3D=3D (clc_len & 0xFFFF)) + if ((recv->msg_len & 0xFFFF) =3D=3D (recv->calc_len & 0xFFFF)) return 0; /* bcc wrapped */ } cifs_dbg(FYI, "Calculated size %u vs length %u mismatch for mid=3D%u\n", - clc_len, rfclen, mid); + recv->calc_len, recv->msg_len, mid); =20 - if (rfclen < clc_len) { + if (recv->msg_len < recv->calc_len) { cifs_dbg(VFS, "RFC1001 size %u smaller than SMB for mid=3D%u\n", - rfclen, mid); + recv->msg_len, mid); return smb_EIO2(smb_eio_trace_rx_calc_len_too_big, - rfclen, clc_len); - } else if (rfclen > clc_len + 512) { + recv->msg_len, recv->calc_len); + } else if (recv->msg_len > recv->calc_len + 512) { /* * Some servers (Windows XP in particular) send more * data than the lengths in the SMB packet would @@ -559,10 +821,366 @@ checkSMB(char *buf, unsigned int pdu_len, unsigned i= nt total_read, * data to 512 bytes. */ cifs_dbg(VFS, "RFC1001 size %u more than 512 bytes larger than SMB for = mid=3D%u\n", - rfclen, mid); + recv->msg_len, mid); return smb_EIO2(smb_eio_trace_rx_overlong, - rfclen, clc_len + 512); + recv->msg_len, recv->calc_len + 512); } } return 0; } + +/* + * Copy data directly into prepared buffers. + * + * Ideally, we'd wait for sufficient data to be present in the queue before + * doing this, but that causes a performance loss as we don't receive data= and + * copy in parallel. + */ +static void smb1_copy_to_prepped_buffers(struct TCP_Server_Info *server, + struct smb_message *smb, + struct netfs_rxqueue *rxq, + struct cifs_receive *recv) +{ + const union smb1_response_hdr *h =3D recv->response; + struct iov_iter dest =3D smb->response_iter; + unsigned int to_copy, skip; + int rc; + + switch (h->hdr.Command) { + case SMB_COM_READ_ANDX: + to_copy =3D recv->data_len; + skip =3D recv->data_offset; + break; + default: + cifs_dbg(FYI, "%s: Non-Read copy\n", __func__); + return; + } + + if (skip < recv->hdr_len) { + if (skip !=3D 0) { + cifs_dbg(FYI, "%s: Read.DataOffset too small\n", __func__); + return; + } + skip =3D recv->hdr_len; + } + if (skip > recv->msg_len) { + cifs_dbg(FYI, "%s: Read.DataOffset beyond end\n", __func__); + return; + } + if (to_copy > recv->msg_len - skip) { + cifs_dbg(FYI, "%s: Read.DataLength beyond end\n", __func__); + return; + } + + if (!rxq->refillable) { + size_t got; + + got =3D netfs_rxqueue_read_iter(rxq, &dest, 0, to_copy); + if (got > 0) + netfs_rxqueue_discard(rxq, got); + recv->extracted +=3D got; + if (got < to_copy) { + cifs_dbg(VFS, "Copy to buffer was short %zu/%u\n", + got, to_copy); + recv->malformed =3D true; + } + return; + } + + while (to_copy) { + size_t got, part =3D umin(to_copy, rxq->qsize); + + got =3D netfs_rxqueue_read_iter(rxq, &dest, 0, part); + if (got > 0) { + recv->extracted +=3D got; + to_copy -=3D got; + netfs_rxqueue_discard(rxq, got); + } + if (!to_copy) + break; + if (got < part) { + cifs_dbg(VFS, "Copy to buffer was short %zu/%zu\n", + part, to_copy + part); + recv->malformed =3D true; + return; + } + + rc =3D smb_rxqueue_refill(server, rxq, 1); + if (rc < 0) { + recv->malformed =3D true; + return; + } + if (!rxq->qsize || !rxq->pdu_remain) + break; + } +} + +/* + * Parse an SMB1 message that's at least partially extracted. For success= ful + * reads, the data part is still in the receive queue or even not yet rece= ived. + */ +static void smb1_parse_one_message(struct TCP_Server_Info *server, + struct cifs_receive *recv, + struct netfs_rxqueue *rxq) +{ + union smb1_response_hdr *h =3D recv->response; + struct smb_message *smb; + struct smb_hdr *shdr =3D &h->hdr; + int rc; + + smb =3D cifs_find_mid(server, shdr); + if (!smb) { + cifs_dbg(VFS, "%s: Unqueued mid (%x)\n", + __func__, le16_to_cpu(shdr->Mid)); + rxq->msg_id =3D 0; + } else { + rxq->msg_id =3D 0; /* TODO: smb->debug_id */ + } + + /* No session expiry check. */ + /* No status pending check. */ + /* SMB1 does not use credits. */ + + if (cifs_is_network_name_deleted(&h->hdr, server)) + return; + + if (shdr->Status.CifsError !=3D 0) + recv->error =3D map_smb_to_linux_error(shdr, false); + + if (smb) { + size_t resp_len =3D 0; + + /* handle_mid */ + smb->status =3D shdr->Status.CifsError; + smb->error =3D recv->error; + smb->credits_received =3D smb->credits_consumed; + smb->resp_data_len =3D recv->data_len; + smb->resp_data_offset =3D recv->data_offset; + + trace_smb3_reply(smb, recv); + + if (h->hdr.Command =3D=3D SMB_COM_TRANSACTION2 && + !recv->malformed) { + /* Handle multipart trans2-class messages. */ + rc =3D smb1_trans2_receive(server, smb, recv, rxq); + if (rc =3D=3D 1) { + release_mid(server, smb); + return; /* Multipart, incomplete. */ + } + if (rc < 0) + recv->malformed =3D true; + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + goto extracted; + } + + /* For a successful Read, we grab everthing up to the base of + * the read region, but no more. This may include padding. + */ + resp_len =3D recv->msg_len; + if (smb->status !=3D 0) + smb->copy_to_bufs =3D false; + if (smb->copy_to_bufs) { + resp_len =3D recv->data_offset; + + rc =3D smb_rxqueue_refill(server, rxq, recv->data_offset); + if (rc < 0) { + recv->malformed =3D true; + goto extracted; + } + } + + if (resp_len <=3D MAX_CIFS_SMALL_BUFFER_SIZE) { + server->smallbuf =3D NULL; + } else if (resp_len <=3D CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) { + memcpy(server->bigbuf, server->smallbuf, recv->extracted); + recv->response =3D server->bigbuf; + server->bigbuf =3D NULL; + recv->resp_buf_type =3D CIFS_LARGE_BUFFER; + h =3D recv->response; + shdr =3D &h->hdr; + } else { + /* Too big - should parse directly from iterator. */ + smb->error =3D -EMSGSIZE; + cifs_dbg(FYI, "%s: Message too big\n", __func__); + } + + smb->response =3D recv->response; + smb->resp_len =3D resp_len; + + if (recv->extracted < recv->msg_len) { + size_t part =3D resp_len - recv->extracted, got; + + got =3D netfs_rxqueue_read(rxq, recv->response + recv->extracted, + recv->extracted, part); + recv->extracted +=3D got; + netfs_rxqueue_discard(rxq, recv->extracted); + + if (WARN_ON(got !=3D part)) { + smb->error =3D smb_EIO2(smb_eio_trace_rx_b_read_short, + got, part); + smb->resp_len =3D recv->extracted; + recv->malformed =3D true; + } else if (smb->copy_to_bufs) { + smb1_copy_to_prepped_buffers(server, smb, rxq, + recv); + } else if (rxq->pdu_remain) { + iov_iter_bvec_queue(&smb->response_iter, ITER_SOURCE, + rxq->take_from, rxq->take_slot, + rxq->take_offset, rxq->pdu_remain); + smb->response_data =3D rxq->take_from; + refcount_inc(&smb->response_data->ref); + } + } else { + netfs_rxqueue_discard(rxq, recv->extracted); + } + + extracted: + dequeue_mid(server, smb, recv->malformed); + mid_execute_callback(server, smb); + + release_mid(server, smb); + } else if (smb1_is_valid_oplock_break(h, recv->msg_len, server)) { + cifs_dbg(FYI, "Received oplock break\n"); + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + } else { + cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %= d\n", + atomic_read(&mid_count)); + cifs_dump_mem("Received Data is: ", h, HEADER_SIZE(server)); +#ifdef CONFIG_CIFS_DEBUG2 + cifs_dump_detail(server, recv); + cifs_dump_mids(server); +#endif /* CIFS_DEBUG2 */ + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + } +} + +/* + * Receive and parse a received SMB1 PDU. + * + * At this point all the data has been read, any transformation unapplied, + * decompression performed and some of it is stored in the receive queue + * (excerpt) without either the rfc1002, transform or compression headers, + * though some may yet to be received. + */ +static void smb1_parse_pdu(struct TCP_Server_Info *server, + struct netfs_rxqueue *rxq) +{ + union smb1_response_hdr *h; + struct smb_hdr *shdr; + unsigned int advance_get, part, got; + int rc; + + server->lstrp =3D jiffies; + + struct cifs_receive recv =3D { + .resp_buf_type =3D CIFS_SMALL_BUFFER, + .response =3D server->smallbuf, + .msg_len =3D rxq->pdu_remain, + }; + h =3D recv.response; + shdr =3D &h->hdr; + + /* We try to grab the header if we can, plus the BCC field, assuming it + * to be trivially placed (ie. WCT=3D=3D0). + * + * Now, it's possible for buggy servers to return less than the size of + * the header in certain cases, such as error cases, so we grab what + * there is of it and then fix up the short header. + */ + advance_get =3D umin(sizeof(h->trivial_rsp), rxq->pdu_remain); + + rc =3D smb_rxqueue_refill(server, rxq, advance_get); + if (rc < 0) + goto failed; + + got =3D netfs_rxqueue_read(rxq, recv.response, 0, advance_get); + if (got !=3D advance_get) { + cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", + rxq->qsize); + goto failed; + } + recv.extracted =3D advance_get; + + /* Validate the header and fix up the message if it's too small due to + * known server bugs. + */ + recv.hdr_len =3D umin(sizeof(*shdr), recv.msg_len); + if (recv.msg_len < sizeof(h->trivial_rsp)) { + rc =3D smb1_fix_up_short_header(&recv); + if (rc < 0) + goto bad; + } + + if (!check_smb_hdr(&recv)) + goto bad; + + /* Get the rest of the command-specific response header plus the BCC. */ + recv.hdr_len +=3D h->hdr.WordCount * 2 + 2; + if (recv.hdr_len > sizeof(*h)) { + cifs_dbg(VFS, "%s: can't read BCC due to invalid WordCount(%u)\n", + __func__, h->hdr.WordCount); + goto bad; + } + + /* If it's a successful read, then wait for the header. */ + if (shdr->Command =3D=3D SMB_COM_READ_ANDX && + shdr->Status.CifsError =3D=3D 0) + advance_get =3D recv.hdr_len; + else + advance_get =3D recv.msg_len; + + rc =3D smb_rxqueue_refill(server, rxq, advance_get); + if (rc < 0) + goto failed; + + part =3D recv.hdr_len - recv.extracted; + got =3D netfs_rxqueue_read(rxq, (void *)recv.response + recv.extracted, + recv.extracted, part); + if (got !=3D part) { + cifs_server_dbg(VFS, "rxqueue_read failed (%u bytes)\n", + rxq->qsize); + goto failed; + } + recv.extracted +=3D got; + + /* + * We've got the MID and the BCC. Now check to see if the rest of the + * header is OK. Note that we've only extracted up to and including + * the BCC at this point; everything else is either in the receive + * queue or still pending (i.e. for the data in a Read). + */ + rc =3D checkSMB(server, &recv); + if (rc) { + recv.malformed =3D true; + goto bad; + } + + smb1_parse_one_message(server, &recv, rxq); + +discard: + WARN(rxq->pdu_remain > 0, "pdu_remain=3D%x", rxq->pdu_remain); + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + return; + +bad: + /* + * 48 bytes is enough to display the header and a little bit into the + * payload for debugging purposes. + */ + cifs_dump_mem("Bad SMB: ", h, umin(recv.msg_len, 48)); +failed: + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + goto discard; +} + +/* + * Receive and parse an SMB1 PDU. We need to wait for data to come in unt= il we + * have enough and then we have to reverse transformations and perform + * decompression before we can fully parse the message contents. + */ +int smb1_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len) +{ + /* There are no transformations in SMB1. */ + smb1_parse_pdu(server, &server->rx_queue); + return 0; +} diff --git a/fs/smb/client/smb2inode.c b/fs/smb/client/smb2inode.c index 6c9c229b91f6..6789049db053 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -590,7 +590,7 @@ static int smb2_compound_op(const unsigned int xid, str= uct cifs_tcon *tcon, char *buf =3D rsp_iov[i + 1].iov_base; =20 if (buf && resp_buftype[i + 1] !=3D CIFS_NO_BUFFER) - rc =3D server->ops->map_error(buf, false); + rc =3D map_smb2_to_linux_error((struct smb2_hdr *)buf, false); else rc =3D tmp_rc; switch (cmds[i]) { diff --git a/fs/smb/client/smb2maperror.c b/fs/smb/client/smb2maperror.c index 9ed21f7b618c..e4ec8c777d78 100644 --- a/fs/smb/client/smb2maperror.c +++ b/fs/smb/client/smb2maperror.c @@ -47,9 +47,8 @@ static const struct status_to_posix_error *smb2_get_err_m= ap(__u32 smb2_status) } =20 int -map_smb2_to_linux_error(char *buf, bool log_err) +map_smb2_to_linux_error(const struct smb2_hdr *shdr, bool log_err) { - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; int rc =3D -EIO; __le32 smb2err =3D shdr->Status; const struct status_to_posix_error *err_map; diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 5c1d41baff7e..249606e5680e 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -20,7 +20,7 @@ #include "cached_dir.h" =20 static int -check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid) +check_smb2_hdr(const struct smb2_hdr *shdr, __u64 mid) { __u64 wire_mid =3D le64_to_cpu(shdr->MessageId); =20 @@ -58,38 +58,36 @@ check_smb2_hdr(struct smb2_hdr *shdr, __u64 mid) * Note that commands are defined in smb2pdu.h in le16 but the array belo= w is * indexed by command in host byte order */ -static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] =3D { - /* SMB2_NEGOTIATE */ cpu_to_le16(65), - /* SMB2_SESSION_SETUP */ cpu_to_le16(9), - /* SMB2_LOGOFF */ cpu_to_le16(4), - /* SMB2_TREE_CONNECT */ cpu_to_le16(16), - /* SMB2_TREE_DISCONNECT */ cpu_to_le16(4), - /* SMB2_CREATE */ cpu_to_le16(89), - /* SMB2_CLOSE */ cpu_to_le16(60), - /* SMB2_FLUSH */ cpu_to_le16(4), - /* SMB2_READ */ cpu_to_le16(17), - /* SMB2_WRITE */ cpu_to_le16(17), - /* SMB2_LOCK */ cpu_to_le16(4), - /* SMB2_IOCTL */ cpu_to_le16(49), +static const u16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] =3D { + [SMB2_NEGOTIATE] =3D 65, + [SMB2_SESSION_SETUP] =3D 9, + [SMB2_LOGOFF] =3D 4, + [SMB2_TREE_CONNECT] =3D 16, + [SMB2_TREE_DISCONNECT] =3D 4, + [SMB2_CREATE] =3D 89, + [SMB2_CLOSE] =3D 60, + [SMB2_FLUSH] =3D 4, + [SMB2_READ] =3D 17, + [SMB2_WRITE] =3D 17, + [SMB2_LOCK] =3D 4, + [SMB2_IOCTL] =3D 49, /* BB CHECK this ... not listed in documentation */ - /* SMB2_CANCEL */ cpu_to_le16(0), - /* SMB2_ECHO */ cpu_to_le16(4), - /* SMB2_QUERY_DIRECTORY */ cpu_to_le16(9), - /* SMB2_CHANGE_NOTIFY */ cpu_to_le16(9), - /* SMB2_QUERY_INFO */ cpu_to_le16(9), - /* SMB2_SET_INFO */ cpu_to_le16(2), - /* BB FIXME can also be 44 for lease break */ - /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24) + [SMB2_CANCEL] =3D 0, + [SMB2_ECHO] =3D 4, + [SMB2_QUERY_DIRECTORY] =3D 9, + [SMB2_CHANGE_NOTIFY] =3D 9, + [SMB2_QUERY_INFO] =3D 9, + [SMB2_SET_INFO] =3D 2, + [SMB2_OPLOCK_BREAK] =3D 24, /* BB FIXME can also be 44 for lease break */ }; =20 #define SMB311_NEGPROT_BASE_SIZE (sizeof(struct smb2_hdr) + sizeof(struct = smb2_negotiate_rsp)) =20 -static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, __u32 len, - __u32 non_ctxlen) +static __u32 get_neg_ctxt_len(const struct smb2_negotiate_rsp *pneg_rsp, + __u32 len, __u32 non_ctxlen) { __u16 neg_count; __u32 nc_offset, size_of_pad_before_neg_ctxts; - struct smb2_negotiate_rsp *pneg_rsp =3D (struct smb2_negotiate_rsp *)hdr; =20 /* Negotiate contexts are only valid for latest dialect SMB3.11 */ neg_count =3D le16_to_cpu(pneg_rsp->NegotiateContextCount); @@ -133,47 +131,27 @@ static __u32 get_neg_ctxt_len(struct smb2_hdr *hdr, _= _u32 len, return (len - nc_offset) + size_of_pad_before_neg_ctxts; } =20 +/* + * Check the sizes of various parts of the message and retrieve the data a= rea + * offset and length if there is one. + */ int -smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len, - struct TCP_Server_Info *server) +smb2_check_message(struct TCP_Server_Info *server, struct cifs_receive *re= cv) { - struct TCP_Server_Info *pserver; - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; - struct smb2_pdu *pdu =3D (struct smb2_pdu *)shdr; + union smb2_response_hdr *h =3D recv->response; + struct smb2_hdr *shdr =3D &h->hdr; + const unsigned int len =3D recv->msg_len; int hdr_size =3D sizeof(struct smb2_hdr); int pdu_size =3D sizeof(struct smb2_pdu); - int command; __u32 calc_len; /* calculated length */ __u64 mid; - - /* If server is a channel, select the primary channel */ - pserver =3D SERVER_IS_CHAN(server) ? server->primary_server : server; + u16 command; + u16 ssize2 =3D le16_to_cpu(h->StructureSize2); =20 /* * Add function to do table lookup of StructureSize by command * ie Validate the wct via smb2_struct_sizes table above */ - if (shdr->ProtocolId =3D=3D SMB2_TRANSFORM_PROTO_NUM) { - struct smb2_transform_hdr *thdr =3D - (struct smb2_transform_hdr *)buf; - struct cifs_ses *ses =3D NULL; - struct cifs_ses *iter; - - /* decrypt frame now that it is completely read in */ - spin_lock(&cifs_tcp_ses_lock); - list_for_each_entry(iter, &pserver->smb_ses_list, smb_ses_list) { - if (iter->Suid =3D=3D le64_to_cpu(thdr->SessionId)) { - ses =3D iter; - break; - } - } - spin_unlock(&cifs_tcp_ses_lock); - if (!ses) { - cifs_dbg(VFS, "no decryption - session id not found\n"); - return 1; - } - } - mid =3D le64_to_cpu(shdr->MessageId); if (check_smb2_hdr(shdr, mid)) return 1; @@ -193,7 +171,7 @@ smb2_check_message(char *buf, unsigned int pdu_len, uns= igned int len, if (len < pdu_size) { if ((len >=3D hdr_size) && (shdr->Status !=3D 0)) { - pdu->StructureSize2 =3D 0; + h->StructureSize2 =3D 0; /* * As with SMB/CIFS, on some error cases servers may * not return wct properly @@ -204,31 +182,32 @@ smb2_check_message(char *buf, unsigned int pdu_len, u= nsigned int len, } return 1; } - if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) { - cifs_dbg(VFS, "SMB length greater than maximum, mid=3D%llu\n", - mid); + if (len > CIFSMaxBufSize + MAX_SMB2_HDR_SIZE && + command !=3D SMB2_READ_HE) { + cifs_dbg(VFS, "SMB length (%u) greater than maximum (%u), mid=3D%llu\n", + len, CIFSMaxBufSize + MAX_SMB2_HDR_SIZE, mid); return 1; } =20 - if (smb2_rsp_struct_sizes[command] !=3D pdu->StructureSize2) { - if (command !=3D SMB2_OPLOCK_BREAK_HE && (shdr->Status =3D=3D 0 || - pdu->StructureSize2 !=3D SMB2_ERROR_STRUCTURE_SIZE2_LE)) { + if (ssize2 !=3D smb2_rsp_struct_sizes[command]) { + if (command !=3D SMB2_OPLOCK_BREAK_HE && + (shdr->Status =3D=3D 0 || ssize2 !=3D SMB2_ERROR_STRUCTURE_SIZE2)) { /* error packets have 9 byte structure size */ cifs_dbg(VFS, "Invalid response size %u for command %d\n", - le16_to_cpu(pdu->StructureSize2), command); + ssize2, command); return 1; } else if (command =3D=3D SMB2_OPLOCK_BREAK_HE && (shdr->Status =3D=3D 0) - && (le16_to_cpu(pdu->StructureSize2) !=3D 44) - && (le16_to_cpu(pdu->StructureSize2) !=3D 36)) { + && (ssize2 !=3D 44) + && (ssize2 !=3D 36)) { /* special case for SMB2.1 lease break message */ cifs_dbg(VFS, "Invalid response size %d for oplock break\n", - le16_to_cpu(pdu->StructureSize2)); + ssize2); return 1; } } =20 - calc_len =3D smb2_calc_size(buf); + smb2_calc_size(recv); =20 /* For SMB2_IOCTL, OutputOffset and OutputLength are optional, so might * be 0, and not a real miscalculation */ @@ -236,7 +215,7 @@ smb2_check_message(char *buf, unsigned int pdu_len, uns= igned int len, return 0; =20 if (command =3D=3D SMB2_NEGOTIATE_HE) - calc_len +=3D get_neg_ctxt_len(shdr, len, calc_len); + calc_len +=3D get_neg_ctxt_len(&h->neg, len, calc_len); =20 if (len !=3D calc_len) { /* create failed on symlink */ @@ -288,25 +267,25 @@ smb2_check_message(char *buf, unsigned int pdu_len, u= nsigned int len, * with no variable length info, show an offset of zero for the offset fie= ld. */ static const bool has_smb2_data_area[NUMBER_OF_SMB2_COMMANDS] =3D { - /* SMB2_NEGOTIATE */ true, - /* SMB2_SESSION_SETUP */ true, - /* SMB2_LOGOFF */ false, - /* SMB2_TREE_CONNECT */ false, - /* SMB2_TREE_DISCONNECT */ false, - /* SMB2_CREATE */ true, - /* SMB2_CLOSE */ false, - /* SMB2_FLUSH */ false, - /* SMB2_READ */ true, - /* SMB2_WRITE */ false, - /* SMB2_LOCK */ false, - /* SMB2_IOCTL */ true, - /* SMB2_CANCEL */ false, /* BB CHECK this not listed in documentation */ - /* SMB2_ECHO */ false, - /* SMB2_QUERY_DIRECTORY */ true, - /* SMB2_CHANGE_NOTIFY */ true, - /* SMB2_QUERY_INFO */ true, - /* SMB2_SET_INFO */ false, - /* SMB2_OPLOCK_BREAK */ false + [SMB2_NEGOTIATE_HE] =3D true, + [SMB2_SESSION_SETUP_HE] =3D true, + [SMB2_LOGOFF_HE] =3D false, + [SMB2_TREE_CONNECT_HE] =3D false, + [SMB2_TREE_DISCONNECT_HE] =3D false, + [SMB2_CREATE_HE] =3D true, + [SMB2_CLOSE_HE] =3D false, + [SMB2_FLUSH_HE] =3D false, + [SMB2_READ_HE] =3D true, + [SMB2_WRITE_HE] =3D false, + [SMB2_LOCK_HE] =3D false, + [SMB2_IOCTL_HE] =3D true, + [SMB2_CANCEL_HE] =3D false, /* BB CHECK this not listed in documentation= */ + [SMB2_ECHO_HE] =3D false, + [SMB2_QUERY_DIRECTORY_HE] =3D true, + [SMB2_CHANGE_NOTIFY_HE] =3D true, + [SMB2_QUERY_INFO_HE] =3D true, + [SMB2_SET_INFO_HE] =3D false, + [SMB2_OPLOCK_BREAK_HE] =3D false, }; =20 /* @@ -314,18 +293,19 @@ static const bool has_smb2_data_area[NUMBER_OF_SMB2_C= OMMANDS] =3D { * area and the offset to it (from the beginning of the smb are also retur= ned. */ char * -smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr) +smb2_get_data_area_len(struct cifs_receive *recv) { - const int max_off =3D 4096; - const int max_len =3D 128 * 1024; + const union smb2_response_hdr *h =3D recv->response; + const struct smb2_hdr *shdr =3D &h->hdr; + u16 command =3D le16_to_cpu(shdr->Command); + int off, len; =20 - *off =3D 0; - *len =3D 0; + recv->data_offset =3D 0; + recv->data_len =3D 0; =20 /* error responses do not have data area */ if (shdr->Status && shdr->Status !=3D STATUS_MORE_PROCESSING_REQUIRED && - (((struct smb2_err_rsp *)shdr)->StructureSize) =3D=3D - SMB2_ERROR_STRUCTURE_SIZE2_LE) + h->StructureSize2 =3D=3D SMB2_ERROR_STRUCTURE_SIZE2_LE) return NULL; =20 /* @@ -333,53 +313,49 @@ smb2_get_data_area_len(int *off, int *len, struct smb= 2_hdr *shdr) * of the data buffer offset and data buffer length for the particular * command. */ - switch (shdr->Command) { - case SMB2_NEGOTIATE: - *off =3D le16_to_cpu( - ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferOffset); - *len =3D le16_to_cpu( - ((struct smb2_negotiate_rsp *)shdr)->SecurityBufferLength); + switch (command) { + case SMB2_NEGOTIATE_HE: + off =3D le16_to_cpu(h->neg.SecurityBufferOffset); + len =3D le16_to_cpu(h->neg.SecurityBufferLength); break; - case SMB2_SESSION_SETUP: - *off =3D le16_to_cpu( - ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferOffset); - *len =3D le16_to_cpu( - ((struct smb2_sess_setup_rsp *)shdr)->SecurityBufferLength); + case SMB2_SESSION_SETUP_HE: + off =3D le16_to_cpu(h->sess.SecurityBufferOffset); + len =3D le16_to_cpu(h->sess.SecurityBufferLength); break; - case SMB2_CREATE: - *off =3D le32_to_cpu( - ((struct smb2_create_rsp *)shdr)->CreateContextsOffset); - *len =3D le32_to_cpu( - ((struct smb2_create_rsp *)shdr)->CreateContextsLength); + case SMB2_CREATE_HE: + off =3D le32_to_cpu(h->create.CreateContextsOffset); + len =3D le32_to_cpu(h->create.CreateContextsLength); break; - case SMB2_QUERY_INFO: - *off =3D le16_to_cpu( - ((struct smb2_query_info_rsp *)shdr)->OutputBufferOffset); - *len =3D le32_to_cpu( - ((struct smb2_query_info_rsp *)shdr)->OutputBufferLength); + case SMB2_QUERY_INFO_HE: + off =3D le16_to_cpu(h->qinfo.OutputBufferOffset); + len =3D le32_to_cpu(h->qinfo.OutputBufferLength); break; - case SMB2_READ: + case SMB2_READ_HE: /* TODO: is this a bug ? */ - *off =3D ((struct smb2_read_rsp *)shdr)->DataOffset; - *len =3D le32_to_cpu(((struct smb2_read_rsp *)shdr)->DataLength); + off =3D h->read.DataOffset; + len =3D le32_to_cpu(h->read.DataLength); + if (off =3D=3D 0) { + /* + * win2k8 sometimes sends an offset of 0 when + * the read is beyond the EOF. Treat it as if + * the data starts just after the header. + */ + cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n", + __func__, off); + off =3D sizeof(h->read); + } break; - case SMB2_QUERY_DIRECTORY: - *off =3D le16_to_cpu( - ((struct smb2_query_directory_rsp *)shdr)->OutputBufferOffset); - *len =3D le32_to_cpu( - ((struct smb2_query_directory_rsp *)shdr)->OutputBufferLength); + case SMB2_QUERY_DIRECTORY_HE: + off =3D le16_to_cpu(h->qdir.OutputBufferOffset); + len =3D le32_to_cpu(h->qdir.OutputBufferLength); break; - case SMB2_IOCTL: - *off =3D le32_to_cpu( - ((struct smb2_ioctl_rsp *)shdr)->OutputOffset); - *len =3D le32_to_cpu( - ((struct smb2_ioctl_rsp *)shdr)->OutputCount); + case SMB2_IOCTL_HE: + off =3D le32_to_cpu(h->ioctl.OutputOffset); + len =3D le32_to_cpu(h->ioctl.OutputCount); break; - case SMB2_CHANGE_NOTIFY: - *off =3D le16_to_cpu( - ((struct smb2_change_notify_rsp *)shdr)->OutputBufferOffset); - *len =3D le32_to_cpu( - ((struct smb2_change_notify_rsp *)shdr)->OutputBufferLength); + case SMB2_CHANGE_NOTIFY_HE: + off =3D le16_to_cpu(h->change.OutputBufferOffset); + len =3D le32_to_cpu(h->change.OutputBufferLength); break; default: cifs_dbg(VFS, "no length check for command %d\n", le16_to_cpu(shdr->Comm= and)); @@ -390,19 +366,21 @@ smb2_get_data_area_len(int *off, int *len, struct smb= 2_hdr *shdr) * Invalid length or offset probably means data area is invalid, but * we have little choice but to ignore the data area in this case. */ - if (unlikely(*off < 0 || *off > max_off || - *len < 0 || *len > max_len)) { + if (unlikely(off < 0 || len < 0)) { cifs_dbg(VFS, "%s: invalid data area (off=3D%d len=3D%d)\n", - __func__, *off, *len); - *off =3D 0; - *len =3D 0; - } else if (*off =3D=3D 0) { - *len =3D 0; + __func__, off, len); + off =3D 0; + len =3D 0; + } else if (off =3D=3D 0) { + len =3D 0; } =20 /* return pointer to beginning of data area, ie offset from SMB start */ - if (*off > 0 && *len > 0) - return (char *)shdr + *off; + if (off > 0 && len > 0) { + recv->data_offset =3D off; + recv->data_len =3D len; + return (char *)shdr + off; + } return NULL; } =20 @@ -410,46 +388,37 @@ smb2_get_data_area_len(int *off, int *len, struct smb= 2_hdr *shdr) * Calculate the size of the SMB message based on the fixed header * portion, the number of word parameters and the data portion of the mess= age. */ -unsigned int -smb2_calc_size(void *buf) +void +smb2_calc_size(struct cifs_receive *recv) { - struct smb2_pdu *pdu =3D buf; - struct smb2_hdr *shdr =3D &pdu->hdr; - int offset; /* the offset from the beginning of SMB to data area */ - int data_length; /* the length of the variable length data area */ - /* Structure Size has already been checked to make sure it is 64 */ - int len =3D le16_to_cpu(shdr->StructureSize); + const union smb2_response_hdr *h =3D recv->response; + const struct smb2_hdr *shdr =3D &h->hdr; + u16 command =3D le16_to_cpu(shdr->Command); =20 - /* - * StructureSize2, ie length of fixed parameter area has already - * been checked to make sure it is the correct length. - */ - len +=3D le16_to_cpu(pdu->StructureSize2); + recv->calc_len =3D recv->hdr_len; + WARN_ON_ONCE(!recv->calc_len); =20 - if (has_smb2_data_area[le16_to_cpu(shdr->Command)] =3D=3D false) + if (command >=3D ARRAY_SIZE(has_smb2_data_area) || + has_smb2_data_area[command] =3D=3D false) goto calc_size_exit; =20 - smb2_get_data_area_len(&offset, &data_length, shdr); - cifs_dbg(FYI, "SMB2 data length %d offset %d\n", data_length, offset); + smb2_get_data_area_len(recv); + cifs_dbg(FYI, "SMB2 data length %d offset %d\n", + recv->data_len, recv->data_offset); =20 - if (data_length > 0) { - /* - * Check to make sure that data area begins after fixed area, - * Note that last byte of the fixed area is part of data area - * for some commands, typically those with odd StructureSize, - * so we must add one to the calculation. - */ - if (offset + 1 < len) { + if (recv->data_len > 0) { + /* Check to make sure that data area begins after fixed area. */ + if (recv->data_offset < recv->hdr_len) { cifs_dbg(VFS, "data area offset %d overlaps SMB2 header %d\n", - offset + 1, len); - data_length =3D 0; - } else { - len =3D offset + data_length; + recv->data_offset, recv->hdr_len); + recv->data_offset =3D 0; + recv->data_len =3D 0; + goto calc_size_exit; } + recv->calc_len =3D recv->data_offset + recv->data_len; } calc_size_exit: - cifs_dbg(FYI, "SMB2 len %d\n", len); - return len; + cifs_dbg(FYI, "SMB2 len %d\n", recv->calc_len); } =20 /* Note: caller must free return buffer */ @@ -598,10 +567,11 @@ smb2_tcon_find_pending_open_lease(struct cifs_tcon *t= con, return found; } =20 -static bool -smb2_is_valid_lease_break(char *buffer, struct TCP_Server_Info *server) +static void +smb2_is_valid_lease_break(struct TCP_Server_Info *server, + union smb2_response_hdr *h) { - struct smb2_lease_break *rsp =3D (struct smb2_lease_break *)buffer; + struct smb2_lease_break *rsp =3D &h->lease; struct TCP_Server_Info *pserver; struct cifs_ses *ses; struct cifs_tcon *tcon; @@ -633,7 +603,7 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Serv= er_Info *server) if (smb2_tcon_has_lease(tcon, rsp)) { spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); - return true; + return; } open =3D smb2_tcon_find_pending_open_lease(tcon, rsp); @@ -649,13 +619,13 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Se= rver_Info *server) smb2_queue_pending_open_break(tlink, lease_key, rsp->NewLeaseState); - return true; + return; } spin_unlock(&tcon->open_file_lock); =20 if (cached_dir_lease_break(tcon, rsp->LeaseKey)) { spin_unlock(&cifs_tcp_ses_lock); - return true; + return; } } } @@ -669,30 +639,27 @@ smb2_is_valid_lease_break(char *buffer, struct TCP_Se= rver_Info *server) *((u64 *)rsp->LeaseKey), *((u64 *)&rsp->LeaseKey[8])); =20 - return false; } =20 -bool -smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *server) +void +smb2_is_valid_oplock_break(struct TCP_Server_Info *server, + union smb2_response_hdr *h) { - struct smb2_oplock_break *rsp =3D (struct smb2_oplock_break *)buffer; + struct smb2_oplock_break *rsp =3D &h->oplock; struct TCP_Server_Info *pserver; struct cifs_ses *ses; struct cifs_tcon *tcon; struct cifsInodeInfo *cinode; struct cifsFileInfo *cfile; + u16 ssize2 =3D le16_to_cpu(h->StructureSize2); =20 cifs_dbg(FYI, "Checking for oplock break\n"); =20 - if (rsp->hdr.Command !=3D SMB2_OPLOCK_BREAK) - return false; - - if (rsp->StructureSize !=3D - smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { - if (le16_to_cpu(rsp->StructureSize) =3D=3D 44) - return smb2_is_valid_lease_break(buffer, server); - else - return false; + if (ssize2 !=3D smb2_rsp_struct_sizes[SMB2_OPLOCK_BREAK_HE]) { + if (ssize2 =3D=3D 44) + return smb2_is_valid_lease_break(server, h); + WARN(1, "Invalid oplock break 0x%x\n", ssize2); + return; } =20 cifs_dbg(FYI, "oplock level 0x%x\n", rsp->OplockLevel); @@ -738,7 +705,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Ser= ver_Info *server) =20 spin_unlock(&tcon->open_file_lock); spin_unlock(&cifs_tcp_ses_lock); - return true; + return; } spin_unlock(&tcon->open_file_lock); } @@ -748,8 +715,7 @@ smb2_is_valid_oplock_break(char *buffer, struct TCP_Ser= ver_Info *server) trace_smb3_oplock_not_found(0 /* no xid */, rsp->PersistentFid, le32_to_cpu(rsp->hdr.Id.SyncId.TreeId), le64_to_cpu(rsp->hdr.SessionId)); - - return true; + return; } =20 void @@ -845,8 +811,8 @@ smb2_handle_cancelled_close(struct cifs_tcon *tcon, __u= 64 persistent_fid, int smb2_handle_cancelled_mid(struct smb_message *smb, struct TCP_Server_Info = *server) { - struct smb2_hdr *hdr =3D smb->resp_buf; - struct smb2_create_rsp *rsp =3D smb->resp_buf; + struct smb2_hdr *hdr =3D smb->response; + struct smb2_create_rsp *rsp =3D smb->response; struct cifs_tcon *tcon; int rc; =20 diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 10bb0fe6b77b..3c30417a3ea6 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include "cifsfs.h" #include "cifsglob.h" @@ -379,6 +380,28 @@ smb2_adjust_credits(struct TCP_Server_Info *server, return 0; } =20 +void +smb2_add_credits_from_hdr(struct smb2_hdr *shdr, struct TCP_Server_Info *s= erver) +{ + int scredits, in_flight; + + if (shdr->CreditRequest) { + spin_lock(&server->req_lock); + server->credits +=3D le16_to_cpu(shdr->CreditRequest); + scredits =3D server->credits; + in_flight =3D server->in_flight; + spin_unlock(&server->req_lock); + wake_up(&server->request_q); + + trace_smb3_hdr_credits(server->current_mid, + server->conn_id, server->hostname, scredits, + le16_to_cpu(shdr->CreditRequest), in_flight); + cifs_server_dbg(FYI, "%s: added %u credits total=3D%d\n", + __func__, le16_to_cpu(shdr->CreditRequest), + scredits); + } +} + static __u64 smb2_get_next_mid(struct TCP_Server_Info *server) { @@ -399,12 +422,11 @@ smb2_revert_current_mid(struct TCP_Server_Info *serve= r, const unsigned int val) spin_unlock(&server->mid_counter_lock); } =20 -static struct smb_message * -__smb2_find_mid(struct TCP_Server_Info *server, char *buf, bool dequeue) +struct smb_message * +smb2_find_mid(struct TCP_Server_Info *server, struct smb2_hdr *shdr, bool = dequeue) { struct smb_message *smb; - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; - __u64 wire_mid =3D le64_to_cpu(shdr->MessageId); + u64 wire_mid =3D le64_to_cpu(shdr->MessageId); =20 if (shdr->ProtocolId =3D=3D SMB2_TRANSFORM_PROTO_NUM) { cifs_server_dbg(VFS, "Encrypted frame parsing not supported yet\n"); @@ -429,33 +451,63 @@ __smb2_find_mid(struct TCP_Server_Info *server, char = *buf, bool dequeue) return NULL; } =20 -static struct smb_message * -smb2_find_mid(struct TCP_Server_Info *server, char *buf) +#ifdef CONFIG_CIFS_DEBUG2 +void +smb2_dump_detail(struct TCP_Server_Info *server, const struct cifs_receive= *recv) { - return __smb2_find_mid(server, buf, false); -} + const union smb2_response_hdr *h =3D recv->response; + const struct smb2_hdr *shdr =3D &h->hdr; =20 -static struct smb_message * -smb2_find_dequeue_mid(struct TCP_Server_Info *server, char *buf) -{ - return __smb2_find_mid(server, buf, true); + cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", + shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId, + shdr->Id.SyncId.ProcessId); + if (recv->malformed) + cifs_server_dbg(VFS, "smb buf %p len %u\n", + recv->response, recv->calc_len); } =20 -static void -smb2_dump_detail(void *buf, size_t buf_len, struct TCP_Server_Info *server) +void smb2_dump_mids(struct TCP_Server_Info *server) { -#ifdef CONFIG_CIFS_DEBUG2 - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; + struct smb_message *smb; =20 - cifs_server_dbg(VFS, "Cmd: %d Err: 0x%x Flags: 0x%x Mid: %llu Pid: %d\n", - shdr->Command, shdr->Status, shdr->Flags, shdr->MessageId, - shdr->Id.SyncId.ProcessId); - if (!server->ops->check_message(buf, buf_len, server->total_read, server)= ) { - cifs_server_dbg(VFS, "smb buf %p len %u\n", buf, - server->ops->calc_smb_size(buf)); + if (server =3D=3D NULL) + return; + + cifs_dbg(VFS, "Dump pending requests:\n"); + spin_lock(&server->mid_queue_lock); + list_for_each_entry(smb, &server->pending_mid_q, qhead) { + struct cifs_receive recv =3D { + .response =3D smb->response, + .msg_len =3D smb->resp_len, + .error =3D smb->error, + .data_len =3D smb->resp_data_len, + .data_offset =3D smb->resp_data_offset, + }; + + cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", + smb->mid_state, + smb->command, + smb->pid, + smb->callback_data, + smb->mid); +#ifdef CONFIG_CIFS_STATS2 + cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", + smb->large_buf, + smb->response, + smb->when_received, + jiffies); +#endif /* STATS2 */ + cifs_dbg(VFS, "IsMult: %d IsEnd: %d\n", + smb->multiRsp, smb->multiEnd); + if (recv.response) { + smb2_dump_detail(server, &recv); + cifs_dump_mem("existing buf: ", + recv.response, umin(recv.msg_len, 62)); + } } -#endif + spin_unlock(&server->mid_queue_lock); } +#endif /* CONFIG_CIFS_DEBUG2 */ =20 static bool smb2_need_neg(struct TCP_Server_Info *server) @@ -2074,26 +2126,6 @@ smb2_flush_file(const unsigned int xid, struct cifs_= tcon *tcon, return SMB2_flush(xid, tcon, fid->persistent_fid, fid->volatile_fid); } =20 -static unsigned int -smb2_read_data_offset(char *buf) -{ - struct smb2_read_rsp *rsp =3D (struct smb2_read_rsp *)buf; - - return rsp->DataOffset; -} - -static unsigned int -smb2_read_data_length(char *buf, bool in_remaining) -{ - struct smb2_read_rsp *rsp =3D (struct smb2_read_rsp *)buf; - - if (in_remaining) - return le32_to_cpu(rsp->DataRemaining); - - return le32_to_cpu(rsp->DataLength); -} - - static int smb2_sync_read(const unsigned int xid, struct cifs_fid *pfid, struct cifs_io_parms *parms, unsigned int *bytes_read, @@ -2610,15 +2642,11 @@ smb2_close_dir(const unsigned int xid, struct cifs_= tcon *tcon, * If we negotiate SMB2 protocol and get STATUS_PENDING - update * the number of credits and return true. Otherwise - return false. */ -static bool -smb2_is_status_pending(char *buf, struct TCP_Server_Info *server) +bool +smb2_status_pending(struct smb2_hdr *shdr, struct TCP_Server_Info *server) { - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; int scredits, in_flight; =20 - if (shdr->Status !=3D STATUS_PENDING) - return false; - if (shdr->CreditRequest) { spin_lock(&server->req_lock); server->credits +=3D le16_to_cpu(shdr->CreditRequest); @@ -2637,46 +2665,13 @@ smb2_is_status_pending(char *buf, struct TCP_Server= _Info *server) return true; } =20 -static bool -smb2_is_session_expired(char *buf) -{ - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; - - if (shdr->Status !=3D STATUS_NETWORK_SESSION_EXPIRED && - shdr->Status !=3D STATUS_USER_SESSION_DELETED) - return false; - - trace_smb3_ses_expired(le32_to_cpu(shdr->Id.SyncId.TreeId), - le64_to_cpu(shdr->SessionId), - le16_to_cpu(shdr->Command), - le64_to_cpu(shdr->MessageId)); - cifs_dbg(FYI, "Session expired or deleted\n"); - - return true; -} - -static bool -smb2_is_status_io_timeout(char *buf) -{ - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; - - if (shdr->Status =3D=3D STATUS_IO_TIMEOUT) - return true; - else - return false; -} - -static bool -smb2_is_network_name_deleted(char *buf, struct TCP_Server_Info *server) +bool +smb2_network_name_is_deleted(struct smb2_hdr *shdr, struct TCP_Server_Info= *server) { - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; struct TCP_Server_Info *pserver; struct cifs_ses *ses; struct cifs_tcon *tcon; =20 - if (shdr->Status !=3D STATUS_NETWORK_NAME_DELETED) - return false; - /* If server is a channel, select the primary channel */ pserver =3D SERVER_IS_CHAN(server) ? server->primary_server : server; =20 @@ -4430,7 +4425,7 @@ static void *smb2_get_aead_req(struct crypto_aead *tf= m, struct smb_rqst *rqst, return p; } =20 -static int +int smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8= *key) { struct TCP_Server_Info *pserver; @@ -4535,82 +4530,6 @@ encrypt_message(struct TCP_Server_Info *server, int = num_rqst, return rc; } =20 -/* - * Decrypt @rqst message. @rqst[0] has the following format: - * iov[0] - transform header (associate data), - * iov[1-N] - SMB2 header and pages - data to decrypt. - * On success return encrypted data in iov[1-N] and pages, leave iov[0] - * untouched. - */ -static int -decrypt_message(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst, struct crypto_aead *tfm) -{ - struct smb2_transform_hdr *tr_hdr =3D - (struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; - unsigned int assoc_data_len =3D sizeof(struct smb2_transform_hdr) - 20; - int rc =3D 0; - struct scatterlist *sg; - u8 sign[SMB2_SIGNATURE_SIZE] =3D {}; - u8 key[SMB3_ENC_DEC_KEY_SIZE]; - struct aead_request *req; - u8 *iv; - DECLARE_CRYPTO_WAIT(wait); - unsigned int crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); - void *creq; - - rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 0, key); - if (rc) { - cifs_server_dbg(FYI, "%s: Could not get decryption key. sid: 0x%llx\n", - __func__, le64_to_cpu(tr_hdr->SessionId)); - return rc; - } - - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_CCM) || - (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); - else - rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); - - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); - return rc; - } - - rc =3D crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); - return rc; - } - - creq =3D smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg); - if (IS_ERR(creq)) - return PTR_ERR(creq); - - memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); - crypt_len +=3D SMB2_SIGNATURE_SIZE; - - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || - (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); - else { - iv[0] =3D 3; - memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); - } - - aead_request_set_tfm(req, tfm); - aead_request_set_crypt(req, sg, sg, crypt_len, iv); - aead_request_set_ad(req, assoc_data_len); - - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &wait); - - rc =3D crypto_wait_req(crypto_aead_decrypt(req), &wait); - - kfree_sensitive(creq); - return rc; -} - /* * Copy data from an iterator to the pages in a bvec queue buffer. */ @@ -4701,591 +4620,6 @@ smb3_init_transform_rq(struct TCP_Server_Info *serv= er, int num_rqst, return rc; } =20 -static int -smb3_is_transform_hdr(void *buf) -{ - struct smb2_transform_hdr *trhdr =3D buf; - - return trhdr->ProtocolId =3D=3D SMB2_TRANSFORM_PROTO_NUM; -} - -static int -decrypt_raw_data(struct TCP_Server_Info *server, char *buf, - unsigned int buf_data_size, struct iov_iter *iter, - bool is_offloaded) -{ - struct crypto_aead *tfm; - struct smb_rqst rqst =3D {NULL}; - struct kvec iov[2]; - size_t iter_size =3D 0; - int rc; - - iov[0].iov_base =3D buf; - iov[0].iov_len =3D sizeof(struct smb2_transform_hdr); - iov[1].iov_base =3D buf + sizeof(struct smb2_transform_hdr); - iov[1].iov_len =3D buf_data_size; - - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 2; - if (iter) { - rqst.rq_iter =3D *iter; - iter_size =3D iov_iter_count(iter); - } - - if (is_offloaded) { - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || - (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - tfm =3D crypto_alloc_aead("gcm(aes)", 0, 0); - else - tfm =3D crypto_alloc_aead("ccm(aes)", 0, 0); - if (IS_ERR(tfm)) { - rc =3D PTR_ERR(tfm); - cifs_server_dbg(VFS, "%s: Failed alloc decrypt TFM, rc=3D%d\n", __func_= _, rc); - - return rc; - } - } else { - rc =3D smb3_crypto_aead_allocate(server); - if (unlikely(rc)) - return rc; - tfm =3D server->secmech.dec; - } - - rc =3D decrypt_message(server, 1, &rqst, tfm); - cifs_dbg(FYI, "Decrypt message returned %d\n", rc); - - if (is_offloaded) - crypto_free_aead(tfm); - - if (rc) - return rc; - - memmove(buf, iov[1].iov_base, buf_data_size); - - if (!is_offloaded) - server->total_read =3D buf_data_size + iter_size; - - return rc; -} - -static int -cifs_copy_bvecq_to_iter(struct bvecq *bq, size_t data_size, - size_t skip, struct iov_iter *iter) -{ - for (; bq; bq =3D bq->next) { - for (int s =3D 0; s < bq->nr_slots; s++) { - struct bio_vec *bv =3D &bq->bv[s]; - size_t n, len =3D umin(bv->bv_len - skip, data_size); - - n =3D copy_page_to_iter(bv->bv_page, bv->bv_offset + skip, len, iter); - if (n !=3D len) { - cifs_dbg(VFS, "%s: something went wrong\n", __func__); - return smb_EIO2(smb_eio_trace_rx_copy_to_iter, - n, len); - } - data_size -=3D n; - skip =3D 0; - } - } - - return 0; -} - -static int -handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb, - char *buf, unsigned int buf_len, struct bvecq *buffer, - unsigned int buffer_len, bool is_offloaded) -{ - unsigned int data_offset; - unsigned int data_len; - unsigned int end_off; - unsigned int cur_off; - unsigned int cur_page_idx; - unsigned int pad_len; - struct cifs_io_subrequest *rdata =3D smb->callback_data; - struct iov_iter iter; - struct smb2_hdr *shdr =3D (struct smb2_hdr *)buf; - size_t copied; - bool use_rdma_mr =3D false; - - if (shdr->Command !=3D SMB2_READ) { - cifs_server_dbg(VFS, "only big read responses are supported\n"); - return -EOPNOTSUPP; - } - - if (server->ops->is_session_expired && - server->ops->is_session_expired(buf)) { - if (!is_offloaded) - cifs_reconnect(server, true); - return -1; - } - - if (server->ops->is_status_pending && - server->ops->is_status_pending(buf, server)) - return -1; - - /* set up first two iov to get credits */ - rdata->iov[0].iov_base =3D buf; - rdata->iov[0].iov_len =3D 0; - rdata->iov[1].iov_base =3D buf; - rdata->iov[1].iov_len =3D - min_t(unsigned int, buf_len, server->vals->read_rsp_size); - cifs_dbg(FYI, "0: iov_base=3D%p iov_len=3D%zu\n", - rdata->iov[0].iov_base, rdata->iov[0].iov_len); - cifs_dbg(FYI, "1: iov_base=3D%p iov_len=3D%zu\n", - rdata->iov[1].iov_base, rdata->iov[1].iov_len); - - rdata->result =3D server->ops->map_error(buf, true); - if (rdata->result !=3D 0) { - cifs_dbg(FYI, "%s: server returned error %d\n", - __func__, rdata->result); - /* normal error on read response */ - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_RECEIVED; - else - dequeue_mid(server, smb, false); - return 0; - } - - data_offset =3D server->ops->read_data_offset(buf); -#ifdef CONFIG_CIFS_SMB_DIRECT - use_rdma_mr =3D rdata->mr; -#endif - data_len =3D server->ops->read_data_length(buf, use_rdma_mr); - - if (data_offset < server->vals->read_rsp_size) { - /* - * win2k8 sometimes sends an offset of 0 when the read - * is beyond the EOF. Treat it as if the data starts just after - * the header. - */ - cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n", - __func__, data_offset); - data_offset =3D server->vals->read_rsp_size; - } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) { - /* data_offset is beyond the end of smallbuf */ - cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", - __func__, data_offset); - rdata->result =3D smb_EIO1(smb_eio_trace_rx_overlong, data_offset); - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_MALFORMED; - else - dequeue_mid(server, smb, rdata->result); - return 0; - } - - pad_len =3D data_offset - server->vals->read_rsp_size; - - iov_iter_bvec_queue(&iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); - - if (buf_len <=3D data_offset) { - /* read response payload is in pages */ - cur_page_idx =3D pad_len / PAGE_SIZE; - cur_off =3D pad_len % PAGE_SIZE; - - if (cur_page_idx !=3D 0) { - /* data offset is beyond the 1st page of response */ - cifs_dbg(FYI, "%s: data offset (%u) beyond 1st page of response\n", - __func__, data_offset); - rdata->result =3D smb_EIO1(smb_eio_trace_rx_overpage, data_offset); - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_MALFORMED; - else - dequeue_mid(server, smb, rdata->result); - return 0; - } - - if (data_len > buffer_len - pad_len) { - /* data_len is corrupt -- discard frame */ - rdata->result =3D smb_EIO1(smb_eio_trace_rx_bad_datalen, data_len); - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_MALFORMED; - else - dequeue_mid(server, smb, rdata->result); - return 0; - } - - /* Copy the data to the output I/O iterator. */ - rdata->result =3D cifs_copy_bvecq_to_iter(buffer, buffer_len, - cur_off, &iter); - if (rdata->result !=3D 0) { - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_MALFORMED; - else - dequeue_mid(server, smb, rdata->result); - return 0; - } - rdata->got_bytes =3D buffer_len; - - } else if (!check_add_overflow(data_offset, data_len, &end_off) && - buf_len >=3D end_off) { - /* read response payload is in buf */ - WARN_ONCE(buffer, "read data can be either in buf or in buffer"); - copied =3D copy_to_iter(buf + data_offset, data_len, &iter); - if (copied =3D=3D 0) - return smb_EIO2(smb_eio_trace_rx_copy_to_iter, copied, data_len); - rdata->got_bytes =3D copied; - } else { - /* read response payload cannot be in both buf and pages */ - WARN_ONCE(1, "buf can not contain only a part of read data"); - rdata->result =3D smb_EIO(smb_eio_trace_rx_both_buf); - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_MALFORMED; - else - dequeue_mid(server, smb, rdata->result); - return 0; - } - - if (is_offloaded) - smb->mid_state =3D MID_RESPONSE_RECEIVED; - else - dequeue_mid(server, smb, false); - return 0; -} - -struct smb2_decrypt_work { - struct work_struct decrypt; - struct TCP_Server_Info *server; - struct bvecq *buffer; - char *buf; - unsigned int len; -}; - - -static void smb2_decrypt_offload(struct work_struct *work) -{ - struct smb2_decrypt_work *dw =3D container_of(work, - struct smb2_decrypt_work, decrypt); - int rc; - struct smb_message *smb; - struct iov_iter iter; - - iov_iter_bvec_queue(&iter, ITER_DEST, dw->buffer, 0, 0, dw->len); - rc =3D decrypt_raw_data(dw->server, dw->buf, dw->server->vals->read_rsp_s= ize, - &iter, true); - if (rc) { - cifs_dbg(VFS, "error decrypting rc=3D%d\n", rc); - goto free_pages; - } - - dw->server->lstrp =3D jiffies; - smb =3D smb2_find_dequeue_mid(dw->server, dw->buf); - if (smb =3D=3D NULL) - cifs_dbg(FYI, "mid not found\n"); - else { - smb->decrypted =3D true; - rc =3D handle_read_data(dw->server, smb, dw->buf, - dw->server->vals->read_rsp_size, - dw->buffer, dw->len, - true); - if (rc >=3D 0) { -#ifdef CONFIG_CIFS_STATS2 - smb->when_received =3D jiffies; -#endif - if (dw->server->ops->is_network_name_deleted) - dw->server->ops->is_network_name_deleted(dw->buf, - dw->server); - - mid_execute_callback(dw->server, smb); - } else { - spin_lock(&dw->server->srv_lock); - if (dw->server->tcpStatus =3D=3D CifsNeedReconnect) { - spin_lock(&dw->server->mid_queue_lock); - smb->mid_state =3D MID_RETRY_NEEDED; - spin_unlock(&dw->server->mid_queue_lock); - spin_unlock(&dw->server->srv_lock); - mid_execute_callback(dw->server, smb); - } else { - spin_lock(&dw->server->mid_queue_lock); - smb->mid_state =3D MID_REQUEST_SUBMITTED; - smb->deleted_from_q =3D false; - list_add_tail(&smb->qhead, - &dw->server->pending_mid_q); - spin_unlock(&dw->server->mid_queue_lock); - spin_unlock(&dw->server->srv_lock); - } - } - release_mid(dw->server, smb); - } - -free_pages: - bvecq_put(dw->buffer); - cifs_small_buf_release(dw->buf); - kfree(dw); -} - - -static int -receive_encrypted_read(struct TCP_Server_Info *server, struct smb_message = **smb, - int *num_mids) -{ - char *buf =3D server->smallbuf; - struct smb2_transform_hdr *tr_hdr =3D (struct smb2_transform_hdr *)buf; - struct iov_iter iter; - unsigned int len; - unsigned int buflen =3D server->pdu_size; - int rc; - struct smb2_decrypt_work *dw; - - dw =3D kzalloc_obj(struct smb2_decrypt_work); - if (!dw) - return -ENOMEM; - INIT_WORK(&dw->decrypt, smb2_decrypt_offload); - dw->server =3D server; - - *num_mids =3D 1; - len =3D min_t(unsigned int, buflen, server->vals->read_rsp_size + - sizeof(struct smb2_transform_hdr)) - HEADER_SIZE(server) + 1; - - rc =3D cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, len); - if (rc < 0) - goto free_dw; - server->total_read +=3D rc; - - if (le32_to_cpu(tr_hdr->OriginalMessageSize) < - server->vals->read_rsp_size) { - cifs_server_dbg(VFS, "OriginalMessageSize %u too small for read response= (%zu)\n", - le32_to_cpu(tr_hdr->OriginalMessageSize), - server->vals->read_rsp_size); - rc =3D -EINVAL; - goto discard_data; - } - len =3D le32_to_cpu(tr_hdr->OriginalMessageSize) - - server->vals->read_rsp_size; - dw->len =3D len; - len =3D round_up(dw->len, PAGE_SIZE); - - rc =3D -ENOMEM; - dw->buffer =3D bvecq_alloc_buffer(len, GFP_NOFS); - if (!dw->buffer) - goto discard_data; - - iov_iter_bvec_queue(&iter, ITER_DEST, dw->buffer, 0, 0, len); - - /* Read the data into the buffer and clear excess bufferage. */ - rc =3D cifs_read_iter_from_socket(server, &iter, dw->len); - if (rc < 0) - goto discard_data; - - server->total_read +=3D rc; - if (rc < len) { - struct iov_iter tmp =3D iter; - - iov_iter_advance(&tmp, rc); - iov_iter_zero(len - rc, &tmp); - } - iov_iter_truncate(&iter, dw->len); - - rc =3D cifs_discard_remaining_data(server); - if (rc) - goto free_pages; - - /* - * For large reads, offload to different thread for better performance, - * use more cores decrypting which can be expensive - */ - - if ((server->min_offload) && (server->in_flight > 1) && - (server->pdu_size >=3D server->min_offload)) { - dw->buf =3D server->smallbuf; - server->smallbuf =3D (char *)cifs_small_buf_get(); - - queue_work(decrypt_wq, &dw->decrypt); - *num_mids =3D 0; /* worker thread takes care of finding mid */ - return -1; - } - - rc =3D decrypt_raw_data(server, buf, server->vals->read_rsp_size, - &iter, false); - if (rc) - goto free_pages; - - *smb =3D smb2_find_mid(server, buf); - if (*smb =3D=3D NULL) { - cifs_dbg(FYI, "mid not found\n"); - } else { - cifs_dbg(FYI, "mid found\n"); - (*smb)->decrypted =3D true; - rc =3D handle_read_data(server, *smb, buf, - server->vals->read_rsp_size, - dw->buffer, dw->len, false); - if (rc >=3D 0) { - if (server->ops->is_network_name_deleted) { - server->ops->is_network_name_deleted(buf, - server); - } - } - } - -free_pages: - bvecq_put(dw->buffer); -free_dw: - kfree(dw); - return rc; -discard_data: - cifs_discard_remaining_data(server); - goto free_pages; -} - -static int -receive_encrypted_standard(struct TCP_Server_Info *server, - struct smb_message **mids, char **bufs, - int *num_mids) -{ - int ret, length; - char *buf =3D server->smallbuf; - struct smb2_hdr *shdr; - unsigned int pdu_length =3D server->pdu_size; - unsigned int buf_size; - unsigned int next_cmd; - struct smb_message *smb; - int next_is_large; - char *next_buffer =3D NULL; - - *num_mids =3D 0; - - /* switch to large buffer if too big for a small one */ - if (pdu_length > MAX_CIFS_SMALL_BUFFER_SIZE) { - server->large_buf =3D true; - memcpy(server->bigbuf, buf, server->total_read); - buf =3D server->bigbuf; - } - - /* now read the rest */ - length =3D cifs_read_from_socket(server, buf + HEADER_SIZE(server) - 1, - pdu_length - HEADER_SIZE(server) + 1); - if (length < 0) - return length; - server->total_read +=3D length; - - buf_size =3D pdu_length - sizeof(struct smb2_transform_hdr); - length =3D decrypt_raw_data(server, buf, buf_size, NULL, false); - if (length) - return length; - - next_is_large =3D server->large_buf; -one_more: - shdr =3D (struct smb2_hdr *)buf; - next_cmd =3D le32_to_cpu(shdr->NextCommand); - if (next_cmd) { - if (WARN_ON_ONCE(next_cmd > pdu_length)) - return -1; - if (next_is_large) - next_buffer =3D (char *)cifs_buf_get(); - else - next_buffer =3D (char *)cifs_small_buf_get(); - if (!next_buffer) { - cifs_server_dbg(VFS, "No memory for (large) SMB response\n"); - return -1; - } - memcpy(next_buffer, buf + next_cmd, pdu_length - next_cmd); - } - - smb =3D smb2_find_mid(server, buf); - if (smb =3D=3D NULL) - cifs_dbg(FYI, "mid not found\n"); - else { - cifs_dbg(FYI, "mid found\n"); - smb->decrypted =3D true; - smb->resp_buf_size =3D server->pdu_size; - } - - if (*num_mids >=3D MAX_COMPOUND) { - cifs_server_dbg(VFS, "too many PDUs in compound\n"); - return -1; - } - bufs[*num_mids] =3D buf; - mids[(*num_mids)++] =3D smb; - - if (smb && smb->handle) - ret =3D smb->handle(server, smb); - else - ret =3D cifs_handle_standard(server, smb); - - if (ret =3D=3D 0 && next_cmd) { - pdu_length -=3D next_cmd; - server->large_buf =3D next_is_large; - if (next_is_large) - server->bigbuf =3D buf =3D next_buffer; - else - server->smallbuf =3D buf =3D next_buffer; - goto one_more; - } else if (ret !=3D 0) { - /* - * ret !=3D 0 here means that we didn't get to handle_mid() thus - * server->smallbuf and server->bigbuf are still valid. We need - * to free next_buffer because it is not going to be used - * anywhere. - */ - if (next_is_large) - free_rsp_buf(CIFS_LARGE_BUFFER, next_buffer); - else - free_rsp_buf(CIFS_SMALL_BUFFER, next_buffer); - } - - return ret; -} - -static int -smb3_receive_transform(struct TCP_Server_Info *server, - struct smb_message **mids, char **bufs, int *num_mids) -{ - char *buf =3D server->smallbuf; - unsigned int pdu_length =3D server->pdu_size; - struct smb2_transform_hdr *tr_hdr =3D (struct smb2_transform_hdr *)buf; - unsigned int orig_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); - - if (pdu_length < sizeof(struct smb2_transform_hdr) + - sizeof(struct smb2_hdr)) { - cifs_server_dbg(VFS, "Transform message is too small (%u)\n", - pdu_length); - cifs_reconnect(server, true); - return -ECONNABORTED; - } - - if (pdu_length < orig_len + sizeof(struct smb2_transform_hdr)) { - cifs_server_dbg(VFS, "Transform message is broken\n"); - cifs_reconnect(server, true); - return -ECONNABORTED; - } - - /* TODO: add support for compounds containing READ. */ - if (pdu_length > CIFSMaxBufSize + MAX_HEADER_SIZE(server)) { - return receive_encrypted_read(server, &mids[0], num_mids); - } - - return receive_encrypted_standard(server, mids, bufs, num_mids); -} - -int -smb3_handle_read_data(struct TCP_Server_Info *server, struct smb_message *= smb) -{ - char *buf =3D server->large_buf ? server->bigbuf : server->smallbuf; - - return handle_read_data(server, smb, buf, server->pdu_size, - NULL, 0, false); -} - -static int smb2_next_header(struct TCP_Server_Info *server, char *buf, - unsigned int *noff) -{ - struct smb2_hdr *hdr =3D (struct smb2_hdr *)buf; - struct smb2_transform_hdr *t_hdr =3D (struct smb2_transform_hdr *)buf; - - if (hdr->ProtocolId =3D=3D SMB2_TRANSFORM_PROTO_NUM) { - *noff =3D le32_to_cpu(t_hdr->OriginalMessageSize); - if (unlikely(check_add_overflow(*noff, sizeof(*t_hdr), noff))) - return -EINVAL; - } else { - *noff =3D le32_to_cpu(hdr->NextCommand); - } - if (unlikely(*noff && *noff < MID_HEADER_SIZE(server))) - return -EINVAL; - return 0; -} - int __cifs_sfu_make_node(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, const char *full_path, umode_t mode, dev_t dev, @@ -5458,6 +4792,25 @@ static int smb2_make_node(unsigned int xid, struct i= node *inode, return rc; } =20 +static unsigned int smb2_calc_smb_size(void *buf) +{ + const union smb2_response_hdr *h =3D buf; + const struct smb2_hdr *shdr =3D &h->hdr; + struct cifs_receive recv =3D { + .response =3D buf, + }; + + /* + * StructureSize2, ie length of fixed parameter area has already + * been checked to make sure it is the correct length. + */ + recv.hdr_len =3D le16_to_cpu(shdr->StructureSize); + recv.hdr_len +=3D le16_to_cpu(h->StructureSize2) & ~SMB2_STRUCT_HAS_DYNAM= IC_PART; + + smb2_calc_size(&recv); + return recv.calc_len; +} + #ifdef CONFIG_CIFS_ALLOW_INSECURE_LEGACY struct smb_version_operations smb20_operations =3D { .compare_fids =3D smb2_compare_fids, @@ -5471,15 +4824,8 @@ struct smb_version_operations smb20_operations =3D { .wait_mtu_credits =3D cifs_wait_mtu_credits, .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, - .read_data_offset =3D smb2_read_data_offset, - .read_data_length =3D smb2_read_data_length, - .map_error =3D map_smb2_to_linux_error, - .find_mid =3D smb2_find_mid, - .check_message =3D smb2_check_message, - .dump_detail =3D smb2_dump_detail, .clear_stats =3D smb2_clear_stats, .print_stats =3D smb2_print_stats, - .is_oplock_break =3D smb2_is_valid_oplock_break, .handle_cancelled_mid =3D smb2_handle_cancelled_mid, .downgrade_oplock =3D smb2_downgrade_oplock, .need_neg =3D smb2_need_neg, @@ -5523,9 +4869,7 @@ struct smb_version_operations smb20_operations =3D { .query_dir_first =3D smb2_query_dir_first, .query_dir_next =3D smb2_query_dir_next, .close_dir =3D smb2_close_dir, - .calc_smb_size =3D smb2_calc_size, - .is_status_pending =3D smb2_is_status_pending, - .is_session_expired =3D smb2_is_session_expired, + .calc_smb_size =3D smb2_calc_smb_size, .oplock_response =3D smb2_oplock_response, .queryfs =3D smb2_queryfs, .mand_lock =3D smb2_mand_lock, @@ -5550,13 +4894,10 @@ struct smb_version_operations smb20_operations =3D { .get_acl =3D get_smb2_acl, .get_acl_by_fid =3D get_smb2_acl_by_fid, .set_acl =3D set_smb2_acl, - .next_header =3D smb2_next_header, .ioctl_query_info =3D smb2_ioctl_query_info, .make_node =3D smb2_make_node, .fiemap =3D smb3_fiemap, .llseek =3D smb3_llseek, - .is_status_io_timeout =3D smb2_is_status_io_timeout, - .is_network_name_deleted =3D smb2_is_network_name_deleted, .rename_pending_delete =3D smb2_rename_pending_delete, }; #endif /* CIFS_ALLOW_INSECURE_LEGACY */ @@ -5574,15 +4915,9 @@ struct smb_version_operations smb21_operations =3D { .adjust_credits =3D smb2_adjust_credits, .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, - .read_data_offset =3D smb2_read_data_offset, - .read_data_length =3D smb2_read_data_length, - .map_error =3D map_smb2_to_linux_error, - .find_mid =3D smb2_find_mid, - .check_message =3D smb2_check_message, - .dump_detail =3D smb2_dump_detail, + .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, .print_stats =3D smb2_print_stats, - .is_oplock_break =3D smb2_is_valid_oplock_break, .handle_cancelled_mid =3D smb2_handle_cancelled_mid, .downgrade_oplock =3D smb2_downgrade_oplock, .need_neg =3D smb2_need_neg, @@ -5626,9 +4961,7 @@ struct smb_version_operations smb21_operations =3D { .query_dir_first =3D smb2_query_dir_first, .query_dir_next =3D smb2_query_dir_next, .close_dir =3D smb2_close_dir, - .calc_smb_size =3D smb2_calc_size, - .is_status_pending =3D smb2_is_status_pending, - .is_session_expired =3D smb2_is_session_expired, + .calc_smb_size =3D smb2_calc_smb_size, .oplock_response =3D smb2_oplock_response, .queryfs =3D smb2_queryfs, .mand_lock =3D smb2_mand_lock, @@ -5655,13 +4988,10 @@ struct smb_version_operations smb21_operations =3D { .get_acl =3D get_smb2_acl, .get_acl_by_fid =3D get_smb2_acl_by_fid, .set_acl =3D set_smb2_acl, - .next_header =3D smb2_next_header, .ioctl_query_info =3D smb2_ioctl_query_info, .make_node =3D smb2_make_node, .fiemap =3D smb3_fiemap, .llseek =3D smb3_llseek, - .is_status_io_timeout =3D smb2_is_status_io_timeout, - .is_network_name_deleted =3D smb2_is_network_name_deleted, .rename_pending_delete =3D smb2_rename_pending_delete, }; =20 @@ -5678,16 +5008,10 @@ struct smb_version_operations smb30_operations =3D { .adjust_credits =3D smb2_adjust_credits, .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, - .read_data_offset =3D smb2_read_data_offset, - .read_data_length =3D smb2_read_data_length, - .map_error =3D map_smb2_to_linux_error, - .find_mid =3D smb2_find_mid, - .check_message =3D smb2_check_message, - .dump_detail =3D smb2_dump_detail, + .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, .print_stats =3D smb2_print_stats, .dump_share_caps =3D smb2_dump_share_caps, - .is_oplock_break =3D smb2_is_valid_oplock_break, .handle_cancelled_mid =3D smb2_handle_cancelled_mid, .downgrade_oplock =3D smb3_downgrade_oplock, .need_neg =3D smb2_need_neg, @@ -5734,9 +5058,7 @@ struct smb_version_operations smb30_operations =3D { .query_dir_first =3D smb2_query_dir_first, .query_dir_next =3D smb2_query_dir_next, .close_dir =3D smb2_close_dir, - .calc_smb_size =3D smb2_calc_size, - .is_status_pending =3D smb2_is_status_pending, - .is_session_expired =3D smb2_is_session_expired, + .calc_smb_size =3D smb2_calc_smb_size, .oplock_response =3D smb2_oplock_response, .queryfs =3D smb2_queryfs, .mand_lock =3D smb2_mand_lock, @@ -5760,8 +5082,6 @@ struct smb_version_operations smb30_operations =3D { .enum_snapshots =3D smb3_enum_snapshots, .notify =3D smb3_notify, .init_transform_rq =3D smb3_init_transform_rq, - .is_transform_hdr =3D smb3_is_transform_hdr, - .receive_transform =3D smb3_receive_transform, .get_dfs_refer =3D smb2_get_dfs_refer, .select_sectype =3D smb2_select_sectype, #ifdef CONFIG_CIFS_XATTR @@ -5771,13 +5091,10 @@ struct smb_version_operations smb30_operations =3D { .get_acl =3D get_smb2_acl, .get_acl_by_fid =3D get_smb2_acl_by_fid, .set_acl =3D set_smb2_acl, - .next_header =3D smb2_next_header, .ioctl_query_info =3D smb2_ioctl_query_info, .make_node =3D smb2_make_node, .fiemap =3D smb3_fiemap, .llseek =3D smb3_llseek, - .is_status_io_timeout =3D smb2_is_status_io_timeout, - .is_network_name_deleted =3D smb2_is_network_name_deleted, .rename_pending_delete =3D smb2_rename_pending_delete, }; =20 @@ -5794,16 +5111,10 @@ struct smb_version_operations smb311_operations =3D= { .adjust_credits =3D smb2_adjust_credits, .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, - .read_data_offset =3D smb2_read_data_offset, - .read_data_length =3D smb2_read_data_length, - .map_error =3D map_smb2_to_linux_error, - .find_mid =3D smb2_find_mid, - .check_message =3D smb2_check_message, - .dump_detail =3D smb2_dump_detail, + .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, .print_stats =3D smb2_print_stats, .dump_share_caps =3D smb2_dump_share_caps, - .is_oplock_break =3D smb2_is_valid_oplock_break, .handle_cancelled_mid =3D smb2_handle_cancelled_mid, .downgrade_oplock =3D smb3_downgrade_oplock, .need_neg =3D smb2_need_neg, @@ -5850,9 +5161,7 @@ struct smb_version_operations smb311_operations =3D { .query_dir_first =3D smb2_query_dir_first, .query_dir_next =3D smb2_query_dir_next, .close_dir =3D smb2_close_dir, - .calc_smb_size =3D smb2_calc_size, - .is_status_pending =3D smb2_is_status_pending, - .is_session_expired =3D smb2_is_session_expired, + .calc_smb_size =3D smb2_calc_smb_size, .oplock_response =3D smb2_oplock_response, .queryfs =3D smb311_queryfs, .mand_lock =3D smb2_mand_lock, @@ -5876,8 +5185,6 @@ struct smb_version_operations smb311_operations =3D { .enum_snapshots =3D smb3_enum_snapshots, .notify =3D smb3_notify, .init_transform_rq =3D smb3_init_transform_rq, - .is_transform_hdr =3D smb3_is_transform_hdr, - .receive_transform =3D smb3_receive_transform, .get_dfs_refer =3D smb2_get_dfs_refer, .select_sectype =3D smb2_select_sectype, #ifdef CONFIG_CIFS_XATTR @@ -5887,13 +5194,10 @@ struct smb_version_operations smb311_operations =3D= { .get_acl =3D get_smb2_acl, .get_acl_by_fid =3D get_smb2_acl_by_fid, .set_acl =3D set_smb2_acl, - .next_header =3D smb2_next_header, .ioctl_query_info =3D smb2_ioctl_query_info, .make_node =3D smb2_make_node, .fiemap =3D smb3_fiemap, .llseek =3D smb3_llseek, - .is_status_io_timeout =3D smb2_is_status_io_timeout, - .is_network_name_deleted =3D smb2_is_network_name_deleted, .rename_pending_delete =3D smb2_rename_pending_delete, }; =20 diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index d4d2da2846e9..ab193f84c1ab 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "cifsglob.h" #include "cifsproto.h" @@ -1084,7 +1085,6 @@ SMB2_negotiate(const unsigned int xid, struct kvec rsp_iov; int rc; int resp_buftype; - int blob_offset, blob_length; char *security_blob; int flags =3D CIFS_NEG_OP; unsigned int total_len; @@ -1284,8 +1284,13 @@ SMB2_negotiate(const unsigned int xid, (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) server->cipher_type =3D SMB2_ENCRYPTION_AES128_CCM; =20 - security_blob =3D smb2_get_data_area_len(&blob_offset, &blob_length, - (struct smb2_hdr *)rsp); + struct cifs_receive recv =3D { + /* TODO: This should be returned into smb_message */ + .response =3D rsp_iov.iov_base, + .msg_len =3D rsp_iov.iov_len, + }; + + security_blob =3D smb2_get_data_area_len(&recv); /* * See MS-SMB2 section 2.2.4: if no blob, client picks default which * for us will be @@ -1293,7 +1298,7 @@ SMB2_negotiate(const unsigned int xid, * but for time being this is our only auth choice so doesn't matter. * We just found a server which sets blob length to zero expecting raw. */ - if (blob_length =3D=3D 0) { + if (recv.data_len =3D=3D 0) { cifs_dbg(FYI, "missing security blob on negprot\n"); server->sec_ntlmssp =3D true; } @@ -1301,8 +1306,8 @@ SMB2_negotiate(const unsigned int xid, rc =3D cifs_enable_signing(server, ses->sign); if (rc) goto neg_exit; - if (blob_length) { - rc =3D decode_negTokenInit(security_blob, blob_length, server); + if (recv.data_len) { + rc =3D decode_negTokenInit(security_blob, recv.data_len, server); if (rc =3D=3D 1) rc =3D 0; else if (rc =3D=3D 0) @@ -4174,7 +4179,7 @@ SMB2_change_notify(const unsigned int xid, struct cif= s_tcon *tcon, static void smb2_echo_callback(struct TCP_Server_Info *server, struct smb_message *smb) { - struct smb2_echo_rsp *rsp =3D (struct smb2_echo_rsp *)smb->resp_buf; + struct smb2_echo_rsp *rsp =3D (struct smb2_echo_rsp *)smb->response; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0 }; =20 if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED @@ -4369,8 +4374,8 @@ SMB2_echo(struct TCP_Server_Info *server) iov[0].iov_len =3D total_len; iov[0].iov_base =3D (char *)req; =20 - rc =3D cifs_call_async(server, &rqst, NULL, smb2_echo_callback, NULL, - server, CIFS_ECHO_OP, NULL); + rc =3D cifs_call_async(server, &rqst, smb2_echo_callback, server, + CIFS_ECHO_OP, NULL, NULL); if (rc) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 @@ -4611,7 +4616,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) struct cifs_io_subrequest *rdata =3D smb->callback_data; struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); - struct smb2_hdr *shdr =3D (struct smb2_hdr *)rdata->iov[0].iov_base; + struct smb2_hdr *shdr =3D smb->response; struct inode *inode =3D &ictx->inode; struct cifs_credits credits =3D { .value =3D 0, @@ -4619,22 +4624,28 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) .rreq_debug_id =3D rdata->rreq->debug_id, .rreq_debug_index =3D rdata->subreq.debug_index, }; - struct smb_rqst rqst =3D { .rq_iov =3D &rdata->iov[0], .rq_nvec =3D 1 }; + struct kvec kv =3D { + .iov_base =3D smb->response, + .iov_len =3D smb->resp_len, + }; + struct smb_rqst rqst =3D { + .rq_iov =3D &kv, + .rq_nvec =3D 1 + }; unsigned int rreq_debug_id =3D rdata->rreq->debug_id; unsigned int subreq_debug_index =3D rdata->subreq.debug_index; =20 - if (rdata->got_bytes) - iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); + iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, + rdata->subreq.content.bvecq, rdata->subreq.content.slot, + rdata->subreq.content.offset, rdata->subreq.len); =20 WARN_ONCE(rdata->server !=3D server, "rdata server %p !=3D mid server %p", rdata->server, server); =20 - cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%zu/%zu\n", - __func__, smb->mid, smb->mid_state, rdata->result, - rdata->got_bytes, rdata->subreq.len - rdata->subreq.transferred); + cifs_dbg(FYI, "%s: mid=3D%llu state=3D%d result=3D%d bytes=3D%u/%zu\n", + __func__, smb->mid, smb->mid_state, smb->error, + smb->resp_data_len, rdata->subreq.len - rdata->subreq.transferred); =20 switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: @@ -4644,7 +4655,6 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) if (server->sign && !smb->decrypted) { int rc; =20 - iov_iter_truncate(&rqst.rq_iter, rdata->got_bytes); rc =3D smb2_verify_signature(&rqst, server); if (rc) { cifs_tcon_dbg(VFS, "SMB signature verification returned error =3D %d\n= ", @@ -4660,6 +4670,8 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) } else trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); } + + rdata->got_bytes =3D smb->resp_data_len; /* FIXME: should this be counted toward the initiating task? */ task_io_account_read(rdata->got_bytes); cifs_stats_bytes_read(tcon, rdata->got_bytes); @@ -4768,6 +4780,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) struct cifs_io_parms io_parms; struct smb_rqst rqst =3D { .rq_iov =3D rdata->iov, .rq_nvec =3D 1 }; + struct iov_iter iter; struct TCP_Server_Info *server; struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); unsigned int total_len; @@ -4776,6 +4789,10 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) cifs_dbg(FYI, "%s: offset=3D%llu bytes=3D%zu\n", __func__, subreq->start, subreq->len); =20 + iov_iter_bvec_queue(&iter, ITER_DEST, + rdata->subreq.content.bvecq, rdata->subreq.content.slot, + rdata->subreq.content.offset, rdata->subreq.len); + if (!rdata->server) rdata->server =3D cifs_pick_channel(tcon->ses); =20 @@ -4827,10 +4844,8 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) flags |=3D CIFS_HAS_CREDITS; } =20 - rc =3D cifs_call_async(server, &rqst, - cifs_readv_receive, smb2_readv_callback, - smb3_handle_read_data, rdata, flags, - &rdata->credits); + rc =3D cifs_call_async(server, &rqst, smb2_readv_callback, rdata, flags, + &rdata->credits, &iter); if (rc) { cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); trace_smb3_read_err(rdata->rreq->debug_id, @@ -4950,7 +4965,7 @@ smb2_writev_callback(struct TCP_Server_Info *server, = struct smb_message *smb) { struct cifs_io_subrequest *wdata =3D smb->callback_data; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); - struct smb2_write_rsp *rsp =3D (struct smb2_write_rsp *)smb->resp_buf; + struct smb2_write_rsp *rsp =3D (struct smb2_write_rsp *)smb->response; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0, @@ -5224,8 +5239,8 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) if (((flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && should_comp= ress(tcon, &rqst)) flags |=3D CIFS_COMPRESS_REQ; =20 - rc =3D cifs_call_async(server, &rqst, NULL, smb2_writev_callback, NULL, - wdata, flags, &wdata->credits); + rc =3D cifs_call_async(server, &rqst, smb2_writev_callback, wdata, flags, + &wdata->credits, NULL); /* Can't touch wdata if rc =3D=3D 0 */ if (rc) { trace_smb3_write_err(wdata->rreq->debug_id, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 5727e47733c8..0b3df644222b 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -21,7 +21,7 @@ struct smb_rqst; * All Prototypes ***************************************************************** */ -int map_smb2_to_linux_error(char *buf, bool log_err); +int map_smb2_to_linux_error(const struct smb2_hdr *shdr, bool log_err); int smb2_init_maperror(void); #if IS_ENABLED(CONFIG_SMB_KUNIT_TESTS) const struct status_to_posix_error *smb2_get_err_map_test(__u32 smb2_statu= s); @@ -29,13 +29,13 @@ extern const struct status_to_posix_error *smb2_error_m= ap_table_test; extern unsigned int smb2_error_map_num; #endif =20 -int smb2_check_message(char *buf, unsigned int pdu_len, unsigned int len, - struct TCP_Server_Info *server); -unsigned int smb2_calc_size(void *buf); -char *smb2_get_data_area_len(int *off, int *len, struct smb2_hdr *shdr); +int smb2_check_message(struct TCP_Server_Info *server, struct cifs_receive= *recv); +void smb2_calc_size(struct cifs_receive *recv); +char *smb2_get_data_area_len(struct cifs_receive *recv); __le16 *cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb); =20 +int smb2_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); int smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server); int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, @@ -48,7 +48,8 @@ struct smb_message *smb2_setup_async_request(struct TCP_S= erver_Info *server, struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid); __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int opl= ock); -bool smb2_is_valid_oplock_break(char *buffer, struct TCP_Server_Info *serv= er); +void smb2_is_valid_oplock_break(struct TCP_Server_Info *server, + union smb2_response_hdr *h); int smb3_handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb); struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data, @@ -121,6 +122,16 @@ void smb2_set_related(struct smb_rqst *rqst); void smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst= ); bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries, int *pcur_sleep); +void smb2_add_credits_from_hdr(struct smb2_hdr *shdr, + struct TCP_Server_Info *server); +struct smb_message *smb2_find_mid(struct TCP_Server_Info *server, + struct smb2_hdr *shdr, bool dequeue); +#ifdef CONFIG_CIFS_DEBUG2 +void smb2_dump_detail(struct TCP_Server_Info *server, const struct cifs_re= ceive *recv); +void smb2_dump_mids(struct TCP_Server_Info *server); +#endif /* CONFIG_CIFS_DEBUG2 */ +bool smb2_status_pending(struct smb2_hdr *shdr, struct TCP_Server_Info *se= rver); +bool smb2_network_name_is_deleted(struct smb2_hdr *shdr, struct TCP_Server= _Info *server); =20 /* * SMB2 Worker functions - most of protocol specific implementation details @@ -264,6 +275,8 @@ int smb2_query_info_compound(const unsigned int xid, st= ruct cifs_tcon *tcon, const char *path, u32 desired_access, u32 class, u32 type, u32 output_len, struct kvec *rsp, int *buftype, struct cifs_sb_info *cifs_sb); +int smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, + u8 *key); /* query path info from the server using SMB311 POSIX extensions*/ int posix_info_parse(const void *beg, const void *end, struct smb2_posix_info_parsed *out); diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 9df3a0b530e2..1086877e9d84 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -29,6 +30,9 @@ #include "../common/smb2status.h" #include "smb2glob.h" =20 +static void smb2_parse_pdu(struct TCP_Server_Info *server, + struct netfs_rxqueue *rxq); + static int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *ke= y) { @@ -545,7 +549,7 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server= _Info *server) int smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *serve= r) { - unsigned int rc; + int rc; char server_response_sig[SMB2_SIGNATURE_SIZE]; struct smb2_hdr *shdr =3D (struct smb2_hdr *)rqst->rq_iov[0].iov_base; @@ -692,15 +696,15 @@ int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *server, bool log_error) { - unsigned int len =3D smb->resp_buf_size; + unsigned int len =3D smb->resp_len; struct kvec iov[1]; struct smb_rqst rqst =3D { .rq_iov =3D iov, .rq_nvec =3D 1 }; =20 - iov[0].iov_base =3D (char *)smb->resp_buf; + iov[0].iov_base =3D (char *)smb->response; iov[0].iov_len =3D len; =20 - dump_smb(smb->resp_buf, min_t(u32, 80, len)); + dump_smb(smb->response, min_t(u32, 80, len)); /* convert the length into a more usable form */ if (len > 24 && server->sign && !smb->decrypted) { int rc; @@ -708,10 +712,10 @@ smb2_check_receive(struct smb_message *smb, struct TC= P_Server_Info *server, rc =3D smb2_verify_signature(&rqst, server); if (rc) cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d\= n", - rc); + rc); } =20 - return map_smb2_to_linux_error(smb->resp_buf, log_error); + return map_smb2_to_linux_error(smb->response, log_error); } =20 struct smb_message * @@ -881,3 +885,620 @@ static void *smb2_get_aead_req_new(struct crypto_aead= *tfm, const struct iov_ite *sgl =3D sgtable.sgl; return p; } + +/* + * Decrypt the PDU in the iterator. The PDU begins with the transform hea= der. + */ +static int decrypt_pdu(struct TCP_Server_Info *server, + struct smb2_transform_hdr *tr_hdr, + struct netfs_rxqueue *rxq) +{ + DECLARE_CRYPTO_WAIT(wait); + struct aead_request *req; + struct crypto_aead *tfm =3D server->secmech.dec; + struct scatterlist *sg; + struct iov_iter iter; + unsigned int assoc_data_len =3D sizeof(struct smb2_transform_hdr) - 20; + unsigned int crypt_len; + size_t sensitive_size; + void *creq; + int rc =3D 0; + u8 sign[SMB2_SIGNATURE_SIZE] =3D {}; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; + u8 *iv; + + crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); + + rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 0, key); + if (rc) { + cifs_server_dbg(FYI, "%s: Could not get decryption key. sid: 0x%llx\n", + __func__, le64_to_cpu(tr_hdr->SessionId)); + return rc; + } + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_CCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); + else + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); + + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); + return rc; + } + + rc =3D crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); + return rc; + } + + netfs_rxqueue_discard(rxq, offsetof(struct smb2_transform_hdr, Nonce)); + + iov_iter_bvec_queue(&iter, ITER_DEST, rxq->take_from, rxq->take_slot, + rxq->take_offset, rxq->pdu_remain); + + creq =3D smb2_get_aead_req_new(tfm, &iter, sign, &iv, &req, &sg, + &sensitive_size); + if (IS_ERR(creq)) + return PTR_ERR(creq); + + memcpy(sign, &tr_hdr->Signature, SMB2_SIGNATURE_SIZE); + crypt_len +=3D SMB2_SIGNATURE_SIZE; + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); + else { + iv[0] =3D 3; + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); + } + + aead_request_set_tfm(req, tfm); + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &wait); + + rc =3D crypto_wait_req(crypto_aead_decrypt(req), &wait); + + netfs_rxqueue_discard(rxq, sizeof(*tr_hdr) - offsetof(struct smb2_transfo= rm_hdr, Nonce)); + + kvfree_sensitive(creq, sensitive_size); + return rc; +} + +struct smb2_decrypt_work { + struct work_struct decrypt; + struct TCP_Server_Info *server; + struct netfs_rxqueue rx_subset; +}; + +static void smb2_decrypt_offload(struct work_struct *work) +{ + struct smb2_transform_hdr tr_hdr; + struct smb2_decrypt_work *dw =3D + container_of(work, struct smb2_decrypt_work, decrypt); + struct netfs_rxqueue *rxq =3D &dw->rx_subset; + int rc; + + if (netfs_rxqueue_read(rxq, &tr_hdr, 0, sizeof(tr_hdr)) !=3D sizeof(tr_hd= r)) + goto out; + + rc =3D decrypt_pdu(dw->server, &tr_hdr, rxq); + if (rc < 0) { + cifs_dbg(VFS, "error decrypting rc=3D%d\n", rc); + goto out; + } + + smb2_parse_pdu(dw->server, rxq); +out: + netfs_put_rx_bvecq(rxq->take_from); + kfree(dw); +} + +static bool smb3_offload_decrypt(struct TCP_Server_Info *server, + struct smb2_transform_hdr *tr_hdr, + struct netfs_rxqueue *rxq) +{ + struct smb2_decrypt_work *dw; + struct bvecq *head_bq; + size_t remain =3D rxq->pdu_remain; + + dw =3D kzalloc(sizeof(struct smb2_decrypt_work), GFP_KERNEL); + if (!dw) + return false; + INIT_WORK(&dw->decrypt, smb2_decrypt_offload); + dw->server =3D server; + + head_bq =3D netfs_rxqueue_decant(rxq, remain); + if (!head_bq) { + kfree(dw); + return -ENOMEM; + } + + dw->rx_subset.take_from =3D head_bq; + dw->rx_subset.add_to =3D NULL; + dw->rx_subset.take_slot =3D 0; + dw->rx_subset.take_offset =3D 0; + dw->rx_subset.refillable =3D false; + dw->rx_subset.qsize =3D remain; + dw->rx_subset.pdu_remain =3D remain; + + queue_work(decrypt_wq, &dw->decrypt); + return true; +} + +/* + * Reverse the transformation the sender made to a PDU we just received, s= uch + * as decrypting it. The PDU body is currently in residence upon the serv= er + * receive queue. + */ +static int smb3_reverse_transform(struct TCP_Server_Info *server, + struct netfs_rxqueue *rxq) +{ + struct smb2_transform_hdr tr_hdr; + unsigned int orig_len; + size_t got; + int rc; + + if (!server->secmech.dec) { + cifs_server_dbg(VFS, "%s: Decryption TFM not allocated\n", __func__); + return -EIO; + } + + rc =3D smb_rxqueue_refill(server, rxq, rxq->pdu_remain); + if (rc < 0) + return rc; + + got =3D netfs_rxqueue_read(rxq, &tr_hdr, 0, sizeof(tr_hdr)); + if (got !=3D sizeof(tr_hdr)) { + cifs_server_dbg(VFS, "Too short for transform header (%u)\n", + rxq->pdu_remain); + return -EIO; + } + + orig_len =3D le32_to_cpu(tr_hdr.OriginalMessageSize); + if (orig_len > rxq->pdu_remain - sizeof(tr_hdr)) { + cifs_server_dbg(VFS, "Transform message is broken\n"); + return -EIO; + } + + /* + * For large reads, offload to different thread for better performance, + * use more cores decrypting which can be expensive + */ + if (server->min_offload && server->in_flight > 1 && + rxq->pdu_remain >=3D server->min_offload && + smb3_offload_decrypt(server, &tr_hdr, rxq)) + return 0; + + rxq->refillable =3D false; + decrypt_pdu(server, &tr_hdr, rxq); + smb2_parse_pdu(server, rxq); + return 0; +} + +/* + * Copy data directly into prepared buffers. + * + * Ideally, we'd wait for sufficient data to be present in the queue before + * doing this, but that causes a performance loss as we don't receive data= and + * copy in parallel. + */ +static void smb2_copy_to_prepped_buffers(struct TCP_Server_Info *server, + struct smb_message *smb, + struct netfs_rxqueue *rxq, + struct cifs_receive *recv) +{ + const union smb2_response_hdr *h =3D recv->response; + struct iov_iter dest =3D smb->response_iter; + unsigned int to_copy, skip; + int rc; + + switch (smb->command) { + case SMB2_READ: + to_copy =3D recv->data_len; + skip =3D recv->data_offset; + + switch (h->read.Flags) { + case SMB2_READFLAG_RESPONSE_NONE: + break; + case SMB2_READFLAG_RESPONSE_RDMA_TRANSFORM: + if (to_copy) + cifs_dbg(FYI, "%s: Read.DataLength !=3D 0 for RDMA\n", __func__); + return; + default: + cifs_dbg(FYI, "%s: Unknown Read.Flags value (%x)\n", + __func__, le32_to_cpu(h->read.Flags)); + recv->malformed =3D true; + return; + } + skip -=3D recv->extracted; + break; + default: + cifs_dbg(FYI, "%s: Non-Read copy\n", __func__); + return; + } + + if (skip < recv->hdr_len) { + if (skip !=3D 0) { + cifs_dbg(FYI, "%s: Read.DataOffset too small\n", __func__); + return; + } + skip =3D recv->hdr_len; + } + if (skip > recv->msg_len) { + cifs_dbg(FYI, "%s: Read.DataOffset beyond end\n", __func__); + return; + } + if (to_copy > recv->msg_len - skip) { + cifs_dbg(FYI, "%s: Read.DataLength beyond end\n", __func__); + return; + } + + if (!rxq->refillable) { + size_t got; + + got =3D netfs_rxqueue_read_iter(rxq, &smb->response_iter, 0, to_copy); + if (got > 0) + netfs_rxqueue_discard(rxq, got); + recv->extracted +=3D got; + if (got < to_copy) { + cifs_dbg(VFS, "Copy to buffer was short %zu/%u\n", + got, to_copy); + recv->malformed =3D true; + } + return; + } + + while (to_copy) { + size_t got, part =3D umin(to_copy, rxq->qsize); + + got =3D netfs_rxqueue_read_iter(rxq, &dest, 0, part); + if (got > 0) { + recv->extracted +=3D got; + to_copy -=3D got; + netfs_rxqueue_discard(rxq, got); + } + if (!to_copy) + break; + if (got < part) { + cifs_dbg(VFS, "Copy to buffer was short %zu/%zu\n", + part, to_copy + part); + recv->malformed =3D true; + return; + } + + rc =3D smb_rxqueue_refill(server, rxq, 1); + if (rc < 0) { + recv->malformed =3D true; + return; + } + if (!rxq->qsize || !rxq->pdu_remain) + break; + } +} + +/* + * Parse an SMB2/3 message that's at least partially extracted. For succe= ssful + * reads, the data part is still in the receive queue or even not yet rece= ived. + */ +static void smb2_parse_one_message(struct TCP_Server_Info *server, + struct cifs_receive *recv, + struct netfs_rxqueue *rxq) +{ + union smb2_response_hdr *h =3D recv->response; + struct smb_message *smb; + struct smb2_hdr *shdr =3D &h->hdr; + int rc; + + smb =3D smb2_find_mid(server, shdr, false); + if (!smb) { + cifs_dbg(VFS, "%s: Unqueued mid (%llx)\n", + __func__, le64_to_cpu(shdr->MessageId)); + rxq->msg_id =3D 0; + } else { + rxq->msg_id =3D 0; /* TODO: smb->debug_id */ + } + + /* + * We know that we received enough to get to the MID as we checked the + * pdu_length earlier. Now check to see if the rest of the header is OK + * and determine the general layout of the message. + * + * 48 bytes is enough to display the header and a little bit into the + * payload for debugging purposes. + */ + rc =3D smb2_check_message(server, recv); + if (rc) { + cifs_dump_mem("Bad SMB: ", h, umin(recv->extracted, 48)); + recv->malformed =3D true; + recv->error =3D -EPROTO; + } + + /* Check the status codes for server/connection-level information. */ + switch (shdr->Status) { + case 0: + trace_smb3_cmd_done(le32_to_cpu(shdr->Id.SyncId.TreeId), + le64_to_cpu(shdr->SessionId), + le16_to_cpu(shdr->Command), + le64_to_cpu(shdr->MessageId)); + break; + case STATUS_NETWORK_SESSION_EXPIRED: + case STATUS_USER_SESSION_DELETED: + trace_smb3_ses_expired(le32_to_cpu(shdr->Id.SyncId.TreeId), + le64_to_cpu(shdr->SessionId), + le16_to_cpu(shdr->Command), + le64_to_cpu(shdr->MessageId)); + cifs_dbg(FYI, "Session expired or deleted\n"); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + release_mid(server, smb); + return; + case STATUS_PENDING: + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + smb2_status_pending(shdr, server); + release_mid(server, smb); + return; + case STATUS_IO_TIMEOUT: + int iotimo =3D atomic_inc_return(&server->num_io_timeout); + if (iotimo > MAX_STATUS_IO_TIMEOUT) { + cifs_server_dbg(VFS, + "Number of request timeouts exceeded %d. Reconnecting", + MAX_STATUS_IO_TIMEOUT); + + set_bit(SMB_SERVER_SESSION_RECONNECT, &server->flags); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + atomic_set(&server->num_io_timeout, 0); + } + break; + case STATUS_NETWORK_NAME_DELETED: + cifs_server_dbg(FYI, "Share deleted. Reconnect needed"); + smb2_network_name_is_deleted(shdr, server); + break; + default: + recv->error =3D map_smb2_to_linux_error(shdr, false); + if (recv->error) { + cifs_dbg(FYI, "%s: server returned error %d\n", + __func__, recv->error); + /* normal error on read response */ + } + break; + } + + if (smb) { + size_t resp_len; + + /* handle_mid */ + smb->status =3D shdr->Status; + smb->error =3D recv->error; + smb->credits_received =3D le16_to_cpu(shdr->CreditRequest); + smb->resp_data_len =3D recv->data_len; + smb->resp_data_offset =3D recv->data_offset; + + trace_smb3_reply(smb, recv); + + /* For a successful Read, we only grab the header. */ + resp_len =3D recv->msg_len; + if (smb->status !=3D 0) + smb->copy_to_bufs =3D false; + if (smb->copy_to_bufs) + resp_len =3D recv->hdr_len; + + if (resp_len <=3D MAX_CIFS_SMALL_BUFFER_SIZE) { + server->smallbuf =3D NULL; + } else if (resp_len <=3D CIFSMaxBufSize + MAX_SMB2_HDR_SIZE) { + memcpy(server->bigbuf, server->smallbuf, recv->extracted); + recv->response =3D server->bigbuf; + server->bigbuf =3D NULL; + recv->resp_buf_type =3D CIFS_LARGE_BUFFER; + h =3D recv->response; + shdr =3D &h->hdr; + } else { + /* Too big - should parse directly from iterator. */ + smb->error =3D -EMSGSIZE; + cifs_dbg(FYI, "%s: Message too big\n", __func__); + } + + smb->response =3D recv->response; + smb->resp_len =3D resp_len; + + if (recv->extracted < recv->msg_len) { + size_t part =3D resp_len - recv->extracted, got; + + got =3D netfs_rxqueue_read(rxq, recv->response + recv->extracted, + recv->extracted, part); + recv->extracted +=3D got; + netfs_rxqueue_discard(rxq, recv->extracted); + + if (WARN_ON(got !=3D part)) { + smb->error =3D -EIO; + smb->resp_len =3D recv->extracted; + recv->malformed =3D true; + } else if (smb->copy_to_bufs) { + smb2_copy_to_prepped_buffers(server, smb, rxq, + recv); + } else if (rxq->pdu_remain) { + iov_iter_bvec_queue(&smb->response_iter, ITER_SOURCE, + rxq->take_from, rxq->take_slot, + rxq->take_offset, rxq->pdu_remain); + smb->response_data =3D rxq->take_from; + refcount_inc(&smb->response_data->ref); + } + } else { + netfs_rxqueue_discard(rxq, recv->extracted); + } + + dequeue_mid(server, smb, recv->malformed); + mid_execute_callback(server, smb); + + release_mid(server, smb); + } else if (shdr->Command =3D=3D cpu_to_le32(SMB2_OPLOCK_BREAK)) { + smb2_is_valid_oplock_break(server, h); + smb2_add_credits_from_hdr(shdr, server); + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + cifs_dbg(FYI, "Received oplock break\n"); + } else { + cifs_server_dbg(VFS, "No task to wake, unknown frame received! NumMids %= d\n", + atomic_read(&mid_count)); + cifs_dump_mem("Received Data is: ", h, HEADER_SIZE(server)); + smb2_add_credits_from_hdr(shdr, server); +#ifdef CONFIG_CIFS_DEBUG2 + smb2_dump_detail(server, recv); + smb2_dump_mids(server); +#endif /* CIFS_DEBUG2 */ + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + } +} + +/* + * Receive and parse a received SMB2/3 PDU. + * + * At this point all the data has been read, any transformation unapplied, + * decompression performed and some of it is stored in the receive queue + * (excerpt) without either the rfc1002, transform or compression headers, + * though some may yet to be received. + */ +static void smb2_parse_pdu(struct TCP_Server_Info *server, + struct netfs_rxqueue *rxq) +{ + u32 next_command, ssize2, next_len; + int rc; + + server->lstrp =3D jiffies; + + do { + union smb2_response_hdr *h; + struct smb2_hdr *shdr; + size_t want, got; + + while (!allocate_buffers(server)) + if (server->tcpStatus =3D=3D CifsExiting) + return; + + struct cifs_receive recv =3D { + .resp_buf_type =3D CIFS_SMALL_BUFFER, + .response =3D server->smallbuf, + .msg_len =3D rxq->pdu_remain, + .hdr_len =3D sizeof(*shdr) + sizeof(h->StructureSize2), + }; + h =3D recv.response; + shdr =3D &h->hdr; + + rc =3D smb_rxqueue_refill(server, rxq, recv.hdr_len); + if (rc < 0) + goto failed; + + got =3D netfs_rxqueue_read(rxq, recv.response, 0, recv.hdr_len); + if (got !=3D recv.hdr_len) { + cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", + rxq->qsize); + goto failed; + } + recv.extracted =3D recv.hdr_len; + + switch (shdr->ProtocolId) { + case SMB2_PROTO_NUMBER: + break; + case SMB2_TRANSFORM_PROTO_NUM: + case SMB2_COMPRESSION_TRANSFORM_ID: + default: + cifs_server_dbg(VFS, "SMB unsupported ProtocolId (%x)\n", + le32_to_cpu(shdr->ProtocolId)); + goto failed; + } + + /* Extract message from a compound. */ + next_command =3D le32_to_cpu(shdr->NextCommand); + next_len =3D 0; + if (next_command) { + if (next_command < sizeof(*shdr) + 4 || + next_command + sizeof(*shdr) >=3D rxq->pdu_remain || + (next_command & 0x7)) { + cifs_dbg(VFS, "%s: malformed response (next_command=3D%u)\n", + __func__, next_command); + goto failed; + } + next_len =3D rxq->pdu_remain - next_command; + rxq->pdu_remain =3D next_command; + recv.msg_len =3D next_command; + } + + /* Get the rest of the command-specific response header. */ + ssize2 =3D le16_to_cpu(h->StructureSize2); + ssize2 &=3D ~SMB2_STRUCT_HAS_DYNAMIC_PART; + if (ssize2 < 4 || + ssize2 > sizeof(*h) - sizeof(h->hdr)) { + cifs_dbg(VFS, "%s: malformed response (structsize2=3D%u)\n", + __func__, ssize2); + goto failed; + } + ssize2 -=3D sizeof(h->StructureSize2); + + /* If it's not a successful read, then wait for the entire message. */ + if (le16_to_cpu(shdr->Command) !=3D SMB2_READ || + shdr->Status !=3D 0) + want =3D recv.msg_len; + else + want =3D recv.hdr_len + ssize2; + + rc =3D smb_rxqueue_refill(server, rxq, want); + if (rc < 0) + goto failed; + + got =3D netfs_rxqueue_read(rxq, &h->pdu + 1, recv.hdr_len, ssize2); + if (got !=3D ssize2) { + cifs_server_dbg(VFS, "SMB response too short (%u bytes)\n", + rxq->qsize); + goto failed; + } + recv.hdr_len +=3D ssize2; + recv.extracted +=3D ssize2; + + smb2_parse_one_message(server, &recv, rxq); + + WARN(rxq->pdu_remain > 0, "MSG=3D%08x pdu_remain=3D%x", + rxq->msg_id, rxq->pdu_remain); + smb_rxqueue_consume(server, rxq, rxq->pdu_remain); + rxq->pdu_remain =3D next_len; + } while (next_command); + return; + +failed: + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); +} + +/* + * Receive and parse an SMB2/3 PDU. We need to wait for data to come in u= ntil + * we have enough and then we have to reverse transformations and perform + * decompression before we can fully parse the message contents. + */ +int smb2_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len) +{ + struct netfs_rxqueue *rxq =3D &server->rx_queue; + __le32 protocol_id; + size_t got; + int rc; + + rc =3D smb_rxqueue_refill(server, rxq, sizeof(struct smb2_pdu)); + if (rc < 0) + return rc; + + got =3D netfs_rxqueue_read(rxq, &protocol_id, 0, sizeof(protocol_id)); + if (got !=3D sizeof(protocol_id)) { + cifs_dbg(VFS, "%s: Couldn't extract ProtocolId\n", __func__); + set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); + return -EIO; + } + + /* Reverse any transformation made to the content. We set up an + * iterator to define the buffer, but anyone looking at the buffer + * *should not* assume that they can simply poke around in it as it may + * be assembled from raw network packet Rx buffers. + */ + if (protocol_id =3D=3D SMB2_TRANSFORM_PROTO_NUM) + return smb3_reverse_transform(server, rxq); + smb2_parse_pdu(server, rxq); + return 0; +} diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index ede61d8a192c..7bd04ebbce5d 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -47,6 +47,7 @@ EM(smb_eio_trace_lock_data_too_small, "lock_data_too_small") \ EM(smb_eio_trace_malformed_ksid_key, "malformed_ksid_key") \ EM(smb_eio_trace_malformed_sid_key, "malformed_sid_key") \ + EM(smb_eio_trace_md5_iter, "md5_iter") \ EM(smb_eio_trace_mkdir_no_rsp, "mkdir_no_rsp") \ EM(smb_eio_trace_neg_bad_rsplen, "neg_bad_rsplen") \ EM(smb_eio_trace_neg_decode_token, "neg_decode_token") \ @@ -1963,6 +1964,68 @@ TRACE_EVENT(smb3_eio, __entry->info, __entry->info2) ); =20 +TRACE_EVENT(smb3_data_ready, + TP_PROTO(int dummy), + TP_ARGS(dummy), + TP_STRUCT__entry( + __field(unsigned int, dummy) + ), + TP_fast_assign( + __entry->dummy =3D dummy; + ), + TP_printk("%d", __entry->dummy) + ); + +TRACE_EVENT(smb3_tcp_splice, + TP_PROTO(int len), + TP_ARGS(len), + TP_STRUCT__entry( + __field(unsigned int, len) + ), + TP_fast_assign( + __entry->len =3D len; + ), + TP_printk("l=3D%d", __entry->len) + ); + +TRACE_EVENT(smb3_rx_pdu, + TP_PROTO(const struct netfs_rxqueue *rxq), + TP_ARGS(rxq), + TP_STRUCT__entry( + __field(unsigned int, len) + ), + TP_fast_assign( + __entry->len =3D rxq->pdu_remain; + ), + TP_printk("l=3D%x", + __entry->len) + ); + +TRACE_EVENT(smb3_reply, + TP_PROTO(const struct smb_message *smb, const struct cifs_receive *re= cv), + TP_ARGS(smb, recv), + TP_STRUCT__entry( + __field(unsigned int, msg_id) + __field(unsigned int, cmd) + __field(unsigned int, doff) + __field(unsigned int, dlen) + __field(unsigned int, len) + __field(unsigned int, extr) + ), + TP_fast_assign( + __entry->msg_id =3D 0; /* TODO: fill in */ + __entry->cmd =3D smb->command; + __entry->doff =3D recv->data_offset; + __entry->dlen =3D recv->data_len; + __entry->len =3D recv->msg_len; + __entry->extr =3D recv->extracted; + ), + TP_printk("MSG=3D%08x cmd=3D%x d=3D%x-%x l=3D%x/%x", + __entry->msg_id, __entry->cmd, + __entry->doff, __entry->doff + __entry->dlen, + __entry->extr, __entry->len) + ); + #undef EM #undef E_ #endif /* _CIFS_TRACE_H */ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 3ea52cf4a64b..3f4d1a52b45c 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -87,7 +87,7 @@ void __release_mid(struct TCP_Server_Info *server, struct= smb_message *smb) unsigned long roundtrip_time; #endif =20 - if (smb->resp_buf && smb->wait_cancelled && + if (smb->response && smb->wait_cancelled && (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED || smb->mid_state =3D=3D MID_RESPONSE_READY) && server->ops->handle_cancelled_mid) @@ -96,9 +96,11 @@ void __release_mid(struct TCP_Server_Info *server, struc= t smb_message *smb) smb->mid_state =3D MID_FREE; atomic_dec(&mid_count); if (smb->large_buf) - cifs_buf_release(smb->resp_buf); + cifs_buf_release(smb->response); else - cifs_small_buf_release(smb->resp_buf); + cifs_small_buf_release(smb->response); + if (smb->response_data) + netfs_put_rx_bvecq(smb->response_data); #ifdef CONFIG_CIFS_STATS2 now =3D jiffies; if (now < smb->when_alloc) @@ -701,9 +703,9 @@ int wait_for_response(struct TCP_Server_Info *server, s= truct smb_message *smb) */ int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, - mid_receive_t receive, mid_callback_t callback, - mid_handle_t handle, void *cbdata, const int flags, - const struct cifs_credits *exist_credits) + mid_callback_t callback, void *cbdata, const int flags, + const struct cifs_credits *exist_credits, + struct iov_iter *resp_buf) { int rc; struct smb_message *smb; @@ -743,11 +745,13 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, } =20 smb->sr_flags =3D flags; - smb->receive =3D receive; smb->callback =3D callback; smb->callback_data =3D cbdata; - smb->handle =3D handle; smb->mid_state =3D MID_REQUEST_SUBMITTED; + if (resp_buf) { + smb->copy_to_bufs =3D true; + smb->response_iter =3D *resp_buf; + } =20 /* put it on the pending_mid_q */ spin_lock(&server->mid_queue_lock); @@ -912,7 +916,6 @@ compound_send_recv(const unsigned int xid, struct cifs_= ses *ses, { .value =3D 0, .instance =3D 0 } }; unsigned int instance; - char *buf; =20 optype =3D flags & CIFS_OP_MASK; =20 @@ -1079,7 +1082,7 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, goto out; } =20 - if (!smb[i]->resp_buf || + if (!smb[i]->response || smb[i]->mid_state !=3D MID_RESPONSE_READY) { rc =3D smb_EIO1(smb_eio_trace_rx_mid_unready, smb[i]->mid_state); cifs_dbg(FYI, "Bad MID state?\n"); @@ -1088,11 +1091,9 @@ compound_send_recv(const unsigned int xid, struct ci= fs_ses *ses, =20 rc =3D server->ops->check_receive(smb[i], server, flags & CIFS_LOG_ERROR); - if (resp_iov) { - buf =3D (char *)smb[i]->resp_buf; - resp_iov[i].iov_base =3D buf; - resp_iov[i].iov_len =3D smb[i]->resp_buf_size; + resp_iov[i].iov_base =3D smb[i]->response; + resp_iov[i].iov_len =3D smb[i]->resp_len; =20 if (smb[i]->large_buf) resp_buf_type[i] =3D CIFS_LARGE_BUFFER; @@ -1101,7 +1102,7 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, =20 /* mark it so buf will not be freed by delete_mid */ if ((flags & CIFS_NO_RSP_BUF) =3D=3D 0) - smb[i]->resp_buf =3D NULL; + smb[i]->response =3D NULL; } } =20 @@ -1146,193 +1147,3 @@ cifs_send_recv(const unsigned int xid, struct cifs_= ses *ses, return compound_send_recv(xid, ses, server, flags, 1, rqst, resp_buf_type, resp_iov); } - - -/* - * Discard any remaining data in the current SMB. To do this, we borrow the - * current bigbuf. - */ -int -cifs_discard_remaining_data(struct TCP_Server_Info *server) -{ - unsigned int rfclen =3D server->pdu_size; - size_t remaining =3D rfclen - server->total_read; - - while (remaining > 0) { - ssize_t length; - - length =3D cifs_discard_from_socket(server, - min_t(size_t, remaining, - CIFSMaxBufSize + MAX_HEADER_SIZE(server))); - if (length < 0) - return length; - server->total_read +=3D length; - remaining -=3D length; - } - - return 0; -} - -static int -__cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *s= mb, - bool malformed) -{ - int length; - - length =3D cifs_discard_remaining_data(server); - dequeue_mid(server, smb, malformed); - smb->resp_buf =3D server->smallbuf; - server->smallbuf =3D NULL; - return length; -} - -static int -cifs_readv_discard(struct TCP_Server_Info *server, struct smb_message *smb) -{ - struct cifs_io_subrequest *rdata =3D smb->callback_data; - - return __cifs_readv_discard(server, smb, rdata->result); -} - -int -cifs_readv_receive(struct TCP_Server_Info *server, struct smb_message *smb) -{ - int length, len; - unsigned int data_offset, data_len, end_off; - struct cifs_io_subrequest *rdata =3D smb->callback_data; - char *buf =3D server->smallbuf; - unsigned int buflen =3D server->pdu_size; - bool use_rdma_mr =3D false; - - cifs_dbg(FYI, "%s: mid=3D%llu offset=3D%llu bytes=3D%zu\n", - __func__, smb->mid, rdata->subreq.start, rdata->subreq.len); - - /* - * read the rest of READ_RSP header (sans Data array), or whatever we - * can if there's not enough data. At this point, we've read down to - * the Mid. - */ - len =3D min_t(unsigned int, buflen, server->vals->read_rsp_size) - - HEADER_SIZE(server) + 1; - - length =3D cifs_read_from_socket(server, - buf + HEADER_SIZE(server) - 1, len); - if (length < 0) - return length; - server->total_read +=3D length; - - if (server->ops->is_session_expired && - server->ops->is_session_expired(buf)) { - cifs_reconnect(server, true); - return -1; - } - - if (server->ops->is_status_pending && - server->ops->is_status_pending(buf, server)) { - cifs_discard_remaining_data(server); - return -1; - } - - /* set up first two iov for signature check and to get credits */ - rdata->iov[0].iov_base =3D buf; - rdata->iov[0].iov_len =3D server->total_read; - cifs_dbg(FYI, "0: iov_base=3D%p iov_len=3D%zu\n", - rdata->iov[0].iov_base, rdata->iov[0].iov_len); - - /* Was the SMB read successful? */ - rdata->result =3D server->ops->map_error(buf, false); - if (rdata->result !=3D 0) { - cifs_dbg(FYI, "%s: server returned error %d\n", - __func__, rdata->result); - /* normal error on read response */ - return __cifs_readv_discard(server, smb, false); - } - - /* Is there enough to get to the rest of the READ_RSP header? */ - if (server->total_read < server->vals->read_rsp_size) { - cifs_dbg(FYI, "%s: server returned short header. got=3D%u expected=3D%zu= \n", - __func__, server->total_read, - server->vals->read_rsp_size); - rdata->result =3D smb_EIO2(smb_eio_trace_read_rsp_short, - server->total_read, server->vals->read_rsp_size); - return cifs_readv_discard(server, smb); - } - - data_offset =3D server->ops->read_data_offset(buf); - if (data_offset < server->total_read) { - /* - * win2k8 sometimes sends an offset of 0 when the read - * is beyond the EOF. Treat it as if the data starts just after - * the header. - */ - cifs_dbg(FYI, "%s: data offset (%u) inside read response header\n", - __func__, data_offset); - data_offset =3D server->total_read; - } else if (data_offset > MAX_CIFS_SMALL_BUFFER_SIZE) { - /* data_offset is beyond the end of smallbuf */ - cifs_dbg(FYI, "%s: data offset (%u) beyond end of smallbuf\n", - __func__, data_offset); - rdata->result =3D smb_EIO1(smb_eio_trace_read_overlarge, - data_offset); - return cifs_readv_discard(server, smb); - } - - cifs_dbg(FYI, "%s: total_read=3D%u data_offset=3D%u\n", - __func__, server->total_read, data_offset); - - len =3D data_offset - server->total_read; - if (len > 0) { - /* read any junk before data into the rest of smallbuf */ - length =3D cifs_read_from_socket(server, - buf + server->total_read, len); - if (length < 0) - return length; - server->total_read +=3D length; - rdata->iov[0].iov_len =3D server->total_read; - } - - /* how much data is in the response? */ -#ifdef CONFIG_CIFS_SMB_DIRECT - use_rdma_mr =3D rdata->mr; -#endif - data_len =3D server->ops->read_data_length(buf, use_rdma_mr); - if (!use_rdma_mr) { - if (check_add_overflow(data_offset, data_len, &end_off) || - end_off > buflen) { - /* data_len is corrupt -- discard frame */ - rdata->result =3D smb_EIO2(smb_eio_trace_read_rsp_malformed, - end_off, buflen); - return cifs_readv_discard(server, smb); - } - } - -#ifdef CONFIG_CIFS_SMB_DIRECT - if (rdata->mr) { - length =3D data_len; /* An RDMA read is already done. */ - } else { -#endif - struct iov_iter iter; - - iov_iter_bvec_queue(&iter, ITER_DEST, rdata->subreq.content.bvecq, - rdata->subreq.content.slot, rdata->subreq.content.offset, - data_len); - length =3D cifs_read_iter_from_socket(server, &iter, data_len); -#ifdef CONFIG_CIFS_SMB_DIRECT - } -#endif - if (length > 0) - rdata->got_bytes +=3D length; - server->total_read +=3D length; - - cifs_dbg(FYI, "total_read=3D%u buflen=3D%u remaining=3D%u\n", - server->total_read, buflen, data_len); - - /* discard anything left over */ - if (server->total_read < buflen) - return cifs_readv_discard(server, smb); - - dequeue_mid(server, smb, false); - smb->resp_buf =3D server->smallbuf; - server->smallbuf =3D NULL; - return length; -} diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index dc5ec2643669..3d69daf8d7ef 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -1782,4 +1782,34 @@ struct smb2_lease_ack { #define SET_MINIMUM_RIGHTS (FILE_READ_EA | FILE_READ_ATTRIBUTES \ | READ_CONTROL | SYNCHRONIZE) =20 +union smb2_response_hdr { + struct { + struct smb2_hdr hdr; + /* size of wct area (varies, request specific) */ + __le16 StructureSize2; + } __packed; + struct smb2_pdu pdu; + struct smb2_err_rsp err; + struct smb2_negotiate_rsp neg; + struct smb2_sess_setup_rsp sess; + struct smb2_logoff_rsp logoff; + struct smb2_tree_connect_rsp tcon; + struct smb2_tree_disconnect_rsp tdis; + struct smb2_create_rsp create; + struct smb2_close_rsp close; + struct smb2_flush_rsp flush; + struct smb2_read_rsp read; + struct smb2_write_rsp write; + struct smb2_lock_rsp lock; + struct smb2_ioctl_rsp ioctl; + /* No cancel response */ + struct smb2_echo_rsp echo; + struct smb2_query_directory_rsp qdir; + struct smb2_change_notify_rsp change; + struct smb2_query_info_rsp qinfo; + struct smb2_set_info_rsp sinfo; + struct smb2_oplock_break oplock; + struct smb2_lease_break lease; +}; + #endif /* _COMMON_SMB2PDU_H */ From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 55B0C3A9D89 for ; Tue, 19 May 2026 10:23:18 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186200; cv=none; b=BczKrKMkMU1bSBwHjVL22TqSlt8UCpYK/kcixLzTuvfuvWpZ1KUhnzsgqvb9IgSXGyA+CTKo5lj/ccvfF+7A4SiBkhU0eSmuURuMDGzfZjX7MVzPTLe0YctHRF9hgQAVZPPMas/jq32eMN72osF8YMzNNWp/3okuoXfkotsqfTw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186200; c=relaxed/simple; bh=XShjgtXhP+tYiq2TplGgGhv4z9FLJ6VOMvOUzEinfso=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=a8isfzdFwi429Vh889k/hNpuxE04kaCFBqnCYeEi2Of+TmwpMkMePYUgSjuIMgAX/0sMmr8Gk6ptREWx+0BJs0yKgc8noguVDg5lz1sR//rWRjBk6FvgFNFnzL1BAaxXB1zJmOREJTVgGLjfSZXZ/FXVaUk7iMGIPrzz0C5M93A= 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=R4sdTTqy; arc=none smtp.client-ip=170.10.133.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="R4sdTTqy" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186197; 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=R38LEhSUg0zG7CZXQr66Y4eG2u+dIMP8sPcWKJpzAyM=; b=R4sdTTqyQSpfrkZhD/L/xam1s0FHNdyhz5AgZwotQNrz5EwMnlLDZz8fgIiZPLuDftRTXF WQ+CKR99W4tVJIRDmuAziqvZHkBs/wSvY+Vglrd2xIl8uvu4CNC/Jk7rf9VsEOeoysC4hY gSKtBkLjXND8L+PVurPYRn+W2gcCCEc= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-676-rZEWN4nsNFyMhzQSAIXsaQ-1; Tue, 19 May 2026 06:23:12 -0400 X-MC-Unique: rZEWN4nsNFyMhzQSAIXsaQ-1 X-Mimecast-MFC-AGG-ID: rZEWN4nsNFyMhzQSAIXsaQ_1779186190 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4574C19560A7; Tue, 19 May 2026 10:23:10 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1BD7519560A2; Tue, 19 May 2026 10:23:06 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 13/36] cifs: Remove validate_t2() Date: Tue, 19 May 2026 11:21:31 +0100 Message-ID: <20260519102158.592165-14-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.12 Content-Type: text/plain; charset="utf-8" validate_t2() is no longer necessary as the checking is now done up front. 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/cifssmb.c | 132 +++++++--------------------------------- 1 file changed, 22 insertions(+), 110 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index c537cc3e66c8..901f8aff6134 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -332,40 +332,6 @@ smb_init_no_reconnect(int smb_command, int wct, struct= cifs_tcon *tcon, return __smb_init(smb_command, wct, tcon, request_buf, response_buf); } =20 -static int validate_t2(struct smb_t2_rsp *pSMB) -{ - unsigned int total_size; - - return 0; /* Checking now done in reception routine. */ - - /* check for plausible wct */ - if (pSMB->hdr.WordCount < 10) - goto vt2_err; - - /* check for parm and data offset going beyond end of smb */ - if (get_unaligned_le16(&pSMB->t2_rsp.ParameterOffset) > 1024 || - get_unaligned_le16(&pSMB->t2_rsp.DataOffset) > 1024) - goto vt2_err; - - total_size =3D get_unaligned_le16(&pSMB->t2_rsp.ParameterCount); - if (total_size >=3D 512) - goto vt2_err; - - /* check that bcc is at least as big as parms + data, and that it is - * less than negotiated smb buffer - */ - total_size +=3D get_unaligned_le16(&pSMB->t2_rsp.DataCount); - if (total_size > get_bcc(&pSMB->hdr) || - total_size >=3D CIFSMaxBufSize + MAX_CIFS_HDR_SIZE) - goto vt2_err; - - return 0; -vt2_err: - cifs_dump_mem("Invalid transact2 SMB: ", (char *)pSMB, - sizeof(struct smb_t2_rsp) + 16); - return -EINVAL; -} - static int decode_ext_sec_blob(struct cifs_ses *ses, SMB_NEGOTIATE_RSP *pSMBr) { @@ -1122,9 +1088,7 @@ CIFSPOSIXCreate(const unsigned int xid, struct cifs_t= con *tcon, } =20 cifs_dbg(FYI, "copying inode info\n"); - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { + if (get_bcc(&pSMBr->hdr) < sizeof(OPEN_PSX_RSP)) { rc =3D smb_EIO2(smb_eio_trace_create_rsp_too_small, get_bcc(&pSMBr->hdr), sizeof(OPEN_PSX_RSP)); goto psx_create_err; @@ -2372,9 +2336,7 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_= tcon *tcon, /* lock structure can be returned on get */ __u16 data_offset; __u16 data_count; - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { + if (get_bcc(&pSMBr->hdr) < sizeof(*parm_data)) { rc =3D smb_EIO2(smb_eio_trace_lock_bcc_too_small, get_bcc(&pSMBr->hdr), sizeof(*parm_data)); goto plk_err_exit; @@ -2939,9 +2901,8 @@ CIFSSMBUnixQuerySymLink(const unsigned int xid, struc= t cifs_tcon *tcon, } else { /* decode response */ =20 - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || get_bcc(&pSMBr->hdr) < 2) + if (get_bcc(&pSMBr->hdr) < 2) rc =3D smb_EIO2(smb_eio_trace_qsym_bcc_too_small, get_bcc(&pSMBr->hdr), 2); else { @@ -3524,9 +3485,8 @@ int cifs_do_get_acl(const unsigned int xid, struct ci= fs_tcon *tcon, } else { /* decode response */ =20 - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || get_bcc(&pSMBr->hdr) < 2) + if (get_bcc(&pSMBr->hdr) < 2) rc =3D smb_EIO2(smb_eio_trace_getacl_bcc_too_small, get_bcc(&pSMBr->hdr), 2); else { @@ -3696,9 +3656,8 @@ CIFSGetExtAttr(const unsigned int xid, struct cifs_tc= on *tcon, cifs_dbg(FYI, "error %d in GetExtAttr\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || get_bcc(&pSMBr->hdr) < 2) + if (get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc =3D smb_EIO2(smb_eio_trace_getextattr_bcc_too_small, @@ -4099,12 +4058,7 @@ CIFSSMBQFileInfo(const unsigned int xid, struct cifs= _tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in QFileInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc) /* BB add auto retry on EOPNOTSUPP? */ - rc =3D smb_EIO2(smb_eio_trace_qfileinfo_invalid, - get_bcc(&pSMBr->hdr), 40); - else if (get_bcc(&pSMBr->hdr) < 40) + if (get_bcc(&pSMBr->hdr) < 40) rc =3D smb_EIO2(smb_eio_trace_qfileinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 40); else if (pFindData) { @@ -4188,12 +4142,7 @@ CIFSSMBQPathInfo(const unsigned int xid, struct cifs= _tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in QPathInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc) /* BB add auto retry on EOPNOTSUPP? */ - rc =3D smb_EIO2(smb_eio_trace_qpathinfo_invalid, - get_bcc(&pSMBr->hdr), 40); - else if (!legacy && get_bcc(&pSMBr->hdr) < 40) + if (!legacy && get_bcc(&pSMBr->hdr) < 40) rc =3D smb_EIO2(smb_eio_trace_qpathinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 40); else if (legacy && get_bcc(&pSMBr->hdr) < 24) @@ -4275,9 +4224,7 @@ CIFSSMBUnixQFileInfo(const unsigned int xid, struct c= ifs_tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in UnixQFileInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { + if (get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions= can be disabled on mount by specifying the nosfu mount option.\n"); rc =3D smb_EIO2(smb_eio_trace_unixqfileinfo_bcc_too_small, get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO)); @@ -4360,9 +4307,7 @@ CIFSSMBUnixQPathInfo(const unsigned int xid, struct c= ifs_tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in UnixQPathInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { + if (get_bcc(&pSMBr->hdr) < sizeof(FILE_UNIX_BASIC_INFO)) { cifs_dbg(VFS, "Malformed FILE_UNIX_BASIC_INFO response. Unix Extensions= can be disabled on mount by specifying the nosfu mount option.\n"); rc =3D smb_EIO2(smb_eio_trace_unixqpathinfo_bcc_too_small, get_bcc(&pSMBr->hdr), sizeof(FILE_UNIX_BASIC_INFO)); @@ -4504,13 +4449,8 @@ CIFSFindFirst(const unsigned int xid, struct cifs_tc= on *tcon, goto findFirstRetry; return rc; } - /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc) { - cifs_buf_release(pSMB); - return rc; - } =20 + /* decode response */ psrch_inf->unicode =3D !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); psrch_inf->ntwrk_buf_start =3D (char *)pSMBr; psrch_inf->smallBuf =3D false; @@ -4619,11 +4559,6 @@ int CIFSFindNext(const unsigned int xid, struct cifs= _tcon *tcon, } =20 /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc) { - cifs_buf_release(pSMB); - return rc; - } /* BB fixme add lock for file (srch_info) struct here */ psrch_inf->unicode =3D !!(pSMBr->hdr.Flags2 & SMBFLG2_UNICODE); response_data =3D (char *)&pSMBr->hdr.Protocol + @@ -4763,9 +4698,8 @@ CIFSGetSrvInodeNumber(const unsigned int xid, struct = cifs_tcon *tcon, cifs_dbg(FYI, "error %d in QueryInternalInfo\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); /* BB also check enough total bytes returned */ - if (rc || get_bcc(&pSMBr->hdr) < 2) + if (get_bcc(&pSMBr->hdr) < 2) /* If rc should we check for EOPNOSUPP and disable the srvino flag? or in caller? */ rc =3D smb_EIO2(smb_eio_trace_getsrvinonum_bcc_too_small, @@ -4883,10 +4817,9 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_= ses *ses, cifs_dbg(FYI, "Send error in GetDFSRefer =3D %d\n", rc); goto GetDFSRefExit; } - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); =20 /* BB Also check if enough total bytes returned? */ - if (rc || get_bcc(&pSMBr->hdr) < 17) { + if (get_bcc(&pSMBr->hdr) < 17) { rc =3D smb_EIO2(smb_eio_trace_getdfsrefer_bcc_too_small, get_bcc(&pSMBr->hdr), 17); goto GetDFSRefExit; @@ -4961,12 +4894,10 @@ SMBOldQFSInfo(const unsigned int xid, struct cifs_t= con *tcon, if (rc) { cifs_dbg(FYI, "Send error in QFSInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < 18) + if (get_bcc(&pSMBr->hdr) < 18) { rc =3D smb_EIO2(smb_eio_trace_oldqfsinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 18); - else { + } else { __u16 data_offset =3D le16_to_cpu(pSMBr->t2.DataOffset); cifs_dbg(FYI, "qfsinf resp BCC: %d Offset %d\n", get_bcc(&pSMBr->hdr), data_offset); @@ -5051,12 +4982,10 @@ CIFSSMBQFSInfo(const unsigned int xid, struct cifs_= tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in QFSInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < 24) + if (get_bcc(&pSMBr->hdr) < 24) { rc =3D smb_EIO2(smb_eio_trace_qfsinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 24); - else { + } else { __u16 data_offset =3D le16_to_cpu(pSMBr->t2.DataOffset); =20 response_data =3D @@ -5141,9 +5070,7 @@ CIFSSMBQFSAttributeInfo(const unsigned int xid, struc= t cifs_tcon *tcon) if (rc) { cifs_dbg(VFS, "Send error in QFSAttributeInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < 13) { + if (get_bcc(&pSMBr->hdr) < 13) { /* BB also check if enough bytes returned */ rc =3D smb_EIO2(smb_eio_trace_qfsattrinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 13); @@ -5215,9 +5142,7 @@ CIFSSMBQFSDeviceInfo(const unsigned int xid, struct c= ifs_tcon *tcon) if (rc) { cifs_dbg(FYI, "Send error in QFSDeviceInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < + if (get_bcc(&pSMBr->hdr) < sizeof(FILE_SYSTEM_DEVICE_INFO)) rc =3D smb_EIO2(smb_eio_trace_qfsdevinfo_bcc_too_small, get_bcc(&pSMBr->hdr), @@ -5289,9 +5214,7 @@ CIFSSMBQFSUnixInfo(const unsigned int xid, struct cif= s_tcon *tcon) if (rc) { cifs_dbg(VFS, "Send error in QFSUnixInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < 13) { + if (get_bcc(&pSMBr->hdr) < 13) { rc =3D smb_EIO2(smb_eio_trace_qfsunixinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 13); } else { @@ -5371,13 +5294,8 @@ CIFSSMBSetFSUnixInfo(const unsigned int xid, struct = cifs_tcon *tcon, __u64 cap) =20 rc =3D SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB, in_len, (struct smb_hdr *) pSMBr, &bytes_returned, 0); - if (rc) { + if (rc) cifs_dbg(VFS, "Send error in SETFSUnixInfo =3D %d\n", rc); - } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc) - rc =3D -EIO; /* bad smb */ - } cifs_buf_release(pSMB); =20 if (rc =3D=3D -EAGAIN) @@ -5438,9 +5356,7 @@ CIFSSMBQFSPosixInfo(const unsigned int xid, struct ci= fs_tcon *tcon, if (rc) { cifs_dbg(FYI, "Send error in QFSUnixInfo =3D %d\n", rc); } else { /* decode response */ - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - - if (rc || get_bcc(&pSMBr->hdr) < 13) { + if (get_bcc(&pSMBr->hdr) < 13) { rc =3D smb_EIO2(smb_eio_trace_qfsposixinfo_bcc_too_small, get_bcc(&pSMBr->hdr), 13); } else { @@ -6237,11 +6153,7 @@ CIFSSMBQAllEAs(const unsigned int xid, struct cifs_t= con *tcon, =20 =20 /* BB also check enough total bytes returned */ - /* BB we need to improve the validity checking - of these trans2 responses */ - - rc =3D validate_t2((struct smb_t2_rsp *)pSMBr); - if (rc || get_bcc(&pSMBr->hdr) < 4) { + if (get_bcc(&pSMBr->hdr) < 4) { rc =3D smb_EIO2(smb_eio_trace_qalleas_bcc_too_small, get_bcc(&pSMBr->hdr), 4); goto QAllEAsOut; From nobody Mon May 25 02:42:24 2026 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 14AEA3F0760 for ; Tue, 19 May 2026 10:23:21 +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=1779186204; cv=none; b=YVZ8NWCxifoGXrpuvfl/Wrw8RrVQYNSJX6UlW9QC/8cpRhzjsHP5x9wH90w/TfAdsOc/9hU3ZFd3+1dY5MWN+fqZdwdTV2DqUyKnsdi6HkjX02SMMR7Bk8WD8I/IKnqPKdld7lkver9vgvfZjxLeG48iKzzy9hr4RjLbR6oBgsE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186204; c=relaxed/simple; bh=K3b5Dyat0A8f/elx3HTfTo8qt8eIWF6txSPsXm2YHTI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TxYcsc3TbAedtuKuIA3JRDTrsUDyr6GrpWD32Ag8d/gnG9b3Y11LTLddl0WDv6bKtbOxdAe3Ls6teF/ZiffmGtuF4rnLwcP508Ri0E26PWdUGkHWLH2wnvc3Ql0aW0yqkvl1C9OIeMvCPfIuK/qIo+avcjDgOzH1+3nEkzvTs14= 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=JnL6F/2l; 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="JnL6F/2l" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186201; 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=0AnFeCjYcDDfsH1O+KLQZ11YU9SELl0/imvW9W9ZBoc=; b=JnL6F/2lN7ZtQtZnzNspJPO+8hxrA/LlnYD3Nm7B9hVNOoJYGibeYapbsRdXc75vMdpzly QuxJYYsfp/JOo0XCqXVkQsIven3VMcyoQePe1sjXw6fZwu/pv+WsUk6t+2GrHQqiZIqm9T Sx8Y9gS2Oyt+qGZvAGk3dnqjQi3yi24= 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-231-JEbCGXKHOt2HxxgowKq9Cg-1; Tue, 19 May 2026 06:23:16 -0400 X-MC-Unique: JEbCGXKHOt2HxxgowKq9Cg-1 X-Mimecast-MFC-AGG-ID: JEbCGXKHOt2HxxgowKq9Cg_1779186195 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 36D3118002E3; Tue, 19 May 2026 10:23:15 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EC1FA30001A2; Tue, 19 May 2026 10:23:11 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 14/36] cifs: Remove cifs_io_subrequest::got_bytes Date: Tue, 19 May 2026 11:21:32 +0100 Message-ID: <20260519102158.592165-15-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Remove cifs_io_subrequest::got_bytes as smb->resp_data_len can be used instead. 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/cifsglob.h | 1 - fs/smb/client/cifssmb.c | 27 +++++++++++++-------------- fs/smb/client/smb2pdu.c | 22 ++++++++++------------ 3 files changed, 23 insertions(+), 27 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 7187e304c42e..2cb858495bc1 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1467,7 +1467,6 @@ struct cifs_io_subrequest { struct netfs_io_request *rreq; struct cifs_io_request *req; }; - ssize_t got_bytes; unsigned int xid; int result; bool have_xid; diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 901f8aff6134..62f554f97a5c 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1450,7 +1450,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) __func__, smb->mid, smb->mid_state, rdata->result, rdata->subreq.len); =20 - if (rdata->got_bytes) + if (smb->resp_data_len) iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, rdata->subreq.content.bvecq, rdata->subreq.content.slot, rdata->subreq.content.offset, rdata->subreq.len); @@ -1458,9 +1458,8 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: /* result already set, check signature */ - rdata->got_bytes =3D smb->resp_data_len; if (server->sign) { - int rc =3D 0; + int rc; =20 iov_iter_truncate(&rqst.rq_iter, smb->resp_data_len); rc =3D cifs_verify_signature(&rqst, server, @@ -1470,8 +1469,8 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) rc); } /* FIXME: should this be counted toward the initiating task? */ - task_io_account_read(rdata->got_bytes); - cifs_stats_bytes_read(tcon, rdata->got_bytes); + task_io_account_read(smb->resp_data_len); + cifs_stats_bytes_read(tcon, smb->resp_data_len); break; case MID_REQUEST_SUBMITTED: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted); @@ -1481,12 +1480,12 @@ cifs_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) do_retry: __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); rdata->result =3D -EAGAIN; - if (server->sign && rdata->got_bytes) + if (server->sign && smb->resp_data_len) /* reset bytes number since we can not check a sign */ - rdata->got_bytes =3D 0; + smb->resp_data_len =3D 0; /* FIXME: should this be counted toward the initiating task? */ - task_io_account_read(rdata->got_bytes); - cifs_stats_bytes_read(tcon, rdata->got_bytes); + task_io_account_read(smb->resp_data_len); + cifs_stats_bytes_read(tcon, smb->resp_data_len); break; case MID_RESPONSE_MALFORMED: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed); @@ -1511,15 +1510,15 @@ cifs_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) rdata->subreq.len - rdata->subreq.transferred, rdata->result); } else { - size_t trans =3D rdata->subreq.transferred + rdata->got_bytes; + size_t trans =3D rdata->subreq.transferred + smb->resp_data_len; if (trans < rdata->subreq.len && rdata->subreq.start + trans >=3D netfs_read_remote_i_size(inode)) { rdata->result =3D 0; __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); - } else if (rdata->got_bytes > 0) { + } else if (smb->resp_data_len > 0) { __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); } - if (rdata->got_bytes) + if (smb->resp_data_len) __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); trace_smb3_read_done(rdata->rreq->debug_id, rdata->subreq.debug_index, @@ -1527,7 +1526,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) rdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, rdata->subreq.start + rdata->subreq.transferred, - rdata->got_bytes); + smb->resp_data_len); } =20 trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, rdata->credits.v= alue, @@ -1535,7 +1534,7 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) 0, cifs_trace_rw_credits_read_response_clear); rdata->credits.value =3D 0; rdata->subreq.error =3D rdata->result; - rdata->subreq.transferred +=3D rdata->got_bytes; + rdata->subreq.transferred +=3D smb->resp_data_len; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); release_mid(server, smb); diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index ab193f84c1ab..ddf127dc27bb 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4671,10 +4671,9 @@ smb2_readv_callback(struct TCP_Server_Info *server, = struct smb_message *smb) trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); } =20 - rdata->got_bytes =3D smb->resp_data_len; /* FIXME: should this be counted toward the initiating task? */ - task_io_account_read(rdata->got_bytes); - cifs_stats_bytes_read(tcon, rdata->got_bytes); + task_io_account_read(smb->resp_data_len); + cifs_stats_bytes_read(tcon, smb->resp_data_len); break; case MID_REQUEST_SUBMITTED: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_req_submitted); @@ -4684,12 +4683,12 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) do_retry: __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); rdata->result =3D -EAGAIN; - if (server->sign && rdata->got_bytes) + if (server->sign && smb->resp_data_len) /* reset bytes number since we can not check a sign */ - rdata->got_bytes =3D 0; + smb->resp_data_len =3D 0; /* FIXME: should this be counted toward the initiating task? */ - task_io_account_read(rdata->got_bytes); - cifs_stats_bytes_read(tcon, rdata->got_bytes); + task_io_account_read(smb->resp_data_len); + cifs_stats_bytes_read(tcon, smb->resp_data_len); break; case MID_RESPONSE_MALFORMED: trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_malformed); @@ -4731,19 +4730,19 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) rdata->req->cfile->fid.persistent_fid, tcon->tid, tcon->ses->Suid, rdata->subreq.start + rdata->subreq.transferred, - rdata->got_bytes); + smb->resp_data_len); =20 if (rdata->result =3D=3D -ENODATA) { __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); rdata->result =3D 0; } else { - size_t trans =3D rdata->subreq.transferred + rdata->got_bytes; + size_t trans =3D rdata->subreq.transferred + smb->resp_data_len; if (trans < rdata->subreq.len && rdata->subreq.start + trans >=3D netfs_read_remote_i_size(inode)) { __set_bit(NETFS_SREQ_HIT_EOF, &rdata->subreq.flags); rdata->result =3D 0; } - if (rdata->got_bytes) + if (smb->resp_data_len) __set_bit(NETFS_SREQ_MADE_PROGRESS, &rdata->subreq.flags); } =20 @@ -4759,7 +4758,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) 0, cifs_trace_rw_credits_read_response_clear); rdata->credits.value =3D 0; rdata->subreq.error =3D rdata->result; - rdata->subreq.transferred +=3D rdata->got_bytes; + rdata->subreq.transferred +=3D smb->resp_data_len; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); release_mid(server, smb); @@ -4814,7 +4813,6 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) =20 rdata->iov[0].iov_base =3D buf; rdata->iov[0].iov_len =3D total_len; - rdata->got_bytes =3D 0; rdata->result =3D 0; =20 shdr =3D (struct smb2_hdr *)buf; From nobody Mon May 25 02:42:24 2026 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 0B7AB4BCAD9 for ; Tue, 19 May 2026 10:23:27 +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=1779186210; cv=none; b=uZRzaoT1/Awl82T5NOjoU2wYXkvCnFxj+oUPFzQMeFUmjOQd4WADV8DuF6i1+QyOGPMkOQEP/O4tLVmaHHXfB9ikyty2/p0VlYn+kW6ZjmU0dvVkTGgC7UVCUQGz6KsSpOBzFO+N9w1ntP+MKfsQMWjaSsn23NnIifS3+agiFFw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186210; c=relaxed/simple; bh=8jWa5UD6qXWED1La5NzDIlhGb8V4w6T4v1EVCHljhA4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FCFsXYu8uQ9+130V+RByW7yh8F4kM8noIAagWwmvHYpT37epwaAxbYd1oNxcrHsZ3WBGzOnITGdFP4hv12eZr/zE83TnYVZTzu1Y4AaYLBKXugFLPBjHbzsz7OTy4Y1FiKHIl816Ny6HN0dQEVDGiOCm1btU40xQVeZjre8ce7s= 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=QOUlvoGp; 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="QOUlvoGp" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186207; 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=VkysUk1MJocDAUy1EaC0Cxyx/GDmaeNWp9VU2xxTEok=; b=QOUlvoGpdZXaylpsXsBA1G2znb8+N5vMYvh9SCFN0q4Ip4fFjnKsCV7cTEU2Hc9UOd0fH8 HQCjmG8c1h01Q1cRA7+IoO7d3zIMI4EREMRCU0m8frtJa+xa1OrtunXEb1TlgIzjEyzBOv 4IclbXVE9oQWVdGKZyfI8/gGVOcnTxQ= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-587-NK3ItpY7NCi8nulgm2h-uw-1; Tue, 19 May 2026 06:23:21 -0400 X-MC-Unique: NK3ItpY7NCi8nulgm2h-uw-1 X-Mimecast-MFC-AGG-ID: NK3ItpY7NCi8nulgm2h-uw_1779186200 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 2F198195608D; Tue, 19 May 2026 10:23:20 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E4CC0180034E; Tue, 19 May 2026 10:23:16 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 15/36] cifs: Pass smb_message to cifs_verify_signature() Date: Tue, 19 May 2026 11:21:33 +0100 Message-ID: <20260519102158.592165-16-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Pass smb_message to cifs_verify_signature() rather than an smb_rqst. 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/cifssmb.c | 13 +------------ fs/smb/client/smb1encrypt.c | 19 ++++++++++++++----- fs/smb/client/smb1proto.h | 2 +- fs/smb/client/smb1transport.c | 16 ++++------------ 4 files changed, 20 insertions(+), 30 deletions(-) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index 62f554f97a5c..c5b18e1c44ab 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1432,11 +1432,6 @@ cifs_readv_callback(struct TCP_Server_Info *server, = struct smb_message *smb) struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct inode *inode =3D &ictx->inode; - struct kvec iov =3D { - .iov_base =3D smb->response, - .iov_len =3D smb->resp_len, - }; - struct smb_rqst rqst =3D { .rq_iov =3D &iov, .rq_nvec =3D 1 }; struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0, @@ -1450,19 +1445,13 @@ cifs_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) __func__, smb->mid, smb->mid_state, rdata->result, rdata->subreq.len); =20 - if (smb->resp_data_len) - iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); - switch (smb->mid_state) { case MID_RESPONSE_RECEIVED: /* result already set, check signature */ if (server->sign) { int rc; =20 - iov_iter_truncate(&rqst.rq_iter, smb->resp_data_len); - rc =3D cifs_verify_signature(&rqst, server, + rc =3D cifs_verify_signature(smb, server, smb->sequence_number); if (rc) cifs_dbg(VFS, "SMB signature verification returned error =3D %d\n", diff --git a/fs/smb/client/smb1encrypt.c b/fs/smb/client/smb1encrypt.c index 819c736c26e9..c61202ae54c6 100644 --- a/fs/smb/client/smb1encrypt.c +++ b/fs/smb/client/smb1encrypt.c @@ -106,14 +106,23 @@ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_= Server_Info *server, return rc; } =20 -int cifs_verify_signature(struct smb_rqst *rqst, +int cifs_verify_signature(struct smb_message *smb, struct TCP_Server_Info *server, __u32 expected_sequence_number) { - unsigned int rc; - char server_response_sig[8]; + struct smb_hdr *cifs_pdu =3D smb->response; + struct kvec iov =3D { + .iov_base =3D smb->response, + .iov_len =3D smb->resp_len, + }; + struct smb_rqst rqst =3D { + .rq_iov =3D &iov, + .rq_nvec =3D 1, + .rq_iter =3D smb->response_iter + }; char what_we_think_sig_should_be[20]; - struct smb_hdr *cifs_pdu =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; + char server_response_sig[8]; + int rc; =20 if (cifs_pdu =3D=3D NULL || server =3D=3D NULL) return -EINVAL; @@ -145,7 +154,7 @@ int cifs_verify_signature(struct smb_rqst *rqst, cifs_pdu->Signature.Sequence.Reserved =3D 0; =20 cifs_server_lock(server); - rc =3D cifs_calc_signature(rqst, server, what_we_think_sig_should_be); + rc =3D cifs_calc_signature(&rqst, server, what_we_think_sig_should_be); cifs_server_unlock(server); =20 if (rc) diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index b2ad0ef64051..54a5261fabce 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -227,7 +227,7 @@ void cifs_dump_mids(struct TCP_Server_Info *server); */ int cifs_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server, __u32 *pexpected_response_sequence_number); -int cifs_verify_signature(struct smb_rqst *rqst, +int cifs_verify_signature(struct smb_message *smb, struct TCP_Server_Info *server, __u32 expected_sequence_number); int cifs_verify_trans_signature(struct TCP_Server_Info *server, diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 776d615f69d3..a6af5bd20847 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -156,22 +156,14 @@ int cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *server, bool log_error) { - unsigned int len =3D smb->resp_len; - - dump_smb(smb->response, min_t(u32, 92, len)); + dump_smb(smb->response, min_t(u32, 92, smb->resp_len)); =20 /* convert the length into a more usable form */ if (server->sign && !smb->sig_checked) { - struct kvec iov[1]; - int rc =3D 0; - struct smb_rqst rqst =3D { .rq_iov =3D iov, - .rq_nvec =3D ARRAY_SIZE(iov) }; - - iov[0].iov_base =3D smb->response; - iov[0].iov_len =3D len; + int rc; =20 - rc =3D cifs_verify_signature(&rqst, server, - smb->sequence_number); + /* FIXME: add code to kill session */ + rc =3D cifs_verify_signature(smb, server, smb->sequence_number); if (rc) { cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d\= n", rc); From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 82B8F4C9010 for ; Tue, 19 May 2026 10:23:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186216; cv=none; b=C8231gBXN1GayZfV3wggHA+UceWhc251VS2wuzmJZ/vsThlIA7HEo9cDQRzATOxtzt3PJ0hRQALajv4yvmbAYMJDw5YdN0pnEqZ1fpuiHGaMpKl1mZ2WLvjfY5OaCnfC1+JYJqYM9osAQtzpZBABE6/rlkaOH9Nmhm8giCLLxs0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186216; c=relaxed/simple; bh=g+ijh7/c1PEgpxPJor1DHHycglJ/fnc6Vcp8X1j2EQE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NpfpE2qgYbcE5JOqQSMJQfdFGDX5939qqbquAsHuJx4A4vPqPGTHoAfGi8wg3Z29hIP8RYffscK73kb3G5/IfAW5maVAQnqDgv1TCoYfTHAopYq80NgJNnC04kgOuIX53pZm0cVesamxp3m2G6MaYUIK2jSQ5U7O0xsQEe/qcRA= 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=L4fVjJFD; arc=none smtp.client-ip=170.10.133.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="L4fVjJFD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186212; 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=dUm2ymb+Z+C06z675gVNuLek4wdEgPlZXQgp2CIxoCM=; b=L4fVjJFD4MBqEA4sNrZUBLDdPJ66vUvVu4NNbTyN0NofFoxQrGEA9/F1Vr35PyF8HWK6b+ 3RJKgXf92qefn7LMZ38Enish92usk8hAjyjJA/jVvkgu4dLdVdboRkXQpj7mrp9t48GpxD 04OSjtmCv8uRxL122+MMYgvTRo6Zc8Y= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-392-3IxGYNejO9OSsk48gae8dQ-1; Tue, 19 May 2026 06:23:27 -0400 X-MC-Unique: 3IxGYNejO9OSsk48gae8dQ-1 X-Mimecast-MFC-AGG-ID: 3IxGYNejO9OSsk48gae8dQ_1779186205 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6BE611956050; Tue, 19 May 2026 10:23:25 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id BFC411800576; Tue, 19 May 2026 10:23:21 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 16/36] cifs: Rewrite base TCP transmission Date: Tue, 19 May 2026 11:21:34 +0100 Message-ID: <20260519102158.592165-17-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Rewrite the base TCP transmission in cifs to copy all the content in a (compound) message into a buffer of pages in a bvecq chain. In future, the pages in this bvecq chain will be allocated from the netmem allocator so that the advance DMA/IOMMU handling will be done. This list of pages can then be attached to an ITER_BVEC_QUEUE-type iov_iter and passed in a single call to sendmsg() with MSG_SPLICE_PAGES, thereby avoiding the need to copy the data in the TCP stack. The encryption code can also be simplified as it only needs to encrypt the data stored in those pages, with the bonus that the content in the pages is correctly aligned for the encryption in place such that it does not need to copy the data whilst encrypting it. It could be arranged for the data to be held in contiguous pages if possible and if necessary such that crypto can be offloaded to devices that only permit a single contiguous buffer. Note that with this patch, "mount -o compress,seal" will now compress writes and then encrypt them. 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/cifsglob.h | 6 +- fs/smb/client/cifsproto.h | 3 +- fs/smb/client/compress.c | 146 ++++++++----- fs/smb/client/compress.h | 10 +- fs/smb/client/smb1ops.c | 5 +- fs/smb/client/smb2ops.c | 273 +----------------------- fs/smb/client/smb2proto.h | 4 + fs/smb/client/smb2transport.c | 113 ++++++++++ fs/smb/client/smbdirect.c | 105 ++------- fs/smb/client/smbdirect.h | 5 +- fs/smb/client/transport.c | 387 +++++++++++++++++++++++----------- 11 files changed, 517 insertions(+), 540 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 2cb858495bc1..f7c12d24e2ea 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -571,8 +571,10 @@ struct smb_version_operations { long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, loff_t); /* init transform (compress/encrypt) request */ - int (*init_transform_rq)(struct TCP_Server_Info *, int num_rqst, - struct smb_rqst *, struct smb_rqst *); + int (*init_transform_rq)(struct TCP_Server_Info *server, + int num_rqst, const struct smb_rqst *rqst, + struct smb2_transform_hdr *tr_hdr, + struct iov_iter *iter); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(struct TCP_Server_Info *server, char *buf, diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 8dedfd677f8d..1c9ac67b7294 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -106,8 +106,7 @@ int compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, int *resp_buf_type, struct kvec *resp_iov); int cifs_sync_mid_result(struct smb_message *mid, struct TCP_Server_Info *server); -int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst); +int __smb_send_rqst(struct TCP_Server_Info *server, struct iov_iter *iter); int wait_for_free_request(struct TCP_Server_Info *server, const int flags, unsigned int *instance); int cifs_wait_mtu_credits(struct TCP_Server_Info *server, size_t size, diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c index be9023f841e6..a9496983ac56 100644 --- a/fs/smb/client/compress.c +++ b/fs/smb/client/compress.c @@ -16,6 +16,7 @@ #include #include #include +#include =20 #include "cifsglob.h" #include "../common/smb2pdu.h" @@ -191,7 +192,7 @@ static int collect_sample(const struct iov_iter *source= , ssize_t max, u8 *sample * Tests shows that this function is quite reliable in predicting data com= pressibility, * matching close to 1:1 with the behaviour of LZ77 compression success an= d failures. */ -static bool is_compressible(const struct iov_iter *data) +bool is_compressible(const struct iov_iter *data) { const size_t read_size =3D SZ_2K, bkt_size =3D 256, max =3D SZ_4M; struct bucket *bkt =3D NULL; @@ -295,74 +296,123 @@ bool should_compress(const struct cifs_tcon *tcon, c= onst struct smb_rqst *rq) if (le32_to_cpu(wreq->Length) < SMB_COMPRESS_MIN_LEN) return false; =20 - return is_compressible(&rq->rq_iter); + return true; } =20 return (shdr->Command =3D=3D SMB2_READ); } =20 -int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, comp= ress_send_fn send_fn) +/* + * vmap the pages from a BVECQ-type iterator. + */ +static void *vmap_bvecq(struct iov_iter *iter, pgprot_t prot) { - struct iov_iter iter; - u32 slen, dlen; - void *src, *dst =3D NULL; - int ret; + struct page **pages =3D NULL; + ssize_t size, offset; + void *map; =20 - if (!server || !rq || !rq->rq_iov || !rq->rq_iov->iov_base) - return -EINVAL; + if (WARN_ON(!iov_iter_is_bvecq(iter))) + return ERR_PTR(-EIO); =20 - if (rq->rq_iov->iov_len !=3D sizeof(struct smb2_write_req)) - return -EINVAL; + size =3D iov_iter_extract_pages(iter, &pages, INT_MAX, INT_MAX, 0, &offse= t); + if (size < 0) + return ERR_PTR(size); =20 - slen =3D iov_iter_count(&rq->rq_iter); - src =3D kvzalloc(slen, GFP_KERNEL); - if (!src) { - ret =3D -ENOMEM; - goto err_free; + if (size =3D=3D 0 || offset > 0) { + kvfree(pages); + return ERR_PTR(-EIO); } =20 - /* Keep the original iter intact. */ - iter =3D rq->rq_iter; + map =3D vmap(pages, DIV_ROUND_UP(size, PAGE_SIZE), 0, prot); + kvfree(pages); + if (!map) + return ERR_PTR(-ENOMEM); + return map; +} + +int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, + struct bvecq **bq) +{ + struct smb2_compression_hdr *z_hdr; + struct smb2_write_req *w_hdr; + struct smb2_hdr *shdr; + struct iov_iter tmp; + struct bvecq *sbq =3D *bq, *dbq =3D NULL; + void *src, *dst =3D NULL; + u32 slen, dlen, hlen, datalen; + int ret; =20 - if (!copy_from_iter_full(src, slen, &iter)) { - ret =3D smb_EIO(smb_eio_trace_compress_copy); + /* We need contiguous buffers for the compression algorithm. */ + slen =3D iov_iter_count(iter); + src =3D vmap_bvecq(iter, PAGE_KERNEL_RO); + if (IS_ERR(src)) { + ret =3D PTR_ERR(src); + src =3D NULL; goto err_free; } =20 + shdr =3D src; + hlen =3D le16_to_cpu(shdr->StructureSize); + w_hdr =3D src; + hlen =3D le16_to_cpu(w_hdr->DataOffset); + datalen =3D le32_to_cpu(w_hdr->Length); + if (datalen !=3D slen - hlen) { + pr_warn("datalen %x !=3D slen-hlen %x\n", datalen, slen - hlen); + return -EMSGSIZE; + } + + /* + * This is just overprovisioning, as the algorithm will error out if @dst= reaches 7/8 + * of @slen. + */ dlen =3D lz77_compressed_alloc_size(slen); - dst =3D kvzalloc(dlen, GFP_KERNEL); - if (!dst) { + dlen =3D sizeof(*z_hdr) + slen; + dbq =3D bvecq_alloc_buffer(dlen, GFP_NOFS); + if (!dbq) { ret =3D -ENOMEM; goto err_free; } =20 - ret =3D lz77_compress(src, slen, dst, &dlen); - if (!ret) { - struct smb2_compression_hdr hdr =3D { 0 }; - struct smb_rqst comp_rq =3D { .rq_nvec =3D 3, }; - struct kvec iov[3]; - - hdr.ProtocolId =3D SMB2_COMPRESSION_TRANSFORM_ID; - hdr.OriginalCompressedSegmentSize =3D cpu_to_le32(slen); - hdr.CompressionAlgorithm =3D SMB3_COMPRESS_LZ77; - hdr.Flags =3D SMB2_COMPRESSION_FLAG_NONE; - hdr.Offset =3D cpu_to_le32(rq->rq_iov[0].iov_len); - - iov[0].iov_base =3D &hdr; - iov[0].iov_len =3D sizeof(hdr); - iov[1] =3D rq->rq_iov[0]; - iov[2].iov_base =3D dst; - iov[2].iov_len =3D dlen; - - comp_rq.rq_iov =3D iov; - - ret =3D send_fn(server, 1, &comp_rq); - } else if (ret =3D=3D -EMSGSIZE || dlen >=3D slen) { - ret =3D send_fn(server, 1, rq); + iov_iter_bvec_queue(&tmp, ITER_DEST, dbq, 1, 0, dlen); + dst =3D vmap_bvecq(&tmp, PAGE_KERNEL); + if (IS_ERR(dst)) { + ret =3D PTR_ERR(dst); + dst =3D NULL; + goto err_free; } -err_free: - kvfree(dst); - kvfree(src); + z_hdr =3D dst; + dst +=3D sizeof(*z_hdr) + hlen; + dlen -=3D sizeof(*z_hdr) + hlen; + + ret =3D lz77_compress(src + hlen, slen - hlen, dst, &dlen); + if (ret) + goto err_free; + + dlen +=3D sizeof(*z_hdr) + hlen; + dst -=3D hlen; + memcpy(dst, src, hlen); =20 + z_hdr->ProtocolId =3D SMB2_COMPRESSION_TRANSFORM_ID; + z_hdr->OriginalCompressedSegmentSize =3D cpu_to_le32(datalen); + z_hdr->CompressionAlgorithm =3D SMB3_COMPRESS_LZ77; + z_hdr->Flags =3D SMB2_COMPRESSION_FLAG_NONE; + z_hdr->Offset =3D cpu_to_le32(hlen); + + vunmap(z_hdr); + vunmap(src); + + dbq->bv[0] =3D sbq->bv[0]; + memset(&sbq->bv[0], 0, sizeof(sbq->bv[0])); + bvecq_shorten_buffer(dbq, 1, dlen); + bvecq_dump(dbq); + + bvecq_put(sbq); + *bq =3D dbq; + return dlen; + +err_free: + vunmap(z_hdr); + vunmap(src); + bvecq_put(dbq); return ret; } diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h index 2679baca129b..48812b0e7476 100644 --- a/fs/smb/client/compress.h +++ b/fs/smb/client/compress.h @@ -30,9 +30,10 @@ typedef int (*compress_send_fn)(struct TCP_Server_Info *, int, struct smb_= rqst *); =20 =20 -int smb_compress(struct TCP_Server_Info *server, struct smb_rqst *rq, - compress_send_fn send_fn); +int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, + struct bvecq **bq); bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *= rq); +bool is_compressible(const struct iov_iter *data); =20 /* * smb_compress_alg_valid() - Validate a compression algorithm. @@ -58,11 +59,14 @@ static __always_inline int smb_compress_alg_valid(__le1= 6 alg, bool valid_none) return false; } #else /* !CONFIG_CIFS_COMPRESSION */ -static inline int smb_compress(void *unused1, void *unused2, void *unused3) +static inline +int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, + struct bvecq **bq) { return -EOPNOTSUPP; } =20 +static inline bool is_compressible(const struct iov_iter *data) { return f= alse; } static inline bool should_compress(void *unused1, void *unused2) { return false; diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 042d44788321..8477440bbcc2 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -142,6 +142,7 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_= Info *server, struct smb_rqst *rqst, struct smb_message *smb, unsigned int xid) { + struct iov_iter iter; struct smb_hdr *in_buf =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; struct kvec iov[1]; struct smb_rqst crqst =3D { .rq_iov =3D iov, .rq_nvec =3D 1 }; @@ -162,13 +163,15 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Serve= r_Info *server, return rc; } =20 + iov_iter_kvec(&iter, ITER_SOURCE, iov, 1, iov[0].iov_len); + /* * The response to this call was already factored into the sequence * number when the call went out, so we must adjust it back downward * after signing here. */ --server->sequence_number; - rc =3D __smb_send_rqst(server, 1, &crqst); + rc =3D __smb_send_rqst(server, &iter); if (rc < 0) server->sequence_number--; =20 diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 3c30417a3ea6..6125184d9826 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -2746,9 +2746,7 @@ void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst) { struct smb2_hdr *shdr; - struct cifs_ses *ses =3D tcon->ses; - struct TCP_Server_Info *server =3D ses->server; - unsigned long len =3D smb_rqst_len(server, rqst); + size_t len =3D 0; int num_padding; =20 shdr =3D (struct smb2_hdr *)(rqst->rq_iov[0].iov_base); @@ -2757,6 +2755,10 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct= smb_rqst *rqst) return; } =20 + for (int i =3D 0; i < rqst->rq_nvec; i++) + len +=3D rqst->rq_iov[i].iov_len; + len +=3D iov_iter_count(&rqst->rq_iter); + /* SMB headers in a compound are 8 byte aligned. */ if (IS_ALIGNED(len, 8)) goto out; @@ -4326,105 +4328,6 @@ smb2_dir_needs_close(struct cifsFileInfo *cfile) return !cfile->invalidHandle; } =20 -static void -fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_le= n, - struct smb_rqst *old_rq, __le16 cipher_type) -{ - struct smb2_hdr *shdr =3D - (struct smb2_hdr *)old_rq->rq_iov[0].iov_base; - - memset(tr_hdr, 0, sizeof(struct smb2_transform_hdr)); - tr_hdr->ProtocolId =3D SMB2_TRANSFORM_PROTO_NUM; - tr_hdr->OriginalMessageSize =3D cpu_to_le32(orig_len); - tr_hdr->Flags =3D cpu_to_le16(0x01); - if ((cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || - (cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE); - else - get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE); - memcpy(&tr_hdr->SessionId, &shdr->SessionId, 8); -} - -static void *smb2_aead_req_alloc(struct crypto_aead *tfm, const struct smb= _rqst *rqst, - int num_rqst, const u8 *sig, u8 **iv, - struct aead_request **req, struct sg_table *sgt, - unsigned int *num_sgs) -{ - unsigned int req_size =3D sizeof(**req) + crypto_aead_reqsize(tfm); - unsigned int iv_size =3D crypto_aead_ivsize(tfm); - unsigned int len; - u8 *p; - - *num_sgs =3D cifs_get_num_sgs(rqst, num_rqst, sig); - if (IS_ERR_VALUE((long)(int)*num_sgs)) - return ERR_PTR(*num_sgs); - - len =3D iv_size; - len +=3D crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1); - len =3D ALIGN(len, crypto_tfm_ctx_alignment()); - len +=3D req_size; - len =3D ALIGN(len, __alignof__(struct scatterlist)); - len +=3D array_size(*num_sgs, sizeof(struct scatterlist)); - - p =3D kzalloc(len, GFP_NOFS); - if (!p) - return ERR_PTR(-ENOMEM); - - *iv =3D (u8 *)PTR_ALIGN(p, crypto_aead_alignmask(tfm) + 1); - *req =3D (struct aead_request *)PTR_ALIGN(*iv + iv_size, - crypto_tfm_ctx_alignment()); - sgt->sgl =3D (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size, - __alignof__(struct scatterlist)); - return p; -} - -static void *smb2_get_aead_req(struct crypto_aead *tfm, struct smb_rqst *r= qst, - int num_rqst, const u8 *sig, u8 **iv, - struct aead_request **req, struct scatterlist **sgl) -{ - struct sg_table sgtable =3D {}; - unsigned int skip, num_sgs, i, j; - ssize_t rc; - void *p; - - p =3D smb2_aead_req_alloc(tfm, rqst, num_rqst, sig, iv, req, &sgtable, &n= um_sgs); - if (IS_ERR(p)) - return ERR_CAST(p); - - sg_init_marker(sgtable.sgl, num_sgs); - - /* - * The first rqst has a transform header where the - * first 20 bytes are not part of the encrypted blob. - */ - skip =3D 20; - - for (i =3D 0; i < num_rqst; i++) { - struct iov_iter *iter =3D &rqst[i].rq_iter; - size_t count =3D iov_iter_count(iter); - - for (j =3D 0; j < rqst[i].rq_nvec; j++) { - cifs_sg_set_buf(&sgtable, - rqst[i].rq_iov[j].iov_base + skip, - rqst[i].rq_iov[j].iov_len - skip); - - /* See the above comment on the 'skip' assignment */ - skip =3D 0; - } - sgtable.orig_nents =3D sgtable.nents; - - rc =3D extract_iter_to_sg(iter, count, &sgtable, - num_sgs - sgtable.nents, 0); - iov_iter_revert(iter, rc); - sgtable.orig_nents =3D sgtable.nents; - } - - cifs_sg_set_buf(&sgtable, sig, SMB2_SIGNATURE_SIZE); - sg_mark_end(&sgtable.sgl[sgtable.nents - 1]); - *sgl =3D sgtable.sgl; - return p; -} - int smb2_get_enc_key(struct TCP_Server_Info *server, __u64 ses_id, int enc, u8= *key) { @@ -4454,172 +4357,6 @@ smb2_get_enc_key(struct TCP_Server_Info *server, __= u64 ses_id, int enc, u8 *key) return -EAGAIN; } =20 -/* - * Encrypt @rqst message. @rqst[0] has the following format: - * iov[0] - transform header (associate data), - * iov[1-N] - SMB2 header and pages - data to encrypt. - * On success return encrypted data in iov[1-N] and pages, leave iov[0] - * untouched. - */ -static int -encrypt_message(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst, struct crypto_aead *tfm) -{ - struct smb2_transform_hdr *tr_hdr =3D - (struct smb2_transform_hdr *)rqst[0].rq_iov[0].iov_base; - unsigned int assoc_data_len =3D sizeof(struct smb2_transform_hdr) - 20; - int rc =3D 0; - struct scatterlist *sg; - u8 sign[SMB2_SIGNATURE_SIZE] =3D {}; - u8 key[SMB3_ENC_DEC_KEY_SIZE]; - struct aead_request *req; - u8 *iv; - DECLARE_CRYPTO_WAIT(wait); - unsigned int crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); - void *creq; - - rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 1, key); - if (rc) { - cifs_server_dbg(FYI, "%s: Could not get encryption key. sid: 0x%llx\n", - __func__, le64_to_cpu(tr_hdr->SessionId)); - return rc; - } - - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_CCM) || - (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); - else - rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); - - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); - return rc; - } - - rc =3D crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); - if (rc) { - cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); - return rc; - } - - creq =3D smb2_get_aead_req(tfm, rqst, num_rqst, sign, &iv, &req, &sg); - if (IS_ERR(creq)) - return PTR_ERR(creq); - - if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || - (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) - memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); - else { - iv[0] =3D 3; - memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); - } - - aead_request_set_tfm(req, tfm); - aead_request_set_crypt(req, sg, sg, crypt_len, iv); - aead_request_set_ad(req, assoc_data_len); - - aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, - crypto_req_done, &wait); - - rc =3D crypto_wait_req(crypto_aead_encrypt(req), &wait); - - if (!rc) - memcpy(&tr_hdr->Signature, sign, SMB2_SIGNATURE_SIZE); - - kfree_sensitive(creq); - return rc; -} - -/* - * Copy data from an iterator to the pages in a bvec queue buffer. - */ -static bool cifs_copy_iter_to_bvecq(struct iov_iter *iter, size_t size, - struct bvecq *buffer) -{ - for (; buffer; buffer =3D buffer->next) { - for (int s =3D 0; s < buffer->nr_slots; s++) { - struct bio_vec *bv =3D &buffer->bv[s]; - size_t part =3D umin(bv->bv_len, size); - - if (copy_page_from_iter(bv->bv_page, bv->bv_offset, - part, iter) !=3D part) - return false; - size -=3D part; - } - } - return true; -} - -void -smb3_free_compound_rqst(int num_rqst, struct smb_rqst *rqst) -{ - for (int i =3D 0; i < num_rqst; i++) - bvecq_put(rqst[i].rq_buffer); -} - -/* - * This function will initialize new_rq and encrypt the content. - * The first entry, new_rq[0], only contains a single iov which contains - * a smb2_transform_hdr and is pre-allocated by the caller. - * This function then populates new_rq[1+] with the content from olq_rq[0+= ]. - * - * The end result is an array of smb_rqst structures where the first struc= ture - * only contains a single iov for the transform header which we then can p= ass - * to crypt_message(). - * - * new_rq[0].rq_iov[0] : smb2_transform_hdr pre-allocated by the caller - * new_rq[1+].rq_iov[*] =3D=3D old_rq[0+].rq_iov[*] : SMB2/3 requests - */ -static int -smb3_init_transform_rq(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *new_rq, struct smb_rqst *old_rq) -{ - struct smb2_transform_hdr *tr_hdr =3D new_rq[0].rq_iov[0].iov_base; - unsigned int orig_len =3D 0; - int rc =3D -ENOMEM; - - for (int i =3D 1; i < num_rqst; i++) { - struct smb_rqst *old =3D &old_rq[i - 1]; - struct smb_rqst *new =3D &new_rq[i]; - struct bvecq *buffer =3D NULL; - size_t size =3D iov_iter_count(&old->rq_iter); - - orig_len +=3D smb_rqst_len(server, old); - new->rq_iov =3D old->rq_iov; - new->rq_nvec =3D old->rq_nvec; - - if (size > 0) { - rc =3D -ENOMEM; - buffer =3D bvecq_alloc_buffer(size, GFP_NOFS); - if (!buffer) - goto err_free; - - new->rq_buffer =3D buffer; - iov_iter_bvec_queue(&new->rq_iter, ITER_SOURCE, - buffer, 0, 0, size); - - if (!cifs_copy_iter_to_bvecq(&old->rq_iter, size, buffer)) { - rc =3D smb_EIO1(smb_eio_trace_tx_copy_iter_to_buf, size); - goto err_free; - } - } - } - - /* fill the 1st iov with a transform header */ - fill_transform_hdr(tr_hdr, orig_len, old_rq, server->cipher_type); - - rc =3D encrypt_message(server, num_rqst, new_rq, server->secmech.enc); - cifs_dbg(FYI, "Encrypt message returned %d\n", rc); - if (rc) - goto err_free; - - return rc; - -err_free: - smb3_free_compound_rqst(num_rqst - 1, &new_rq[1]); - return rc; -} - int __cifs_sfu_make_node(unsigned int xid, struct inode *inode, struct dentry *dentry, struct cifs_tcon *tcon, const char *full_path, umode_t mode, dev_t dev, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 0b3df644222b..3b4bc946d1bb 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -115,6 +115,10 @@ int smb2_unlock_range(struct cifsFileInfo *cfile, stru= ct file_lock *flock, int smb2_push_mandatory_locks(struct cifsFileInfo *cfile); void smb2_reconnect_server(struct work_struct *work); int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); +int smb3_init_transform_rq(struct TCP_Server_Info *server, + int num_rqst, const struct smb_rqst *rqst, + struct smb2_transform_hdr *tr_hdr, + struct iov_iter *iter); unsigned long smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst); void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst); diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 1086877e9d84..874956515322 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -886,6 +886,119 @@ static void *smb2_get_aead_req_new(struct crypto_aead= *tfm, const struct iov_ite return p; } =20 +/* + * Encrypt the message in the buffer described by the iterator. + * On success return encrypted data in iov[1-N] and pages, leave iov[0] + * untouched. + */ +static int +encrypt_message(struct TCP_Server_Info *server, + struct smb2_transform_hdr *tr_hdr, + struct iov_iter *iter, struct crypto_aead *tfm) +{ + unsigned int assoc_data_len =3D sizeof(struct smb2_transform_hdr) - 20; + int rc =3D 0; + struct scatterlist *sg; + u8 key[SMB3_ENC_DEC_KEY_SIZE]; + struct aead_request *req; + u8 *iv; + DECLARE_CRYPTO_WAIT(wait); + unsigned int crypt_len =3D le32_to_cpu(tr_hdr->OriginalMessageSize); + void *creq; + size_t sensitive_size; + + rc =3D smb2_get_enc_key(server, le64_to_cpu(tr_hdr->SessionId), 1, key); + if (rc) { + cifs_server_dbg(FYI, "%s: Could not get encryption key. sid: 0x%llx\n", + __func__, le64_to_cpu(tr_hdr->SessionId)); + return rc; + } + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_CCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM256_CRYPTKEY_SIZE); + else + rc =3D crypto_aead_setkey(tfm, key, SMB3_GCM128_CRYPTKEY_SIZE); + + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set aead key %d\n", __func__, rc); + return rc; + } + + rc =3D crypto_aead_setauthsize(tfm, SMB2_SIGNATURE_SIZE); + if (rc) { + cifs_server_dbg(VFS, "%s: Failed to set authsize %d\n", __func__, rc); + return rc; + } + + creq =3D smb2_get_aead_req_new(tfm, iter, tr_hdr->Signature, &iv, &req, &= sg, + &sensitive_size); + if (IS_ERR(creq)) + return PTR_ERR(creq); + + if ((server->cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || + (server->cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + memcpy(iv, (char *)tr_hdr->Nonce, SMB3_AES_GCM_NONCE); + else { + iv[0] =3D 3; + memcpy(iv + 1, (char *)tr_hdr->Nonce, SMB3_AES_CCM_NONCE); + } + + aead_request_set_tfm(req, tfm); + aead_request_set_crypt(req, sg, sg, crypt_len, iv); + aead_request_set_ad(req, assoc_data_len); + + aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG, + crypto_req_done, &wait); + + rc =3D crypto_wait_req(crypto_aead_encrypt(req), &wait); + + kvfree_sensitive(creq, sensitive_size); + return rc; +} + +static void +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_le= n, + const struct smb_rqst *old_rq, __le16 cipher_type) +{ + struct smb2_hdr *shdr =3D (struct smb2_hdr *)old_rq->rq_iov[0].iov_base; + + *tr_hdr =3D (struct smb2_transform_hdr){ + .ProtocolId =3D SMB2_TRANSFORM_PROTO_NUM, + .OriginalMessageSize =3D cpu_to_le32(orig_len), + .Flags =3D cpu_to_le16(0x01), + .SessionId =3D shdr->SessionId, + }; + if ((cipher_type =3D=3D SMB2_ENCRYPTION_AES128_GCM) || + (cipher_type =3D=3D SMB2_ENCRYPTION_AES256_GCM)) + get_random_bytes(&tr_hdr->Nonce, SMB3_AES_GCM_NONCE); + else + get_random_bytes(&tr_hdr->Nonce, SMB3_AES_CCM_NONCE); +} + +/* + * This function encrypts the content in the buffer described by the itera= tor + * and fills in the transform header. The source request buffers are prov= ided + * for reference. + */ +int +smb3_init_transform_rq(struct TCP_Server_Info *server, + int num_rqst, const struct smb_rqst *rqst, + struct smb2_transform_hdr *tr_hdr, + struct iov_iter *iter) +{ + size_t orig_len =3D iov_iter_count(iter) - sizeof(*tr_hdr); + int rc; + + fill_transform_hdr(tr_hdr, orig_len, rqst, server->cipher_type); + + iov_iter_advance(iter, offsetof(struct smb2_transform_hdr, Nonce)); + + rc =3D encrypt_message(server, tr_hdr, iter, server->secmech.enc); + cifs_dbg(FYI, "Encrypt message returned %d\n", rc); + return rc; +} + /* * Decrypt the PDU in the iterator. The PDU begins with the transform hea= der. */ diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c index 563ef488a225..e20fbc10c82e 100644 --- a/fs/smb/client/smbdirect.c +++ b/fs/smb/client/smbdirect.c @@ -164,36 +164,6 @@ do { \ #define log_rdma_mr(level, fmt, args...) \ log_rdma(level, LOG_RDMA_MR, fmt, ##args) =20 -static int smbd_post_send_full_iter(struct smbdirect_socket *sc, - struct smbdirect_send_batch *batch, - struct iov_iter *iter, - u32 remaining_data_length) -{ - int bytes =3D 0; - - /* - * smbdirect_connection_send_single_iter() respects the - * negotiated max_send_size, so we need to - * loop until the full iter is posted - */ - - while (iov_iter_count(iter) > 0) { - int rc; - - rc =3D smbdirect_connection_send_single_iter(sc, - batch, - iter, - 0, /* flags */ - remaining_data_length); - if (rc < 0) - return rc; - remaining_data_length -=3D rc; - bytes +=3D rc; - } - - return bytes; -} - /* * Destroy the transport and related RDMA and memory resources * Need to go through all the pending counters and make sure on one is usi= ng @@ -405,85 +375,46 @@ int smbd_recv(struct smbd_connection *info, struct ms= ghdr *msg) =20 /* * Send data to transport - * Each rqst is transported as a SMBDirect payload - * rqst: the data to write * return value: 0 if successfully write, otherwise error code */ -int smbd_send(struct TCP_Server_Info *server, - int num_rqst, struct smb_rqst *rqst_array) +int smbd_send(struct TCP_Server_Info *server, struct iov_iter *iter) { struct smbd_connection *info =3D server->smbd_conn; struct smbdirect_socket *sc =3D info->socket; const struct smbdirect_socket_parameters *sp =3D smbd_get_parameters(info= ); - struct smb_rqst *rqst; - struct iov_iter iter; struct smbdirect_send_batch_storage bstorage; struct smbdirect_send_batch *batch; - unsigned int remaining_data_length, klen; - int rc, i, rqst_idx; - int error =3D 0; + size_t size =3D iov_iter_count(iter); + int rc, error =3D 0; =20 if (!smbdirect_connection_is_connected(sc)) return -EAGAIN; =20 - /* - * Add in the page array if there is one. The caller needs to set - * rq_tailsz to PAGE_SIZE when the buffer has multiple pages and - * ends at page boundary - */ - remaining_data_length =3D 0; - for (i =3D 0; i < num_rqst; i++) - remaining_data_length +=3D smb_rqst_len(server, &rqst_array[i]); - - if (unlikely(remaining_data_length > sp->max_fragmented_send_size)) { + if (unlikely(size > sp->max_fragmented_send_size)) { /* assertion: payload never exceeds negotiated maximum */ - log_write(ERR, "payload size %d > max size %d\n", - remaining_data_length, sp->max_fragmented_send_size); + log_write(ERR, "payload size %zu > max size %d\n", + size, sp->max_fragmented_send_size); return -EINVAL; } =20 - log_write(INFO, "num_rqst=3D%d total length=3D%u\n", - num_rqst, remaining_data_length); + log_write(INFO, "size=3D%zu\n", size); =20 - rqst_idx =3D 0; + /* + * smbdirect_connection_send_single_iter() respects the negotiated + * max_send_size, so we need to loop until the full iter is posted + */ batch =3D smbdirect_init_send_batch_storage(&bstorage, false, 0); - do { - rqst =3D &rqst_array[rqst_idx]; - - cifs_dbg(FYI, "Sending smb (RDMA): idx=3D%d smb_len=3D%lu\n", - rqst_idx, smb_rqst_len(server, rqst)); - for (i =3D 0; i < rqst->rq_nvec; i++) - dump_smb(rqst->rq_iov[i].iov_base, rqst->rq_iov[i].iov_len); - - log_write(INFO, "RDMA-WR[%u] nvec=3D%d len=3D%u iter=3D%zu rqlen=3D%lu\n= ", - rqst_idx, rqst->rq_nvec, remaining_data_length, - iov_iter_count(&rqst->rq_iter), smb_rqst_len(server, rqst)); - - /* Send the metadata pages. */ - klen =3D 0; - for (i =3D 0; i < rqst->rq_nvec; i++) - klen +=3D rqst->rq_iov[i].iov_len; - iov_iter_kvec(&iter, ITER_SOURCE, rqst->rq_iov, rqst->rq_nvec, klen); - - rc =3D smbd_post_send_full_iter(sc, batch, &iter, remaining_data_length); + while (iov_iter_count(iter) > 0) { + rc =3D smbdirect_connection_send_single_iter(sc, + batch, + iter, + 0, /* flags */ + iov_iter_count(iter)); if (rc < 0) { error =3D rc; break; } - remaining_data_length -=3D rc; - - if (iov_iter_count(&rqst->rq_iter) > 0) { - /* And then the data pages if there are any */ - rc =3D smbd_post_send_full_iter(sc, batch, &rqst->rq_iter, - remaining_data_length); - if (rc < 0) { - error =3D rc; - break; - } - remaining_data_length -=3D rc; - } - - } while (++rqst_idx < num_rqst); + } =20 rc =3D smbdirect_connection_send_batch_flush(sc, batch, true); if (unlikely(!rc && error)) diff --git a/fs/smb/client/smbdirect.h b/fs/smb/client/smbdirect.h index be205ec02077..a5c17e796ff9 100644 --- a/fs/smb/client/smbdirect.h +++ b/fs/smb/client/smbdirect.h @@ -40,8 +40,7 @@ void smbd_destroy(struct TCP_Server_Info *server); =20 /* Interface for carrying upper layer I/O through send/recv */ int smbd_recv(struct smbd_connection *info, struct msghdr *msg); -int smbd_send(struct TCP_Server_Info *server, - int num_rqst, struct smb_rqst *rqst); +int smbd_send(struct TCP_Server_Info *server, struct iov_iter *iter); =20 /* Interfaces to register and deregister MR for RDMA read/write */ struct smbdirect_mr_io *smbd_register_mr( @@ -61,7 +60,7 @@ static inline void *smbd_get_connection( static inline int smbd_reconnect(struct TCP_Server_Info *server) {return -= 1; } static inline void smbd_destroy(struct TCP_Server_Info *server) {} static inline int smbd_recv(struct smbd_connection *info, struct msghdr *m= sg) {return -1; } -static inline int smbd_send(struct TCP_Server_Info *server, int num_rqst, = struct smb_rqst *rqst) {return -1; } +static inline int smbd_send(struct TCP_Server_Info *server, struct iov_ite= r *iter) {return -1; } #endif =20 #endif diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 3f4d1a52b45c..3ead26f76112 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -23,6 +23,9 @@ #include #include #include +#include +#include "rfc1002pdu.h" +#include "cifspdu.h" #include "cifsglob.h" #include "cifsproto.h" #include "cifs_debug.h" @@ -252,51 +255,100 @@ smb_send_kvec(struct TCP_Server_Info *server, struct= msghdr *smb_msg, return 0; } =20 -unsigned long -smb_rqst_len(struct TCP_Server_Info *server, struct smb_rqst *rqst) +/* + * smb_sendmsg - send a buffer to the socket + * @server: Server to send the data to + * @iter: The data to send (not advanced) + * @sent: The amount of data sent + * + * Our basic "send data to server" function. Should be called with srv_mut= ex + * held. The caller is responsible for handling the results. + */ +static int smb_sendmsg(struct TCP_Server_Info *server, const struct iov_it= er *iter, + size_t *sent) { - unsigned int i; - struct kvec *iov; - int nvec; - unsigned long buflen =3D 0; - - if (!is_smb1(server) && rqst->rq_nvec >=3D 2 && - rqst->rq_iov[0].iov_len =3D=3D 4) { - iov =3D &rqst->rq_iov[1]; - nvec =3D rqst->rq_nvec - 1; - } else { - iov =3D rqst->rq_iov; - nvec =3D rqst->rq_nvec; - } + struct socket *ssocket =3D server->ssocket; + struct msghdr msg =3D { + /* + * MSG_SPLICE_PAGES causes tcp_sendmsg() to splice in the pages + * in the iterator rather than copying from them. + */ + .msg_flags =3D MSG_NOSIGNAL | MSG_SPLICE_PAGES, + .msg_iter =3D *iter, + }; + int retries =3D 0; + int rc =3D 0; + + *sent =3D 0; + if (server->noblocksnd) + msg.msg_flags =3D MSG_DONTWAIT; + + while (msg_data_left(&msg)) { + /* + * If blocking send, we try 3 times, since each can block for 5 + * seconds. For nonblocking we have to try more but wait + * increasing amounts of time allowing time for socket to + * clear. The overall time we wait in either case to send on + * the socket is about 15 seconds. Similarly we wait for 15 + * seconds for a response from the server in SendReceive[2] for + * the server to send a response back for most types of + * requests (except SMB Write past end of file which can be + * slow, and blocking lock operations). NFS waits slightly + * longer than CIFS, but this can make it take longer for + * nonresponsive servers to be detected and 15 seconds is more + * than enough time for modern networks to send a packet. In + * most cases if we fail to send after the retries we will kill + * the socket and reconnect which may clear the network + * problem. + */ + rc =3D sock_sendmsg(ssocket, &msg); + if (rc =3D=3D -EAGAIN) { + retries++; + if (retries >=3D 14 || + (!server->noblocksnd && (retries > 2))) { + cifs_server_dbg(VFS, "sends on sock %p stuck for 15 seconds\n", + ssocket); + return -EAGAIN; + } + msleep(1 << retries); + continue; + } + + if (rc < 0) + return rc; + + if (rc =3D=3D 0) { + /* should never happen, letting socket clear before + retrying is our only obvious option here */ + cifs_server_dbg(VFS, "tcp sent no data\n"); + msleep(500); + continue; + } =20 - /* total up iov array first */ - for (i =3D 0; i < nvec; i++) - buflen +=3D iov[i].iov_len; + *sent +=3D rc; =20 - buflen +=3D iov_iter_count(&rqst->rq_iter); - return buflen; + /* send was at least partially successful */ + retries =3D 0; /* in case we get ENOSPC on the next send */ + } + return 0; } =20 -int __smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst) +int +__smb_send_rqst(struct TCP_Server_Info *server, struct iov_iter *iter) { - int rc; - struct kvec *iov; - int n_vec; - unsigned int send_length =3D 0; - unsigned int i, j; - sigset_t mask, oldmask; - size_t total_len =3D 0, sent, size; struct socket *ssocket =3D server->ssocket; - struct msghdr smb_msg =3D {}; - __be32 rfc1002_marker; + sigset_t mask, oldmask; + size_t total_to_send =3D iov_iter_count(iter), sent =3D 0; + int rc; =20 cifs_in_send_inc(server); if (cifs_rdma_enabled(server)) { /* return -EAGAIN when connecting or reconnecting */ rc =3D -EAGAIN; - if (server->smbd_conn) - rc =3D smbd_send(server, num_rqst, rqst); + if (server->smbd_conn) { + iov_iter_advance(iter, 4); + rc =3D smbd_send(server, iter); + } goto smbd_done; } =20 @@ -314,10 +366,6 @@ int __smb_send_rqst(struct TCP_Server_Info *server, in= t num_rqst, /* cork the socket */ tcp_sock_set_cork(ssocket->sk, true); =20 - for (j =3D 0; j < num_rqst; j++) - send_length +=3D smb_rqst_len(server, &rqst[j]); - rfc1002_marker =3D cpu_to_be32(send_length); - /* * We should not allow signals to interrupt the network send because * any partial send will cause session reconnects thus increasing @@ -328,83 +376,44 @@ int __smb_send_rqst(struct TCP_Server_Info *server, i= nt num_rqst, sigfillset(&mask); sigprocmask(SIG_BLOCK, &mask, &oldmask); =20 - /* Generate a rfc1002 marker */ - { - struct kvec hiov =3D { - .iov_base =3D &rfc1002_marker, - .iov_len =3D 4 - }; - iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, &hiov, 1, 4); - rc =3D smb_send_kvec(server, &smb_msg, &sent); - if (rc < 0) - goto unmask; - - total_len +=3D sent; - send_length +=3D 4; - } - - cifs_dbg(FYI, "Sending smb: smb_len=3D%u\n", send_length); - - for (j =3D 0; j < num_rqst; j++) { - iov =3D rqst[j].rq_iov; - n_vec =3D rqst[j].rq_nvec; - - size =3D 0; - for (i =3D 0; i < n_vec; i++) { - dump_smb(iov[i].iov_base, iov[i].iov_len); - size +=3D iov[i].iov_len; - } - - iov_iter_kvec(&smb_msg.msg_iter, ITER_SOURCE, iov, n_vec, size); + cifs_dbg(FYI, "Sending smb: smb_len=3D%zu\n", iov_iter_count(iter)); + rc =3D smb_sendmsg(server, iter, &sent); =20 - rc =3D smb_send_kvec(server, &smb_msg, &sent); - if (rc < 0) - goto unmask; - - total_len +=3D sent; - - if (iov_iter_count(&rqst[j].rq_iter) > 0) { - smb_msg.msg_iter =3D rqst[j].rq_iter; - rc =3D smb_send_kvec(server, &smb_msg, &sent); - if (rc < 0) - break; - total_len +=3D sent; - } - } - -unmask: sigprocmask(SIG_SETMASK, &oldmask, NULL); =20 - /* - * If signal is pending but we have already sent the whole packet to - * the server we need to return success status to allow a corresponding - * mid entry to be kept in the pending requests queue thus allowing - * to handle responses from the server by the client. - * - * If only part of the packet has been sent there is no need to hide - * interrupt because the session will be reconnected anyway, so there - * won't be any response from the server to handle. - */ - - if (signal_pending(current) && (total_len !=3D send_length)) { - cifs_dbg(FYI, "signal is pending after attempt to send\n"); - rc =3D -ERESTARTSYS; - } - /* uncork it */ tcp_sock_set_cork(ssocket->sk, false); =20 - if ((total_len > 0) && (total_len !=3D send_length)) { - cifs_dbg(FYI, "partial send (wanted=3D%u sent=3D%zu): terminating sessio= n\n", - send_length, total_len); + if (sent > 0) { + /* + * If signal is pending but we have already sent the whole + * packet to the server we need to return success status to + * allow a corresponding mid entry to be kept in the pending + * requests queue thus allowing to handle responses from the + * server by the client. + * + * If only part of the packet has been sent there is no need to + * hide interrupt because the session will be reconnected + * anyway, so there won't be any response from the server to + * handle. + */ + if (signal_pending(current)) { + cifs_dbg(FYI, "signal is pending after attempt to send\n"); + rc =3D -ERESTARTSYS; + } + /* * If we have only sent part of an SMB then the next SMB could * be taken as the remainder of this one. We need to kill the * socket so the server throws away the partial SMB */ - cifs_signal_cifsd_for_reconnect(server, false); - trace_smb3_partial_send_reconnect(server->current_mid, - server->conn_id, server->hostname); + if (sent !=3D total_to_send) { + cifs_dbg(FYI, "partial send (wanted=3D%zu sent=3D%zu): terminating sess= ion\n", + total_to_send, sent); + cifs_signal_cifsd_for_reconnect(server, false); + trace_smb3_partial_send_reconnect(server->current_mid, + server->conn_id, server->hostname); + } } smbd_done: /* @@ -424,41 +433,167 @@ int __smb_send_rqst(struct TCP_Server_Info *server, = int num_rqst, return rc; } =20 +static size_t smb3_copy_data_iter(void *iter_from, size_t progress, size_t= len, + void *priv, void *priv2) +{ + struct iov_iter *iter =3D priv; + return copy_to_iter(iter_from, len, iter) =3D=3D len ? 0 : len; +} + +/* + * Copy the data into a buffer that we can use for encryption in place and= also + * pass to sendmsg() with MSG_SPLICE_PAGES. This avoids a lot of copies i= n TCP + * at the expense of doing it upfront here. A spare slot is left in the b= vec + * queue at the front for the header(s). + * + * TODO: In future, the buffers should be allocated by the marshalling cod= e. + */ +static int smb_copy_data_into_buffer(struct TCP_Server_Info *server, + int num_rqst, struct smb_rqst *rqst, + struct iov_iter *iter, struct bvecq **_bq) +{ + struct bvecq *bq; + size_t total_len =3D 0, offset =3D 0; + + for (int i =3D 0; i < num_rqst; i++) { + struct smb_rqst *req =3D &rqst[i]; + size_t size =3D iov_iter_count(&req->rq_iter); + + for (int j =3D 0; j < req->rq_nvec; j++) + size +=3D req->rq_iov[j].iov_len; + total_len =3D ALIGN8(total_len); + total_len +=3D size; + } + + bq =3D bvecq_alloc_buffer(total_len, GFP_NOFS); + if (!bq) + return -ENOMEM; + + iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); + + for (int i =3D 0; i < num_rqst; i++) { + struct smb_rqst *req =3D &rqst[i]; + size_t size =3D iov_iter_count(&req->rq_iter); + + if (offset & 7) { + unsigned int tmp =3D offset; + offset =3D ALIGN8(offset); + iov_iter_zero(offset - tmp, iter); + } + + for (int j =3D 0; j < req->rq_nvec; j++) { + size_t len =3D req->rq_iov[j].iov_len; + if (copy_to_iter(req->rq_iov[j].iov_base, len, iter) !=3D len) + goto error; + offset +=3D len; + } + + if (iterate_and_advance_kernel(&req->rq_iter, + size, iter, NULL, + smb3_copy_data_iter) !=3D size) + goto error; + + offset +=3D size; + } + + if (WARN_ONCE(offset !=3D total_len, + "offset=3D%zx total_len=3D%zx\n", offset, total_len)) { + goto error; + } + iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); + *_bq =3D bq; + return 0; +error: + bvecq_put(bq); + *_bq =3D NULL; + return -EIO; +} + static int smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst, int flags) { - struct smb2_transform_hdr tr_hdr; - struct smb_rqst new_rqst[MAX_COMPOUND] =3D {}; - struct kvec iov =3D { - .iov_base =3D &tr_hdr, - .iov_len =3D sizeof(tr_hdr), - }; + struct iov_iter iter; + struct bvecq *bq; + u32 content_len; int rc; =20 - if (flags & CIFS_COMPRESS_REQ) - return smb_compress(server, &rqst[0], __smb_send_rqst); - - if (!(flags & CIFS_TRANSFORM_REQ)) - return __smb_send_rqst(server, num_rqst, rqst); - - if (WARN_ON_ONCE(num_rqst > MAX_COMPOUND - 1)) - return smb_EIO1(smb_eio_trace_tx_max_compound, num_rqst); - - if (!server->ops->init_transform_rq) { + if ((flags & CIFS_TRANSFORM_REQ) && + !server->ops->init_transform_rq) { cifs_server_dbg(VFS, "Encryption requested but transform callback is mis= sing\n"); return smb_EIO(smb_eio_trace_tx_need_transform); } =20 - new_rqst[0].rq_iov =3D &iov; - new_rqst[0].rq_nvec =3D 1; + rc =3D smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq); + if (rc) + return rc; + content_len =3D iov_iter_count(&iter); + + { + struct smb2_transform_hdr *tr_hdr; + unsigned int hdr_len =3D 4, troff =3D 0; + __le32 *rfc1002; + void *hdr_blob; + + if (flags & CIFS_TRANSFORM_REQ) { + troff =3D hdr_len; + hdr_len +=3D sizeof(*tr_hdr); + } + + /* TODO: Allocate netmem here */ + rc =3D -ENOMEM; + hdr_blob =3D (void *)__get_free_page(GFP_NOFS); + if (!hdr_blob) + goto error; + bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len); + + if (flags & CIFS_COMPRESS_REQ) { + struct smb2_write_req *whdr =3D bvec_virt(&bq->bv[1]); + size_t doff =3D le16_to_cpu(whdr->DataOffset); + + iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, doff, + content_len - doff); + + if (is_compressible(&iter)) { + iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, 0, + content_len); + + rc =3D smb_compress(server, &iter, &bq); + if (rc > 0) { + content_len =3D rc; + } else if (rc =3D=3D -EMSGSIZE) { + /* Fall back to uncompressed. */ + } else { + if (rc =3D=3D 0) + rc =3D -EIO; + goto error; + } + } + } + + if (flags & CIFS_TRANSFORM_REQ) { + iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 0, 0, + hdr_len + content_len); + iov_iter_advance(&iter, troff); + tr_hdr =3D hdr_blob + troff; + + rc =3D server->ops->init_transform_rq(server, num_rqst, rqst, tr_hdr, &= iter); + if (rc) + goto error; + content_len +=3D sizeof(*tr_hdr); + } else { + bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len); + } + + /* Set the RFC1002 header at the front. */ + rfc1002 =3D hdr_blob; + *rfc1002 =3D cpu_to_be32(RFC1002_SESSION_MESSAGE << 24 | content_len); =20 - rc =3D server->ops->init_transform_rq(server, num_rqst + 1, - new_rqst, rqst); - if (!rc) { - rc =3D __smb_send_rqst(server, num_rqst + 1, new_rqst); - smb3_free_compound_rqst(num_rqst, &new_rqst[1]); + iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 0, 0, 4 + content_len); } + rc =3D __smb_send_rqst(server, &iter); +error: + bvecq_put(bq); return rc; } From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 599FF4CA260 for ; Tue, 19 May 2026 10:23:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186219; cv=none; b=o2Q32nQhbnYG0+sr3M7PJRLl53s3n1yr/EU3HlR31h2UelBdpo7oErAKPYDf/H3rTawLgTJDxJrTuanbE3aT78a7QKqK4YcfzUSNh5a6CNjJASQUGm7GN/sjfiHmvQZZNsjWgLwScG5ZIQDgfTOJR3WYuhbcC2jXzVk3C+qcWxo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186219; c=relaxed/simple; bh=0C0oxU5WSjFNdDxdnVtbUM7f6dBk/2BN9/tB3L8uuig=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=stkqbIhY5MVUU+5/VAOECEClRjsSGkweGmm/RLa4Dlfixhq7r/cKyAMIOZu2CunZHBI1P5OcvOR5Zljy3hCjGkaiPhzNffPFWEkK6Ll/6w7jV75butaxDhqzKzkxIarHf8qttpbnCnVqe8jj7ypHQI54zkoRi9/gqgOzIpPhyFw= 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=afOxm2aZ; arc=none smtp.client-ip=170.10.133.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="afOxm2aZ" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186216; 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=Qznz4sKC7x1xRadlwZi8CnPQ8HiiD1rNpPtHaviUXUo=; b=afOxm2aZOIktqH/rOI8VtFJ9kHvbhENAVRwDzHDxyKZ2TWWy0JUjYdTMeZ9Po6w0I12W17 FSoclFQJvG/uJAQeVENo4tliZSgKRWHFf9Xv10CCeyrrbx1JpEB7houcZqtYrbGExcfFKV 1lDw3faGa7svjISt4E6wR0pyVGhLhvk= 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-32-NbkSoDhPMi-ejqUt3dBuKg-1; Tue, 19 May 2026 06:23:31 -0400 X-MC-Unique: NbkSoDhPMi-ejqUt3dBuKg-1 X-Mimecast-MFC-AGG-ID: NbkSoDhPMi-ejqUt3dBuKg_1779186210 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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 2FE1218002E0; Tue, 19 May 2026 10:23:30 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0A08418004A3; Tue, 19 May 2026 10:23:26 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 17/36] cifs: Don't use corking Date: Tue, 19 May 2026 11:21:35 +0100 Message-ID: <20260519102158.592165-18-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 Content-Type: text/plain; charset="utf-8" We don't need to cork the TCP socket if we send each message in a single sendmsg() and set MSG_EOR to mark the last packet of the message with a don't-append flag. 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/transport.c | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 3ead26f76112..e43fce1099a9 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -271,9 +271,11 @@ static int smb_sendmsg(struct TCP_Server_Info *server,= const struct iov_iter *it struct msghdr msg =3D { /* * MSG_SPLICE_PAGES causes tcp_sendmsg() to splice in the pages - * in the iterator rather than copying from them. + * in the iterator rather than copying from them; MSG_EOR + * indicates that the last TCP packet we create should be + * marked no-append with regards to the next sendmsg. */ - .msg_flags =3D MSG_NOSIGNAL | MSG_SPLICE_PAGES, + .msg_flags =3D MSG_NOSIGNAL | MSG_SPLICE_PAGES | MSG_EOR, .msg_iter =3D *iter, }; int retries =3D 0; @@ -362,10 +364,6 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct= iov_iter *iter) goto out; } =20 - rc =3D 0; - /* cork the socket */ - tcp_sock_set_cork(ssocket->sk, true); - /* * We should not allow signals to interrupt the network send because * any partial send will cause session reconnects thus increasing @@ -381,9 +379,6 @@ __smb_send_rqst(struct TCP_Server_Info *server, struct = iov_iter *iter) =20 sigprocmask(SIG_SETMASK, &oldmask, NULL); =20 - /* uncork it */ - tcp_sock_set_cork(ssocket->sk, false); - if (sent > 0) { /* * If signal is pending but we have already sent the whole From nobody Mon May 25 02:42:24 2026 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 B923A4B8DEA for ; Tue, 19 May 2026 10:23:39 +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=1779186221; cv=none; b=Rsmium61QTHRJhEDczmCs27heJhfg7qkLnK5fEwk5oVi91rxrwmWh37Z1ysIyWJ7i9QgW7wbDBkVm3K49Rwe/ljrL1Y/HpZGdnC+ehJx8HKoEHwaF3I8ggcIbua5NrgOFLEbUHXK/gd8zRDdFrwKw6Qfykc8fIdG4VyD8iCQD8U= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186221; c=relaxed/simple; bh=gSlyQr+6Tkys+p9IDrNUZdWNOCbh6M97dN95Etkro44=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=grR68btr4l2aOX0FIV4E/1rWeHMQ/sW+tPZqKtLYD2aaOMyFAKB9EGKEzFOqTnDIViwg7UO9MkSrRILALDVzL0xCMpWvUBLK78aCzHFYnwkY/tN+QYfctdjkyeNZdQWZgEmHL/1+0X1aRO/rOJPQKS3FWZHoO0qIH0WEgZ8KNTE= 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=JcCB8+/g; 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="JcCB8+/g" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186218; 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=1OT0DIRL21C4YaGMi0su8gLYisllUKrenId+PISlFG4=; b=JcCB8+/gGpDQxZychxYb1ZQRFCNA6Z/emTeD4O1+N7HUOqKwzQIrCtwARg8nnTnaiUigxD 8NqDhfTyuchy0AgGPgp0s+aeyTl/xBQOkjGru9PRCI1P/ME6erjxR0bt0r3TY8QNkU2/Wv uxyrkk43upljfL/KCgMd2k2lWtAyAMM= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-617-LyeGPw__PlmdJOCcskBn5Q-1; Tue, 19 May 2026 06:23:36 -0400 X-MC-Unique: LyeGPw__PlmdJOCcskBn5Q-1 X-Mimecast-MFC-AGG-ID: LyeGPw__PlmdJOCcskBn5Q_1779186214 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id AFAB319560B4; Tue, 19 May 2026 10:23:34 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id C278B1800352; Tue, 19 May 2026 10:23:31 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 18/36] cifs: Use page frag allocator for Tx buffers Date: Tue, 19 May 2026 11:21:36 +0100 Message-ID: <20260519102158.592165-19-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Use a per-TCP connection page fragment allocator for transmission buffers rather than using whole pages for messages less than half a page in size. Currently, the data is copied into there, but we should allocate these in future up front instead of kmalloc'd bits and avoid that copy too. Note that these page fragments can be used with MSG_SPLICE_PAGES and thus avoid a copy inside the TCP stack. 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: linux-fsdevel@vger.kernel.org --- fs/smb/client/cifsglob.h | 2 ++ fs/smb/client/connect.c | 3 +++ fs/smb/client/transport.c | 38 ++++++++++++++++++++++++++++++++------ 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index f7c12d24e2ea..cd9bf550a144 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -662,6 +662,8 @@ struct TCP_Server_Info { /* updates to tcpStatus protected by cifs_tcp_ses_lock */ enum statusEnum tcpStatus; /* what we think the status is */ char *hostname; /* hostname portion of UNC string */ + struct page_frag_cache tx_alloc; /* Transmission buffer allocator */ + struct mutex tx_alloc_lock; /* Lock for ->tx_alloc */ struct socket *ssocket; struct sockaddr_storage dstaddr; struct sockaddr_storage srcaddr; /* locally bind to this IP */ diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 4a3ebbd6d71b..1d6a18390a25 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -1054,6 +1054,8 @@ clean_demultiplex_info(struct TCP_Server_Info *server) */ } =20 + page_frag_cache_drain(&server->tx_alloc); + put_net(cifs_net_ns(server)); kfree(server->leaf_fullpath); kfree(server->hostname); @@ -1694,6 +1696,7 @@ cifs_get_tcp_session(struct smb3_fs_context *ctx, INIT_DELAYED_WORK(&tcp_ses->echo, cifs_echo_request); INIT_DELAYED_WORK(&tcp_ses->reconnect, smb2_reconnect_server); mutex_init(&tcp_ses->reconnect_mutex); + mutex_init(&tcp_ses->tx_alloc_lock); memcpy(&tcp_ses->srcaddr, &ctx->srcaddr, sizeof(tcp_ses->srcaddr)); memcpy(&tcp_ses->dstaddr, &ctx->dstaddr, diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index e43fce1099a9..98dca2524376 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -445,7 +445,8 @@ static size_t smb3_copy_data_iter(void *iter_from, size= _t progress, size_t len, */ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server, int num_rqst, struct smb_rqst *rqst, - struct iov_iter *iter, struct bvecq **_bq) + struct iov_iter *iter, struct bvecq **_bq, + unsigned int flags) { struct bvecq *bq; size_t total_len =3D 0, offset =3D 0; @@ -460,9 +461,31 @@ static int smb_copy_data_into_buffer(struct TCP_Server= _Info *server, total_len +=3D size; } =20 - bq =3D bvecq_alloc_buffer(total_len, GFP_NOFS); - if (!bq) - return -ENOMEM; + if (total_len <=3D PAGE_SIZE / 2) { + /* TODO: Choose algo-based alignment. */ + unsigned int align =3D (flags & CIFS_TRANSFORM_REQ) ? 32 : 1; + size_t alen =3D (flags & CIFS_TRANSFORM_REQ) ? + round_up(total_len, align) : total_len; + + bq =3D bvecq_alloc_chain(2, GFP_NOFS); + if (!bq) + return -ENOMEM; + mutex_lock(&server->tx_alloc_lock); + void *p =3D page_frag_alloc_align(&server->tx_alloc, alen, + GFP_NOFS, align); + mutex_unlock(&server->tx_alloc_lock); + if (!p) { + bvecq_put(bq); + return -ENOMEM; + } + bvec_set_virt(&bq->bv[1], p, total_len); + bq->nr_slots =3D 2; + bq->mem_type =3D BVECQ_MEM_PAGECACHE; + } else { + bq =3D bvecq_alloc_buffer2(total_len, 1, GFP_NOFS); + if (!bq) + return -ENOMEM; + } =20 iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); =20 @@ -495,6 +518,7 @@ static int smb_copy_data_into_buffer(struct TCP_Server_= Info *server, "offset=3D%zx total_len=3D%zx\n", offset, total_len)) { goto error; } + iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); *_bq =3D bq; return 0; @@ -519,7 +543,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_r= qst, return smb_EIO(smb_eio_trace_tx_need_transform); } =20 - rc =3D smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq); + rc =3D smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq, flag= s); if (rc) return rc; content_len =3D iov_iter_count(&iter); @@ -537,7 +561,9 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_r= qst, =20 /* TODO: Allocate netmem here */ rc =3D -ENOMEM; - hdr_blob =3D (void *)__get_free_page(GFP_NOFS); + mutex_lock(&server->tx_alloc_lock); + hdr_blob =3D page_frag_alloc(&server->tx_alloc, hdr_len, GFP_NOFS); + mutex_unlock(&server->tx_alloc_lock); if (!hdr_blob) goto error; bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len); From nobody Mon May 25 02:42:24 2026 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 0209C4DA534 for ; Tue, 19 May 2026 10:23:45 +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=1779186231; cv=none; b=rTZZeuaTs+aD7fvVkaHoB3u3gSjsvA9Xsg3iaOGuF46X/Ma3KM1yFDIp3V584ATyHMA+Vzv4Ex0BhHysgJzBBymVQyB+AXqN9DDF+R3AvDh7yOaxzMG8v/YJGxsYRJ5zILZpdwCkDOzqGP9rKK9g02L4mVgpqo0iB+VqYhtjbs0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186231; c=relaxed/simple; bh=51B2rHKys7mbRhtY7XKxWSOvTT02j1bbjwUHdnXS90g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=N7bYxJv+Xz4rXX7zYR6pV1oUB6W9cC6RWFQmZuX9A5Z/1w1meXGrv3tAYwEZ6IjHY/DHVdsrjimwWDukwqnQxCaxFom2AIXFGY40GSMRqQAeS8UotgTj4SNS/7kOR/xRcSf14Li/Po+j7hbFtvm3M4SE06t9m3tWsyjeHxzbAhE= 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=AIOKIvOC; 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="AIOKIvOC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186224; 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=roC32dctScvHhnDgsFFj+YvvKQrdeBQEvvpna5yuBKs=; b=AIOKIvOCs+VjoB+yHeQHkXuiTPvxVdBUE7uTp+cXbgVKsOgEP838fBTB0BQTcnh1qLc207 WEUuCw1EmmQVZjL8gdlilmextSFoUO2xgz62FYrA7UrzIJcrUNCmrL9O/EDaSysQKeLiDF 6Rk79hjaLlcMobwZAPK1PmsEUinDUrM= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-685-aGJtKDLXM6WEZSyr7JyuhA-1; Tue, 19 May 2026 06:23:40 -0400 X-MC-Unique: aGJtKDLXM6WEZSyr7JyuhA-1 X-Mimecast-MFC-AGG-ID: aGJtKDLXM6WEZSyr7JyuhA_1779186219 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 552EA1956050; Tue, 19 May 2026 10:23:39 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6579430002DC; Tue, 19 May 2026 10:23:36 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , Stefan Metzmacher , Mina Almasry , linux-cifs@vger.kernel.org, linux-kernel@vger.kernel.org, linux-fsdevel@vger.kernel.org Subject: [RFC PATCH 19/36] cifs: Try to better handle the "Dynamic" flag in StructureSize2 in SMB2/3 Date: Tue, 19 May 2026 11:21:37 +0100 Message-ID: <20260519102158.592165-20-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" The bottom bit of the size field of the op-specific SMB2/3 struct that immediately follows the smb[23]_hdr struct is a bit weird. Wireshark considers it a "dynamic flag" and it would seem that it needs to be masked off to get the actualy size of the struct - and if there is data following the struct, it is kind of meaningless. The adjusted value, however, must still be set that way, and if there is nothing following the struct, it seems that the message must be padded out with an extra zero byte so that the message size is no less than the header including that flag in the StructureSize. Possibly this is a remnant of someone putting an empty data field at the end of the struct as "unsigned char Buffer[1];". But whatever the origin, there are a bunch of places in which the extra 1 needs to be subtracted off. Since subtracting 1 is the rule rather than the exception, return the size with the bit masked off and add the pad byte if we don't have anything else to add (Read being the main example of this). This can then be handled more transparently in future. 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: linux-fsdevel@vger.kernel.org --- fs/smb/client/smb2pdu.c | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index ddf127dc27bb..48f56ce73cd3 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -543,7 +543,11 @@ fill_small_buf(__le16 smb2_command, struct cifs_tcon *= tcon, smb2_hdr_assemble(&spdu->hdr, smb2_command, tcon, server); spdu->StructureSize2 =3D cpu_to_le16(parmsize); =20 - *total_len =3D parmsize + sizeof(struct smb2_hdr); + if (smb2_command =3D=3D SMB2_READ) + *total_len =3D sizeof(struct smb2_hdr) + parmsize; + else + *total_len =3D sizeof(struct smb2_hdr) + + (parmsize & ~SMB2_STRUCT_HAS_DYNAMIC_PART); } =20 /* @@ -1589,7 +1593,7 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_da= ta) =20 sess_data->iov[0].iov_base =3D (char *)req; /* 1 for pad */ - sess_data->iov[0].iov_len =3D total_len - 1; + sess_data->iov[0].iov_len =3D total_len; /* * This variable will be used to clear the buffer * allocated above in case of any error in the calling function. @@ -2154,7 +2158,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *se= s, const char *tree, =20 iov[0].iov_base =3D (char *)req; /* 1 for pad */ - iov[0].iov_len =3D total_len - 1; + iov[0].iov_len =3D total_len; =20 /* Testing shows that buffer offset must be at location of Buffer[0] */ req->PathOffset =3D cpu_to_le16(sizeof(struct smb2_tree_connect_req)); @@ -2958,7 +2962,7 @@ int smb311_posix_mkdir(const unsigned int xid, struct= inode *inode, =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; + iov[0].iov_len =3D total_len; =20 req->NameOffset =3D cpu_to_le16(sizeof(struct smb2_create_req)); =20 @@ -3105,7 +3109,7 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_Ser= ver_Info *server, =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; + iov[0].iov_len =3D total_len; =20 if (oparms->create_options & CREATE_OPTION_READONLY) file_attributes |=3D ATTR_READONLY; @@ -3427,12 +3431,12 @@ SMB2_ioctl_init(struct cifs_tcon *tcon, struct TCP_= Server_Info *server, req->InputOffset =3D cpu_to_le32(offsetof(struct smb2_ioctl_req, Buffer)); rqst->rq_nvec =3D 2; - iov[0].iov_len =3D total_len - 1; + iov[0].iov_len =3D total_len; iov[1].iov_base =3D in_data_buf; iov[1].iov_len =3D indatalen; } else { rqst->rq_nvec =3D 1; - iov[0].iov_len =3D total_len; + iov[0].iov_len =3D total_len + 1; } =20 req->OutputOffset =3D 0; @@ -3874,7 +3878,7 @@ SMB2_query_info_init(struct cifs_tcon *tcon, struct T= CP_Server_Info *server, if (input_len) { req->InputBufferLength =3D cpu_to_le32(input_len); /* total_len for smb query request never close to le16 max */ - req->InputBufferOffset =3D cpu_to_le16(total_len - 1); + req->InputBufferOffset =3D cpu_to_le16(total_len); memcpy(req->Buffer, input, input_len); } =20 @@ -4579,7 +4583,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, v1 =3D (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0]; smbd_mr_fill_buffer_descriptor(rdata->mr, v1); =20 - *total_len +=3D sizeof(*v1) - 1; + *total_len +=3D sizeof(*v1); } #endif if (request_type & CHAINED_REQUEST) { @@ -5339,7 +5343,7 @@ SMB2_write(const unsigned int xid, struct cifs_io_par= ms *io_parms, =20 iov[0].iov_base =3D (char *)req; /* 1 for Buffer */ - iov[0].iov_len =3D total_len - 1; + iov[0].iov_len =3D total_len; =20 memset(&rqst, 0, sizeof(struct smb_rqst)); rqst.rq_iov =3D iov; @@ -5597,7 +5601,7 @@ int SMB2_query_directory_init(const unsigned int xid, =20 iov[0].iov_base =3D (char *)req; /* 1 for Buffer */ - iov[0].iov_len =3D total_len - 1; + iov[0].iov_len =3D total_len; =20 iov[1].iov_base =3D (char *)(req->Buffer); iov[1].iov_len =3D len; @@ -5810,7 +5814,7 @@ SMB2_set_info_init(struct cifs_tcon *tcon, struct TCP= _Server_Info *server, =20 iov[0].iov_base =3D (char *)req; /* 1 for Buffer */ - iov[0].iov_len =3D total_len - 1; + iov[0].iov_len =3D total_len; =20 for (i =3D 1; i < rqst->rq_nvec; i++) { le32_add_cpu(&req->BufferLength, size[i]); From nobody Mon May 25 02:42:24 2026 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 3DEC34D9910 for ; Tue, 19 May 2026 10:23:51 +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=1779186239; cv=none; b=IKPpqzUiBvomH8U7qio8HJI1/T6BvMXTZbw1+SQvQhUCzqn4okG8RxmzQixAeTnjv5P/zVzFGMqhlc3nce/ty8xkdCfrnU4yUOK8tXgRJas97n2W3imJDuQmBbWbxz0wfcpAhQMSkuZIh+dzPcO8icBDAHzgw4xG3o3KUgjsE9c= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186239; c=relaxed/simple; bh=mVWFy46cMuFVcIfL1nrCjVTLzeUSf+V0FaAHF5luz04=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=TD6bR1W8v/va8pcjfO3EDJ48l2rTl1OoTJz0dWFnRTzc5pBABw+JQsbwgyhh8CrAdJ1i+6YYfsRpNlyUMIdJp5La8tm8OioBVZtNAT5EdtCf3iuaaQ3SWNpTBILcPRiAKyahw6+Pnertt5CXeW+ACbgqPXzc2sh8KwsUQpL7YAQ= 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=Src0Xvf4; 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="Src0Xvf4" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186230; 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=F+EZe3/Opbqn6AXMHL3mIwaioMxtPWw0a5KagCd/VnY=; b=Src0Xvf4x0xR7azwWH02Q6h3+aCqDwefuziYo2soxDFv3EcOBCgk+gaUcy3L/PDwDByv3G VN5+s7eQV0dx9D2WiBIFOneB4t+4u4PaE+2wNQP1YqORKfaMd4pPKahEPM5YJFZ8fsvi0V kiT6p3dPFiWyEeAf/ngnnS7beFuyfcY= Received: from mx-prod-mc-06.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-79-lRP78vTbNS21QD2-zxlSqw-1; Tue, 19 May 2026 06:23:46 -0400 X-MC-Unique: lRP78vTbNS21QD2-zxlSqw-1 X-Mimecast-MFC-AGG-ID: lRP78vTbNS21QD2-zxlSqw_1779186224 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 9F5B418005B4; Tue, 19 May 2026 10:23:44 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EE0D030001A2; Tue, 19 May 2026 10:23:40 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 20/36] cifs: Pass smb_message structs down into the transport layer Date: Tue, 19 May 2026 11:21:38 +0100 Message-ID: <20260519102158.592165-21-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Institute the creation of smb_message structs at the layer above the transport layer and pass them down into the transport layer. This replaces the handling of mid_q_structs entirely within the transport layer. This includes the following changes: (1) The smb_rqst struct is partially absorbed into the smb_message struct. Because the latter is on a linked list, the fixed-size arrays of requests can be got rid of - along with the COMPOUND_MAX-1 limit that gets imposed by the encryption code because it needs to steal a slot for the transform header. (2) Hand smb_message structs into the message sending code in the transport rather than allocating them (as it did for mid_q_structs) in the ->setup_request/->setup_async_request functions. For the moment compound_send_rcv() does the generation of smb_message structs, stringing them together before passing them down. (3) Protocol Message IDs are allocated at the time of transmission and as the code to do that is called by protocol-specific code, we don't need a function pointer or so many wrapper functions for it. 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/cifsglob.h | 40 +--- fs/smb/client/cifsproto.h | 105 +--------- fs/smb/client/cifssmb.c | 155 ++++++++------ fs/smb/client/compress.c | 10 +- fs/smb/client/compress.h | 4 +- fs/smb/client/connect.c | 21 +- fs/smb/client/smb1misc.c | 2 - fs/smb/client/smb1ops.c | 25 +-- fs/smb/client/smb1proto.h | 17 +- fs/smb/client/smb1transport.c | 105 ++++------ fs/smb/client/smb2misc.c | 42 ++-- fs/smb/client/smb2ops.c | 13 +- fs/smb/client/smb2pdu.c | 230 +++++++++++--------- fs/smb/client/smb2proto.h | 29 +-- fs/smb/client/smb2transport.c | 242 ++++++++++----------- fs/smb/client/trace.h | 26 ++- fs/smb/client/transport.c | 382 ++++++++++++++++++++-------------- 17 files changed, 710 insertions(+), 738 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index cd9bf550a144..c444b7d81c23 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -312,18 +312,16 @@ struct cifs_credits; =20 struct smb_version_operations { int (*send_cancel)(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct smb_message *smb, - unsigned int xid); + struct smb_message *smb, unsigned int xid); bool (*compare_fids)(struct cifsFileInfo *, struct cifsFileInfo *); - /* setup request: allocate mid, sign message */ - struct smb_message *(*setup_request)(struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct smb_rqst *rqst); + /* setup request: set up mid, sign message */ + int (*setup_request)(struct cifs_ses *ses, + struct TCP_Server_Info *server, + struct smb_message *smb); /* setup async request: allocate mid, sign message */ - struct smb_message *(*setup_async_request)(struct TCP_Server_Info *server, - struct smb_rqst *rqst); + int (*setup_async_request)(struct TCP_Server_Info *server, struct smb_mes= sage *smb); /* check response: verify signature, map error */ - int (*check_receive)(struct smb_message *mid, struct TCP_Server_Info *ser= ver, + int (*check_receive)(struct smb_message *smb, struct TCP_Server_Info *ser= ver, bool log_error); void (*add_credits)(struct TCP_Server_Info *server, struct cifs_credits *credits, @@ -331,7 +329,6 @@ struct smb_version_operations { void (*set_credits)(struct TCP_Server_Info *, const int); int * (*get_credits_field)(struct TCP_Server_Info *, const int); unsigned int (*get_credits)(struct smb_message *smb); - __u64 (*get_next_mid)(struct TCP_Server_Info *); void (*revert_current_mid)(struct TCP_Server_Info *server, const unsigned int val); /* Finish receiving a PDU and decrypt and decompress and parse it. */ @@ -571,10 +568,8 @@ struct smb_version_operations { long (*fallocate)(struct file *, struct cifs_tcon *, int, loff_t, loff_t); /* init transform (compress/encrypt) request */ - int (*init_transform_rq)(struct TCP_Server_Info *server, - int num_rqst, const struct smb_rqst *rqst, - struct smb2_transform_hdr *tr_hdr, - struct iov_iter *iter); + int (*init_transform_rq)(struct TCP_Server_Info *server, struct smb_messa= ge *head_smb, + struct smb2_transform_hdr *tr_hdr, struct iov_iter *iter); enum securityEnum (*select_sectype)(struct TCP_Server_Info *, enum securityEnum); int (*next_header)(struct TCP_Server_Info *server, char *buf, @@ -898,23 +893,6 @@ adjust_credits(struct TCP_Server_Info *server, struct = cifs_io_subrequest *subreq server->ops->adjust_credits(server, subreq, trace) : 0; } =20 -static inline __le64 -get_next_mid64(struct TCP_Server_Info *server) -{ - return cpu_to_le64(server->ops->get_next_mid(server)); -} - -static inline __le16 -get_next_mid(struct TCP_Server_Info *server) -{ - __u16 mid =3D server->ops->get_next_mid(server); - /* - * The value in the SMB header should be little endian for easy - * on-the-wire decoding. - */ - return cpu_to_le16(mid); -} - static inline void revert_current_mid(struct TCP_Server_Info *server, const unsigned int val) { diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 1c9ac67b7294..47f78955796f 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -92,10 +92,8 @@ char *smb3_fs_context_fullpath(const struct smb3_fs_cont= ext *ctx, char dirsep); int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); -int cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, - mid_callback_t callback, void *cbdata, const int flags, - const struct cifs_credits *exist_credits, - struct iov_iter *resp_buf); +int cifs_call_async(struct TCP_Server_Info *server, struct smb_message *sm= b, + const int flags, const struct cifs_credits *exist_credits); struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses); int cifs_send_recv(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server, struct smb_rqst *rqst, @@ -114,11 +112,10 @@ int cifs_wait_mtu_credits(struct TCP_Server_Info *ser= ver, size_t size, =20 static inline int send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct smb_message *smb, - unsigned int xid) + struct smb_message *smb, unsigned int xid) { return server->ops->send_cancel ? - server->ops->send_cancel(ses, server, rqst, smb, xid) : 0; + server->ops->send_cancel(ses, server, smb, xid) : 0; } =20 int wait_for_response(struct TCP_Server_Info *server, struct smb_message *= smb); @@ -465,12 +462,6 @@ static inline bool dfs_src_pathname_equal(const char *= s1, const char *s2) return true; } =20 -static inline void release_mid(struct TCP_Server_Info *server, struct smb_= message *smb) -{ - if (refcount_dec_and_test(&smb->ref)) - __release_mid(server, smb); -} - static inline void cifs_free_open_info(struct cifs_open_info_data *data) { kfree(data->symlink_target); @@ -496,94 +487,6 @@ static inline int smb_EIO2(enum smb_eio_trace trace, u= nsigned long info, unsigne return -EIO; } =20 -static inline int cifs_get_num_sgs(const struct smb_rqst *rqst, - int num_rqst, - const u8 *sig) -{ - unsigned int len, skip; - unsigned int nents =3D 0; - unsigned long addr; - size_t data_size; - int i, j; - - /* - * The first rqst has a transform header where the first 20 bytes are - * not part of the encrypted blob. - */ - skip =3D 20; - - /* Assumes the first rqst has a transform header as the first iov. - * I.e. - * rqst[0].rq_iov[0] is transform header - * rqst[0].rq_iov[1+] data to be encrypted/decrypted - * rqst[1+].rq_iov[0+] data to be encrypted/decrypted - */ - for (i =3D 0; i < num_rqst; i++) { - data_size =3D iov_iter_count(&rqst[i].rq_iter); - - /* We really don't want a mixture of pinned and unpinned pages - * in the sglist. It's hard to keep track of which is what. - * Instead, we convert to a BVEC-type iterator higher up. - */ - if (data_size && - WARN_ON_ONCE(user_backed_iter(&rqst[i].rq_iter))) - return smb_EIO(smb_eio_trace_user_iter); - - /* We also don't want to have any extra refs or pins to clean - * up in the sglist. - */ - if (data_size && - WARN_ON_ONCE(iov_iter_extract_will_pin(&rqst[i].rq_iter))) - return smb_EIO(smb_eio_trace_extract_will_pin); - - for (j =3D 0; j < rqst[i].rq_nvec; j++) { - struct kvec *iov =3D &rqst[i].rq_iov[j]; - - addr =3D (unsigned long)iov->iov_base + skip; - if (is_vmalloc_or_module_addr((void *)addr)) { - len =3D iov->iov_len - skip; - nents +=3D DIV_ROUND_UP(offset_in_page(addr) + len, - PAGE_SIZE); - } else { - nents++; - } - skip =3D 0; - } - if (data_size) - nents +=3D iov_iter_npages(&rqst[i].rq_iter, INT_MAX); - } - nents +=3D DIV_ROUND_UP(offset_in_page(sig) + SMB2_SIGNATURE_SIZE, PAGE_S= IZE); - return nents; -} - -/* We can not use the normal sg_set_buf() as we will sometimes pass a - * stack object as buf. - */ -static inline void cifs_sg_set_buf(struct sg_table *sgtable, - const void *buf, - unsigned int buflen) -{ - unsigned long addr =3D (unsigned long)buf; - unsigned int off =3D offset_in_page(addr); - - addr &=3D PAGE_MASK; - if (is_vmalloc_or_module_addr((void *)addr)) { - do { - unsigned int len =3D min_t(unsigned int, buflen, PAGE_SIZE - off); - - sg_set_page(&sgtable->sgl[sgtable->nents++], - vmalloc_to_page((void *)addr), len, off); - - off =3D 0; - addr +=3D PAGE_SIZE; - buflen -=3D len; - } while (buflen); - } else { - sg_set_page(&sgtable->sgl[sgtable->nents++], - virt_to_page((void *)addr), buflen, off); - } -} - static inline int cifs_get_writable_file(struct cifsInodeInfo *cifs_inode, unsigned int find_flags, struct cifsFileInfo **ret_file) diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index c5b18e1c44ab..ebd95de2cd91 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -261,7 +261,6 @@ small_smb_init_no_tc(const int smb_command, const int w= ct, return rc; =20 buffer =3D (struct smb_hdr *)*request_buf; - buffer->Mid =3D get_next_mid(ses->server); if (ses->capabilities & CAP_UNICODE) buffer->Flags2 |=3D SMBFLG2_UNICODE; if (ses->capabilities & CAP_STATUS32) @@ -411,7 +410,6 @@ CIFSSMBNegotiate(const unsigned int xid, return rc; in_len =3D rc; =20 - pSMB->hdr.Mid =3D get_next_mid(server); pSMB->hdr.Flags2 |=3D SMBFLG2_ERR_STATUS; =20 if (ses->unicode !=3D 0) @@ -531,7 +529,6 @@ CIFSTCon(const unsigned int xid, struct cifs_ses *ses, in_len =3D header_assemble(smb_buffer, SMB_COM_TREE_CONNECT_ANDX, NULL /*no tid */, 4 /*wct */); =20 - smb_buffer->Mid =3D get_next_mid(ses->server); smb_buffer->Uid =3D ses->Suid; pSMB =3D (TCONX_REQ *) smb_buffer; pSMBr =3D (TCONX_RSP *) smb_buffer_response; @@ -699,50 +696,55 @@ cifs_echo_callback(struct TCP_Server_Info *server, st= ruct smb_message *smb) { struct cifs_credits credits =3D { .value =3D 1, .instance =3D 0 }; =20 - release_mid(server, smb); add_credits(server, &credits, CIFS_ECHO_OP); } =20 int CIFSSMBEcho(struct TCP_Server_Info *server) { - ECHO_REQ *smb; + struct smb_message *smb; + ECHO_REQ *req; int rc =3D 0; struct kvec iov[1]; - struct smb_rqst rqst =3D { - .rq_iov =3D iov, - .rq_nvec =3D ARRAY_SIZE(iov), - }; unsigned int in_len; =20 cifs_dbg(FYI, "In echo request\n"); =20 - rc =3D small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&smb); + smb =3D smb_message_alloc(smb1_command_trace_echo, GFP_NOFS); + if (!smb) + return -ENOMEM; + + rc =3D small_smb_init(SMB_COM_ECHO, 0, NULL, (void **)&req); if (rc < 0) return rc; in_len =3D rc; =20 if (server->capabilities & CAP_UNICODE) - smb->hdr.Flags2 |=3D SMBFLG2_UNICODE; + req->hdr.Flags2 |=3D SMBFLG2_UNICODE; =20 /* set up echo request */ - smb->hdr.Tid =3D 0xffff; - smb->hdr.WordCount =3D 1; - put_unaligned_le16(1, &smb->EchoCount); - put_bcc(1, &smb->hdr); - smb->Data[0] =3D 'a'; + req->hdr.Tid =3D 0xffff; + req->hdr.WordCount =3D 1; + put_unaligned_le16(1, &req->EchoCount); + put_bcc(1, &req->hdr); + req->Data[0] =3D 'a'; in_len +=3D 3; =20 - iov[0].iov_len =3D in_len; - iov[0].iov_base =3D smb; + iov[0].iov_len =3D in_len; + iov[0].iov_base =3D req; + smb->rqst.rq_iov =3D iov; + smb->rqst.rq_nvec =3D 1; + smb->request =3D req; + smb->total_len =3D in_len; + smb->callback =3D cifs_echo_callback; + smb->callback_data =3D server; =20 - rc =3D cifs_call_async(server, &rqst, cifs_echo_callback, server, - CIFS_NON_BLOCKING | CIFS_ECHO_OP, NULL, NULL); + rc =3D cifs_call_async(server, smb, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NUL= L); if (rc) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 - cifs_small_buf_release(smb); - + cifs_small_buf_release(req); + smb_put_message(smb); return rc; } =20 @@ -779,8 +781,6 @@ CIFSSMBLogoff(const unsigned int xid, struct cifs_ses *= ses) } in_len =3D rc; =20 - pSMB->hdr.Mid =3D get_next_mid(ses->server); - if (ses->server->sign) pSMB->hdr.Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; =20 @@ -1526,7 +1526,6 @@ cifs_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) rdata->subreq.transferred +=3D smb->resp_data_len; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); - release_mid(server, smb); add_credits(server, &credits, 0); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, @@ -1538,12 +1537,10 @@ int cifs_async_readv(struct cifs_io_subrequest *rdata) { int rc; - READ_REQ *smb =3D NULL; + READ_REQ *req =3D NULL; int wct; + struct smb_message *smb; struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); - struct smb_rqst rqst =3D { .rq_iov =3D rdata->iov, - .rq_nvec =3D 1 }; - struct iov_iter iter; unsigned int in_len; =20 cifs_dbg(FYI, "%s: offset=3D%llu bytes=3D%zu\n", @@ -1559,35 +1556,52 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) } } =20 - rc =3D small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&smb); + smb =3D smb_message_alloc(smb1_command_trace_read, GFP_NOFS); + if (!smb) + return -ENOMEM; + + rc =3D small_smb_init(SMB_COM_READ_ANDX, wct, tcon, (void **)&req); if (rc < 0) - return rc; + goto put_smb; in_len =3D rc; =20 - smb->hdr.Pid =3D cpu_to_le16((__u16)rdata->req->pid); - smb->hdr.PidHigh =3D cpu_to_le16((__u16)(rdata->req->pid >> 16)); + req->hdr.Pid =3D cpu_to_le16((__u16)rdata->req->pid); + req->hdr.PidHigh =3D cpu_to_le16((__u16)(rdata->req->pid >> 16)); =20 - smb->AndXCommand =3D 0xFF; /* none */ - smb->Fid =3D rdata->req->cfile->fid.netfid; - smb->OffsetLow =3D cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF); + req->AndXCommand =3D 0xFF; /* none */ + req->Fid =3D rdata->req->cfile->fid.netfid; + req->OffsetLow =3D cpu_to_le32(rdata->subreq.start & 0xFFFFFFFF); if (wct =3D=3D 12) - smb->OffsetHigh =3D cpu_to_le32(rdata->subreq.start >> 32); - smb->Remaining =3D 0; - smb->MaxCount =3D cpu_to_le16(rdata->subreq.len & 0xFFFF); - smb->MaxCountHigh =3D cpu_to_le32(rdata->subreq.len >> 16); + req->OffsetHigh =3D cpu_to_le32(rdata->subreq.start >> 32); + req->Remaining =3D 0; + req->MaxCount =3D cpu_to_le16(rdata->subreq.len & 0xFFFF); + req->MaxCountHigh =3D cpu_to_le32(rdata->subreq.len >> 16); if (wct =3D=3D 12) - smb->ByteCount =3D 0; + req->ByteCount =3D 0; else { /* old style read */ - struct smb_com_readx_req *smbr =3D - (struct smb_com_readx_req *)smb; - smbr->ByteCount =3D 0; + struct smb_com_readx_req *reqr =3D + (struct smb_com_readx_req *)req; + reqr->ByteCount =3D 0; } =20 /* 4 for RFC1001 length + 1 for BCC */ - rdata->iov[0].iov_base =3D smb; + rdata->iov[0].iov_base =3D req; rdata->iov[0].iov_len =3D in_len; =20 + smb->rqst.rq_iov =3D rdata->iov; + smb->rqst.rq_nvec =3D 1; + smb->command =3D SMB2_READ; + smb->request =3D req; + smb->total_len =3D in_len; + smb->callback =3D cifs_readv_callback; + smb->callback_data =3D rdata; + smb->copy_to_bufs =3D true; + + iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, + rdata->subreq.content.bvecq, rdata->subreq.content.slot, + rdata->subreq.content.offset, rdata->subreq.len); + trace_smb3_read_enter(rdata->rreq->debug_id, rdata->subreq.debug_index, rdata->xid, @@ -1595,16 +1609,12 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) tcon->tid, tcon->ses->Suid, rdata->subreq.start, rdata->subreq.len); =20 - iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); - - rc =3D cifs_call_async(tcon->ses->server, &rqst, - cifs_readv_callback, rdata, 0, NULL, &iter); + rc =3D cifs_call_async(tcon->ses->server, smb, 0, NULL); =20 if (rc =3D=3D 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); - cifs_small_buf_release(smb); +put_smb: + smb_put_message(smb); return rc; } =20 @@ -1915,7 +1925,6 @@ cifs_writev_callback(struct TCP_Server_Info *server, = struct smb_message *smb) 0, cifs_trace_rw_credits_write_response_clear); wdata->credits.value =3D 0; cifs_write_subrequest_terminated(wdata, result); - release_mid(server, smb); trace_smb3_rw_credits(credits.rreq_debug_id, credits.rreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_write_response_add); @@ -1929,9 +1938,9 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) int rc =3D -EACCES; WRITE_REQ *req =3D NULL; int wct; + struct smb_message *smb; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); struct kvec iov[1]; - struct smb_rqst rqst =3D { }; unsigned int in_len; =20 if (tcon->ses->capabilities & CAP_LARGE_FILES) { @@ -1945,11 +1954,33 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) } } =20 + smb =3D smb_message_alloc(smb1_command_trace_write, GFP_NOFS); + if (!smb) { + rc =3D -ENOMEM; + goto out_put; + } + rc =3D small_smb_init(SMB_COM_WRITE_ANDX, wct, tcon, (void **)&req); if (rc < 0) goto async_writev_out; in_len =3D rc; =20 + iov[0].iov_base =3D req; + iov[0].iov_len =3D in_len + 1; /* +1 for BCC */ + + smb->rqst.rq_iov =3D iov; + smb->rqst.rq_nvec =3D 1; + smb->command =3D SMB2_WRITE; + smb->request =3D req; + smb->total_len =3D in_len + 1; + smb->total_len +=3D wdata->subreq.len; + smb->callback =3D cifs_writev_callback; + smb->callback_data =3D wdata; + + iov_iter_bvec_queue(&smb->rqst.rq_iter, ITER_DEST, + wdata->subreq.content.bvecq, wdata->subreq.content.slot, + wdata->subreq.content.offset, wdata->subreq.len); + req->hdr.Pid =3D cpu_to_le16((__u16)wdata->req->pid); req->hdr.PidHigh =3D cpu_to_le16((__u16)(wdata->req->pid >> 16)); =20 @@ -1965,16 +1996,6 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) req->DataOffset =3D cpu_to_le16(offsetof(struct smb_com_write_req, Data)); =20 - iov[0].iov_base =3D req; - iov[0].iov_len =3D in_len + 1; /* +1 for BCC */ - - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 1; - - iov_iter_bvec_queue(&rqst.rq_iter, ITER_SOURCE, - wdata->subreq.content.bvecq, wdata->subreq.content.slot, - wdata->subreq.content.offset, wdata->subreq.len); - cifs_dbg(FYI, "async write at %llu %zu bytes\n", wdata->subreq.start, wdata->subreq.len); =20 @@ -1993,14 +2014,15 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) iov[0].iov_len +=3D 4; /* pad bigger by four bytes */ } =20 - rc =3D cifs_call_async(tcon->ses->server, &rqst, - cifs_writev_callback, wdata, 0, NULL, NULL); + rc =3D cifs_call_async(tcon->ses->server, smb, 0, NULL); /* Can't touch wdata if rc =3D=3D 0 */ if (rc =3D=3D 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_writes); =20 async_writev_out: cifs_small_buf_release(req); +out_put: + smb_put_message(smb); out: if (rc) { add_credits_and_wake_if(wdata->server, &wdata->credits, 0); @@ -4750,7 +4772,6 @@ CIFSGetDFSRefer(const unsigned int xid, struct cifs_s= es *ses, =20 /* server pointer checked in called function, but should never be null here anyway */ - pSMB->hdr.Mid =3D get_next_mid(ses->server); pSMB->hdr.Tid =3D ses->tcon_ipc->tid; pSMB->hdr.Uid =3D ses->Suid; if (ses->capabilities & CAP_STATUS32) diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c index a9496983ac56..36eb8a604603 100644 --- a/fs/smb/client/compress.c +++ b/fs/smb/client/compress.c @@ -277,10 +277,8 @@ bool is_compressible(const struct iov_iter *data) * * Return false otherwise. */ -bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *= rq) +bool should_compress(const struct cifs_tcon *tcon, const struct smb_messag= e *smb) { - const struct smb2_hdr *shdr =3D rq->rq_iov->iov_base; - if (unlikely(!tcon || !tcon->ses || !tcon->ses->server)) return false; =20 @@ -290,8 +288,8 @@ bool should_compress(const struct cifs_tcon *tcon, cons= t struct smb_rqst *rq) if (!(tcon->share_flags & SMB2_SHAREFLAG_COMPRESS_DATA)) return false; =20 - if (shdr->Command =3D=3D SMB2_WRITE) { - const struct smb2_write_req *wreq =3D rq->rq_iov->iov_base; + if (smb->command =3D=3D SMB2_WRITE) { + const struct smb2_write_req *wreq =3D smb->request; =20 if (le32_to_cpu(wreq->Length) < SMB_COMPRESS_MIN_LEN) return false; @@ -299,7 +297,7 @@ bool should_compress(const struct cifs_tcon *tcon, cons= t struct smb_rqst *rq) return true; } =20 - return (shdr->Command =3D=3D SMB2_READ); + return smb->command =3D=3D SMB2_READ; } =20 /* diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h index 48812b0e7476..d03f7342b4bd 100644 --- a/fs/smb/client/compress.h +++ b/fs/smb/client/compress.h @@ -32,7 +32,7 @@ typedef int (*compress_send_fn)(struct TCP_Server_Info *,= int, struct smb_rqst * =20 int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, struct bvecq **bq); -bool should_compress(const struct cifs_tcon *tcon, const struct smb_rqst *= rq); +bool should_compress(const struct cifs_tcon *tcon, const struct smb_messag= e *smb); bool is_compressible(const struct iov_iter *data); =20 /* @@ -67,7 +67,7 @@ int smb_compress(struct TCP_Server_Info *server, struct i= ov_iter *iter, } =20 static inline bool is_compressible(const struct iov_iter *data) { return f= alse; } -static inline bool should_compress(void *unused1, void *unused2) +static inline bool should_compress(const struct cifs_tcon *tcon, const str= uct smb_message *smb) { return false; } diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index 1d6a18390a25..dd092f0a0515 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -364,7 +364,6 @@ cifs_abort_connection(struct TCP_Server_Info *server) cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { - smb_get_message(smb); if (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) smb->mid_state =3D MID_RETRY_NEEDED; list_move(&smb->qhead, &retry_list); @@ -377,7 +376,7 @@ cifs_abort_connection(struct TCP_Server_Info *server) list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) { list_del_init(&smb->qhead); mid_execute_callback(server, smb); - release_mid(server, smb); + smb_put_message(smb); } } =20 @@ -807,9 +806,9 @@ static bool smb_decode_rfc1002(struct TCP_Server_Info *= server, u32 rfc1002_hdr) server->tcpStatus =3D=3D CifsInNegotiate && !server->with_rfc1001 && server->rfc1001_sessinit !=3D 0) { - int rc, mid_rc; struct smb_message *smb, *nsmb; LIST_HEAD(dispose_list); + int rc, mid_rc; =20 cifs_dbg(FYI, "RFC 1002 negative session response during SMB Negotiate,= retrying with NetBIOS session\n"); =20 @@ -822,7 +821,6 @@ static bool smb_decode_rfc1002(struct TCP_Server_Info *= server, u32 rfc1002_hdr) */ spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { - smb_get_message(smb); list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; } @@ -856,7 +854,7 @@ static bool smb_decode_rfc1002(struct TCP_Server_Info *= server, u32 rfc1002_hdr) smb->mid_rc =3D mid_rc; smb->mid_state =3D MID_RC; mid_execute_callback(server, smb); - release_mid(server, smb); + smb_put_message(smb); } =20 /* @@ -910,6 +908,7 @@ dequeue_mid(struct TCP_Server_Info *server, struct smb_= message *smb, bool malfor spin_unlock(&server->mid_queue_lock); pr_warn_once("trying to dequeue a deleted mid\n"); } else { + smb_put_message(smb); list_del_init(&smb->qhead); smb->deleted_from_q =3D true; spin_unlock(&server->mid_queue_lock); @@ -1010,15 +1009,12 @@ clean_demultiplex_info(struct TCP_Server_Info *serv= er) } =20 if (!list_empty(&server->pending_mid_q)) { - struct smb_message *smb; - struct list_head *tmp, *tmp2; + struct smb_message *smb, *smb2; LIST_HEAD(dispose_list); =20 spin_lock(&server->mid_queue_lock); - list_for_each_safe(tmp, tmp2, &server->pending_mid_q) { - smb =3D list_entry(tmp, struct smb_message, qhead); + list_for_each_entry_safe(smb, smb2, &server->pending_mid_q, qhead) { cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid); - smb_get_message(smb); smb->mid_state =3D MID_SHUTDOWN; list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; @@ -1026,12 +1022,11 @@ clean_demultiplex_info(struct TCP_Server_Info *serv= er) spin_unlock(&server->mid_queue_lock); =20 /* now walk dispose list and issue callbacks */ - list_for_each_safe(tmp, tmp2, &dispose_list) { - smb =3D list_entry(tmp, struct smb_message, qhead); + list_for_each_entry_safe(smb, smb2, &dispose_list, qhead) { cifs_dbg(FYI, "Callback mid %llu\n", smb->mid); list_del_init(&smb->qhead); mid_execute_callback(server, smb); - release_mid(server, smb); + smb_put_message(smb); } /* 1/8th of sec is more than enough time for them to exit */ msleep(125); diff --git a/fs/smb/client/smb1misc.c b/fs/smb/client/smb1misc.c index 357850e9691f..a765b18fcab8 100644 --- a/fs/smb/client/smb1misc.c +++ b/fs/smb/client/smb1misc.c @@ -45,8 +45,6 @@ header_assemble(struct smb_hdr *buffer, char smb_command, =20 /* Uid is not converted */ buffer->Uid =3D treeCon->ses->Suid; - if (treeCon->ses->server) - buffer->Mid =3D get_next_mid(treeCon->ses->server); } if (treeCon->Flags & SMB_SHARE_IS_IN_DFS) buffer->Flags2 |=3D SMBFLG2_DFS; diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index 8477440bbcc2..fb3529a79c6b 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -139,11 +139,10 @@ void reset_cifs_unix_caps(unsigned int xid, struct ci= fs_tcon *tcon, */ static int send_nt_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct smb_message *smb, - unsigned int xid) + struct smb_message *smb, unsigned int xid) { struct iov_iter iter; - struct smb_hdr *in_buf =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; + struct smb_hdr *in_buf =3D (struct smb_hdr *)smb->rqst.rq_iov[0].iov_base; struct kvec iov[1]; struct smb_rqst crqst =3D { .rq_iov =3D iov, .rq_nvec =3D 1 }; int rc =3D 0; @@ -189,11 +188,10 @@ send_nt_cancel(struct cifs_ses *ses, struct TCP_Serve= r_Info *server, */ static int send_lock_cancel(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst, struct smb_message *smb, - unsigned int xid) + struct smb_message *smb, unsigned int xid) { - struct smb_hdr *in_buf =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; - unsigned int in_len =3D rqst->rq_iov[0].iov_len; + struct smb_hdr *in_buf =3D (struct smb_hdr *)smb->rqst.rq_iov[0].iov_base; + unsigned int in_len =3D smb->rqst.rq_iov[0].iov_len; LOCK_REQ *pSMB =3D (LOCK_REQ *)in_buf; int rc; =20 @@ -204,7 +202,6 @@ send_lock_cancel(struct cifs_ses *ses, struct TCP_Serve= r_Info *server, */ pSMB->LockType =3D LOCKING_ANDX_CANCEL_LOCK|LOCKING_ANDX_LARGE_FILES; pSMB->Timeout =3D 0; - pSMB->hdr.Mid =3D get_next_mid(ses->server); =20 rc =3D SendReceive(xid, ses, in_buf, in_len, NULL, NULL, 0); if (rc =3D=3D -ENOLCK) @@ -215,12 +212,11 @@ send_lock_cancel(struct cifs_ses *ses, struct TCP_Ser= ver_Info *server, } =20 static int cifs_send_cancel(struct cifs_ses *ses, struct TCP_Server_Info *= server, - struct smb_rqst *rqst, struct smb_message *smb, - unsigned int xid) + struct smb_message *smb, unsigned int xid) { if (smb->sr_flags & CIFS_WINDOWS_LOCK) - return send_lock_cancel(ses, server, rqst, smb, xid); - return send_nt_cancel(ses, server, rqst, smb, xid); + return send_lock_cancel(ses, server, smb, xid); + return send_nt_cancel(ses, server, smb, xid); } =20 static bool @@ -233,7 +229,7 @@ struct smb_message * cifs_find_mid(struct TCP_Server_Info *server, const struct smb_hdr *shdr) { struct smb_message *smb; - u16 mid =3D le16_to_cpu(shdr->Mid); + u64 mid =3D le16_to_cpu(shdr->Mid); =20 spin_lock(&server->mid_queue_lock); list_for_each_entry(smb, &server->pending_mid_q, qhead) { @@ -302,7 +298,7 @@ cifs_get_credits(struct smb_message *smb) * to somewhat less than 64K-1 although it is hard to imagine * so many threads being in the vfs at one time. */ -static __u64 +u16 cifs_get_next_mid(struct TCP_Server_Info *server) { __u64 mid =3D 0; @@ -1380,7 +1376,6 @@ struct smb_version_operations smb1_operations =3D { .get_credits_field =3D cifs_get_credits_field, .get_credits =3D cifs_get_credits, .wait_mtu_credits =3D cifs_wait_mtu_credits, - .get_next_mid =3D cifs_get_next_mid, .clear_stats =3D cifs_clear_stats, .print_stats =3D cifs_print_stats, .downgrade_oplock =3D cifs_downgrade_oplock, diff --git a/fs/smb/client/smb1proto.h b/fs/smb/client/smb1proto.h index 54a5261fabce..ac0ba1fa2b74 100644 --- a/fs/smb/client/smb1proto.h +++ b/fs/smb/client/smb1proto.h @@ -287,16 +287,18 @@ int CIFS_SessSetup(const unsigned int xid, struct cif= s_ses *ses, /* * smb1transport.c */ -struct smb_message *cifs_setup_async_request(struct TCP_Server_Info *serve= r, - struct smb_rqst *rqst); +u16 cifs_get_next_mid(struct TCP_Server_Info *server); +struct smb_message *cifs_find_mid(struct TCP_Server_Info *server, const st= ruct smb_hdr *shdr); +bool cifs_is_network_name_deleted(const struct smb_hdr *shdr, struct TCP_S= erver_Info *server); +int cifs_setup_async_request(struct TCP_Server_Info *server, + struct smb_message *smb); int SendReceiveNoRsp(const unsigned int xid, struct cifs_ses *ses, char *in_buf, unsigned int in_len, int flags); int checkSMB(const struct TCP_Server_Info *server, struct cifs_receive *re= cv); int cifs_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, bool log_error); -struct smb_message *cifs_setup_request(struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct smb_rqst *rqst); +int cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *serve= r, + struct smb_message *smb); int SendReceive2(const unsigned int xid, struct cifs_ses *ses, struct kvec *iov, int n_vec, int *resp_buf_type /* ret */, const int flags, struct kvec *resp_iov); @@ -304,6 +306,7 @@ int SendReceive(const unsigned int xid, struct cifs_ses= *ses, struct smb_hdr *in_buf, unsigned int in_len, struct smb_hdr *out_buf, int *pbytes_returned, const int flags); +int smb1_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); =20 #define GETU16(var) (*((__u16 *)var)) /* BB check for endian issues */ #define GETU32(var) (*((__u32 *)var)) /* BB check for endian issues */ @@ -336,10 +339,6 @@ put_bcc(__u16 count, struct smb_hdr *hdr) put_unaligned_le16(count, bc_ptr); } =20 -struct smb_message *cifs_find_mid(struct TCP_Server_Info *server, const st= ruct smb_hdr *shdr); -bool cifs_is_network_name_deleted(const struct smb_hdr *shdr, struct TCP_S= erver_Info *server); -int smb1_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); - #endif /* CONFIG_CIFS_ALLOW_INSECURE_LEGACY */ =20 #endif /* _SMB1PROTO_H */ diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index a6af5bd20847..1bbfa0844e6f 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -30,52 +30,18 @@ #include "smbdirect.h" #include "compress.h" =20 -/* Max number of iovectors we can use off the stack when sending requests.= */ -#define CIFS_MAX_IOV_SIZE 8 - -static struct smb_message * -alloc_mid(const struct smb_hdr *shdr, struct TCP_Server_Info *server) +static int allocate_mid(struct cifs_ses *ses, struct smb_message *smb) { - struct smb_message *smb; - - if (server =3D=3D NULL) { - cifs_dbg(VFS, "%s: null TCP session\n", __func__); - return NULL; - } + struct smb_hdr *hdr =3D smb->request; + u16 mid =3D cifs_get_next_mid(ses->server); =20 - smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); - memset(smb, 0, sizeof(struct smb_message)); - refcount_set(&smb->ref, 1); - spin_lock_init(&smb->mid_lock); - smb->mid =3D le16_to_cpu(shdr->Mid); - smb->pid =3D current->pid; - smb->command =3D cpu_to_le16(shdr->Command); - cifs_dbg(FYI, "For smb_command %d\n", shdr->Command); - /* easier to use jiffies */ - /* when mid allocated can be before when sent */ - smb->when_alloc =3D jiffies; + smb->mid =3D mid; + hdr->Mid =3D cpu_to_le16(mid); =20 - /* - * The default is for the mid to be synchronous, so the - * default callback just wakes up the current task. - */ - get_task_struct(current); - smb->creator =3D current; - smb->callback =3D cifs_wake_up_task; - smb->callback_data =3D current; - - atomic_inc(&mid_count); - smb->mid_state =3D MID_REQUEST_ALLOCATED; - return smb; -} - -static int allocate_mid(struct cifs_ses *ses, struct smb_hdr *in_buf, - struct smb_message **ppmidQ) -{ spin_lock(&ses->ses_lock); if (ses->ses_status =3D=3D SES_NEW) { - if ((in_buf->Command !=3D SMB_COM_SESSION_SETUP_ANDX) && - (in_buf->Command !=3D SMB_COM_NEGOTIATE)) { + if ((hdr->Command !=3D SMB_COM_SESSION_SETUP_ANDX) && + (hdr->Command !=3D SMB_COM_NEGOTIATE)) { spin_unlock(&ses->ses_lock); return -EAGAIN; } @@ -84,7 +50,7 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_= hdr *in_buf, =20 if (ses->ses_status =3D=3D SES_EXITING) { /* check if SMB session is bad because we are setting it up */ - if (in_buf->Command !=3D SMB_COM_LOGOFF_ANDX) { + if (hdr->Command !=3D SMB_COM_LOGOFF_ANDX) { spin_unlock(&ses->ses_lock); return -EAGAIN; } @@ -92,37 +58,38 @@ static int allocate_mid(struct cifs_ses *ses, struct sm= b_hdr *in_buf, } spin_unlock(&ses->ses_lock); =20 - *ppmidQ =3D alloc_mid(in_buf, ses->server); - if (*ppmidQ =3D=3D NULL) - return -ENOMEM; + smb_get_message(smb); spin_lock(&ses->server->mid_queue_lock); - list_add_tail(&(*ppmidQ)->qhead, &ses->server->pending_mid_q); + list_add_tail(&smb->qhead, &ses->server->pending_mid_q); spin_unlock(&ses->server->mid_queue_lock); return 0; } =20 -struct smb_message * -cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *= rqst) +int +cifs_setup_async_request(struct TCP_Server_Info *server, struct smb_messag= e *smb) { + struct smb_hdr *shdr =3D smb->request; + u16 mid; int rc; - struct smb_hdr *hdr =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; - struct smb_message *smb; =20 /* enable signing if server requires it */ if (server->sign) - hdr->Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; + shdr->Flags2 |=3D SMBFLG2_SECURITY_SIGNATURE; =20 - smb =3D alloc_mid(hdr, server); - if (smb =3D=3D NULL) - return ERR_PTR(-ENOMEM); + mid =3D cifs_get_next_mid(server); + shdr->Mid =3D cpu_to_le16(mid); + smb->mid =3D mid; + smb->command =3D shdr->Command; + cifs_dbg(FYI, "For smb_command %d\n", smb->command); + atomic_inc(&mid_count); =20 - rc =3D cifs_sign_rqst(rqst, server, &smb->sequence_number); + rc =3D cifs_sign_rqst(&smb->rqst, server, &smb->sequence_number); if (rc) { - release_mid(server, smb); - return ERR_PTR(rc); + smb_put_message(smb); + return rc; } =20 - return smb; + return 0; } =20 /* @@ -179,23 +146,21 @@ cifs_check_receive(struct smb_message *smb, struct TC= P_Server_Info *server, return map_and_check_smb_error(server, smb, log_error); } =20 -struct smb_message * +int cifs_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst) + struct smb_message *smb) { int rc; - struct smb_hdr *hdr =3D (struct smb_hdr *)rqst->rq_iov[0].iov_base; - struct smb_message *smb; =20 - rc =3D allocate_mid(ses, hdr, &smb); + rc =3D allocate_mid(ses, smb); if (rc) - return ERR_PTR(rc); - rc =3D cifs_sign_rqst(rqst, server, &smb->sequence_number); + return rc; + rc =3D cifs_sign_rqst(&smb->rqst, server, &smb->sequence_number); if (rc) { - delete_mid(server, smb); - return ERR_PTR(rc); + dequeue_mid(server, smb, false); + return rc; } - return smb; + return 0; } =20 int @@ -956,7 +921,7 @@ static void smb1_parse_one_message(struct TCP_Server_In= fo *server, /* Handle multipart trans2-class messages. */ rc =3D smb1_trans2_receive(server, smb, recv, rxq); if (rc =3D=3D 1) { - release_mid(server, smb); + smb_put_message(smb); return; /* Multipart, incomplete. */ } if (rc < 0) @@ -1030,7 +995,7 @@ static void smb1_parse_one_message(struct TCP_Server_I= nfo *server, dequeue_mid(server, smb, recv->malformed); mid_execute_callback(server, smb); =20 - release_mid(server, smb); + smb_put_message(smb); } else if (smb1_is_valid_oplock_break(h, recv->msg_len, server)) { cifs_dbg(FYI, "Received oplock break\n"); smb_rxqueue_consume(server, rxq, rxq->pdu_remain); diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 249606e5680e..d28812107e8f 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -837,27 +837,20 @@ smb2_handle_cancelled_mid(struct smb_message *smb, st= ruct TCP_Server_Info *serve } =20 /** - * smb311_update_preauth_hash - update @ses hash with the packet data in @= iov - * - * Assumes @iov does not contain the rfc1002 length and iov[0] has the - * SMB2 header. - * + * smb311_update_preauth_hash - update @ses hash from the message * @ses: server session structure * @server: pointer to server info - * @iov: array containing the SMB request we will send to the server - * @nvec: number of array entries for the iov + * @smb: the SMB request we will send to the server + * @hash_resp: T if we're hashing a response */ void smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *s= erver, - struct kvec *iov, int nvec) + struct smb_message *smb, bool hash_resp) { - int i; - struct smb2_hdr *hdr; struct sha512_ctx sha_ctx; =20 - hdr =3D (struct smb2_hdr *)iov[0].iov_base; /* neg prot are always taken */ - if (hdr->Command =3D=3D SMB2_NEGOTIATE) + if (smb->command =3D=3D SMB2_NEGOTIATE) goto ok; =20 /* @@ -868,20 +861,29 @@ smb311_update_preauth_hash(struct cifs_ses *ses, stru= ct TCP_Server_Info *server, if (server->dialect !=3D SMB311_PROT_ID) return; =20 - if (hdr->Command !=3D SMB2_SESSION_SETUP) + if (smb->command !=3D SMB2_SESSION_SETUP) return; =20 /* skip last sess setup response */ - if ((hdr->Flags & SMB2_FLAGS_SERVER_TO_REDIR) - && (hdr->Status =3D=3D NT_STATUS_OK - || (hdr->Status !=3D - cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)))) - return; + if (hash_resp) { + struct smb2_hdr *resp =3D smb->response; + if (resp->Status =3D=3D NT_STATUS_OK || + resp->Status !=3D cpu_to_le32(NT_STATUS_MORE_PROCESSING_REQUIRED)) + return; + } =20 ok: sha512_init(&sha_ctx); sha512_update(&sha_ctx, ses->preauth_sha_hash, SMB2_PREAUTH_HASH_SIZE); - for (i =3D 0; i < nvec; i++) - sha512_update(&sha_ctx, iov[i].iov_base, iov[i].iov_len); + + if (hash_resp) { + sha512_update(&sha_ctx, smb->response, smb->resp_len); + } else { + struct kvec *iov =3D smb->rqst.rq_iov; + + for (int i =3D 0; i < smb->rqst.rq_nvec; i++) + sha512_update(&sha_ctx, iov[i].iov_base, iov[i].iov_len); + } + sha512_final(&sha_ctx, ses->preauth_sha_hash); } diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 6125184d9826..93ec64d67d54 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -402,13 +402,14 @@ smb2_add_credits_from_hdr(struct smb2_hdr *shdr, stru= ct TCP_Server_Info *server) } } =20 -static __u64 -smb2_get_next_mid(struct TCP_Server_Info *server) +u64 +smb2_get_next_mid(struct TCP_Server_Info *server, unsigned int count) { - __u64 mid; + u64 mid; /* for SMB2 we need the current value */ spin_lock(&server->mid_counter_lock); - mid =3D server->current_mid++; + mid =3D server->current_mid; + server->current_mid =3D mid + umax(count, 1); spin_unlock(&server->mid_counter_lock); return mid; } @@ -4559,7 +4560,6 @@ struct smb_version_operations smb20_operations =3D { .get_credits_field =3D smb2_get_credits_field, .get_credits =3D smb2_get_credits, .wait_mtu_credits =3D cifs_wait_mtu_credits, - .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, .clear_stats =3D smb2_clear_stats, .print_stats =3D smb2_print_stats, @@ -4650,7 +4650,6 @@ struct smb_version_operations smb21_operations =3D { .get_credits =3D smb2_get_credits, .wait_mtu_credits =3D smb2_wait_mtu_credits, .adjust_credits =3D smb2_adjust_credits, - .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, @@ -4743,7 +4742,6 @@ struct smb_version_operations smb30_operations =3D { .get_credits =3D smb2_get_credits, .wait_mtu_credits =3D smb2_wait_mtu_credits, .adjust_credits =3D smb2_adjust_credits, - .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, @@ -4846,7 +4844,6 @@ struct smb_version_operations smb311_operations =3D { .get_credits =3D smb2_get_credits, .wait_mtu_credits =3D smb2_wait_mtu_credits, .adjust_credits =3D smb2_adjust_credits, - .get_next_mid =3D smb2_get_next_mid, .revert_current_mid =3D smb2_revert_current_mid, .receive_pdu =3D smb2_receive_pdu, .clear_stats =3D smb2_clear_stats, diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 48f56ce73cd3..5919cd99dec6 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4192,7 +4192,6 @@ smb2_echo_callback(struct TCP_Server_Info *server, st= ruct smb_message *smb) credits.instance =3D server->reconnect_instance; } =20 - release_mid(server, smb); add_credits(server, &credits, CIFS_ECHO_OP); } =20 @@ -4350,10 +4349,9 @@ int SMB2_echo(struct TCP_Server_Info *server) { struct smb2_echo_req *req; + struct smb_message *smb; int rc =3D 0; struct kvec iov[1]; - struct smb_rqst rqst =3D { .rq_iov =3D iov, - .rq_nvec =3D 1 }; unsigned int total_len; =20 cifs_dbg(FYI, "In echo request for conn_id %lld\n", server->conn_id); @@ -4368,22 +4366,36 @@ SMB2_echo(struct TCP_Server_Info *server) } spin_unlock(&server->srv_lock); =20 + smb =3D smb_message_alloc(smb2_command_trace_echo, GFP_NOFS); + if (!smb) + return -ENOMEM; + rc =3D smb2_plain_req_init(SMB2_ECHO, NULL, server, (void **)&req, &total_len); - if (rc) + if (rc) { + mempool_free(smb, &smb_message_pool); return rc; - - req->hdr.CreditRequest =3D cpu_to_le16(1); + } =20 iov[0].iov_len =3D total_len; iov[0].iov_base =3D (char *)req; =20 - rc =3D cifs_call_async(server, &rqst, smb2_echo_callback, server, - CIFS_ECHO_OP, NULL, NULL); + smb->rqst.rq_iov =3D iov; + smb->rqst.rq_nvec =3D 1; + smb->command =3D SMB2_ECHO; + smb->request =3D req; + smb->total_len =3D total_len; + smb->callback =3D smb2_echo_callback; + smb->callback_data =3D server; + + req->hdr.CreditRequest =3D cpu_to_le16(1); + + rc =3D cifs_call_async(server, smb, CIFS_ECHO_OP, NULL); if (rc) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 cifs_small_buf_release(req); + smb_put_message(smb); return rc; } =20 @@ -4628,21 +4640,10 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) .rreq_debug_id =3D rdata->rreq->debug_id, .rreq_debug_index =3D rdata->subreq.debug_index, }; - struct kvec kv =3D { - .iov_base =3D smb->response, - .iov_len =3D smb->resp_len, - }; - struct smb_rqst rqst =3D { - .rq_iov =3D &kv, - .rq_nvec =3D 1 - }; unsigned int rreq_debug_id =3D rdata->rreq->debug_id; unsigned int subreq_debug_index =3D rdata->subreq.debug_index; =20 - iov_iter_bvec_queue(&rqst.rq_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); - + rdata->result =3D smb->error; WARN_ONCE(rdata->server !=3D server, "rdata server %p !=3D mid server %p", rdata->server, server); @@ -4659,7 +4660,7 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) if (server->sign && !smb->decrypted) { int rc; =20 - rc =3D smb2_verify_signature(&rqst, server); + rc =3D smb2_verify_signature(smb, server); if (rc) { cifs_tcon_dbg(VFS, "SMB signature verification returned error =3D %d\n= ", rc); @@ -4765,7 +4766,6 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) rdata->subreq.transferred +=3D smb->resp_data_len; trace_netfs_sreq(&rdata->subreq, netfs_sreq_trace_io_progress); netfs_read_subreq_terminated(&rdata->subreq); - release_mid(server, smb); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_read_response_add); @@ -4776,41 +4776,44 @@ smb2_readv_callback(struct TCP_Server_Info *server,= struct smb_message *smb) int smb2_async_readv(struct cifs_io_subrequest *rdata) { - int rc, flags =3D 0; - char *buf; struct netfs_io_subrequest *subreq =3D &rdata->subreq; - struct smb2_hdr *shdr; - struct cifs_io_parms io_parms; - struct smb_rqst rqst =3D { .rq_iov =3D rdata->iov, - .rq_nvec =3D 1 }; - struct iov_iter iter; struct TCP_Server_Info *server; + struct smb_message *smb; + struct smb2_hdr *shdr; struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); unsigned int total_len; + void *buf; int credit_request; + int rc, flags =3D 0; =20 cifs_dbg(FYI, "%s: offset=3D%llu bytes=3D%zu\n", __func__, subreq->start, subreq->len); =20 - iov_iter_bvec_queue(&iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); - - if (!rdata->server) - rdata->server =3D cifs_pick_channel(tcon->ses); + server =3D rdata->server; + if (!server) + server =3D rdata->server =3D cifs_pick_channel(tcon->ses); + + struct cifs_io_parms io_parms =3D { + .tcon =3D tlink_tcon(rdata->req->cfile->tlink), + .server =3D server, + .offset =3D subreq->start + subreq->transferred, + .length =3D subreq->len - subreq->transferred, + .persistent_fid =3D rdata->req->cfile->fid.persistent_fid, + .volatile_fid =3D rdata->req->cfile->fid.volatile_fid, + .pid =3D rdata->req->pid, + }; =20 - io_parms.tcon =3D tlink_tcon(rdata->req->cfile->tlink); - io_parms.server =3D server =3D rdata->server; - io_parms.offset =3D subreq->start + subreq->transferred; - io_parms.length =3D subreq->len - subreq->transferred; - io_parms.persistent_fid =3D rdata->req->cfile->fid.persistent_fid; - io_parms.volatile_fid =3D rdata->req->cfile->fid.volatile_fid; - io_parms.pid =3D rdata->req->pid; + smb =3D smb_message_alloc(smb2_command_trace_read, GFP_NOFS); + if (!smb) { + rc =3D -ENOMEM; + goto out; + } =20 - rc =3D smb2_new_read_req( - (void **) &buf, &total_len, &io_parms, rdata, 0, 0); - if (rc) + rc =3D smb2_new_read_req(&buf, &total_len, &io_parms, rdata, 0, 0); + if (rc) { + mempool_free(smb, &smb_message_pool); goto out; + } =20 if (smb3_encryption_required(io_parms.tcon)) flags |=3D CIFS_TRANSFORM_REQ; @@ -4819,13 +4822,26 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) rdata->iov[0].iov_len =3D total_len; rdata->result =3D 0; =20 - shdr =3D (struct smb2_hdr *)buf; + smb->rqst.rq_iov =3D rdata->iov; + smb->rqst.rq_nvec =3D 1; + smb->command =3D SMB2_READ; + smb->request =3D buf; + smb->total_len =3D total_len; + smb->callback =3D smb2_readv_callback; + smb->callback_data =3D rdata; + smb->copy_to_bufs =3D true; + + iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, + rdata->subreq.content.bvecq, rdata->subreq.content.slot, + rdata->subreq.content.offset, rdata->subreq.len); + + shdr =3D (struct smb2_hdr *)smb->request; =20 if (rdata->replay) { /* Back-off before retry */ if (rdata->cur_sleep) msleep(rdata->cur_sleep); - smb2_set_replay(server, &rqst); + smb2_set_replay(server, &smb->rqst); } =20 if (rdata->credits.value > 0) { @@ -4846,8 +4862,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) flags |=3D CIFS_HAS_CREDITS; } =20 - rc =3D cifs_call_async(server, &rqst, smb2_readv_callback, rdata, flags, - &rdata->credits, &iter); + rc =3D cifs_call_async(server, smb, flags, &rdata->credits); if (rc) { cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); trace_smb3_read_err(rdata->rreq->debug_id, @@ -4872,6 +4887,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); } =20 + smb_put_message(smb); return rc; } =20 @@ -5087,7 +5103,6 @@ smb2_writev_callback(struct TCP_Server_Info *server, = struct smb_message *smb) wdata->replay =3D true; =20 cifs_write_subrequest_terminated(wdata, result ?: written); - release_mid(server, smb); trace_smb3_rw_credits(rreq_debug_id, subreq_debug_index, 0, server->credits, server->in_flight, credits.value, cifs_trace_rw_credits_write_response_add); @@ -5098,79 +5113,91 @@ smb2_writev_callback(struct TCP_Server_Info *server= , struct smb_message *smb) void smb2_async_writev(struct cifs_io_subrequest *wdata) { - int rc =3D -EACCES, flags =3D 0; struct smb2_write_req *req =3D NULL; + struct smb_message *smb; struct smb2_hdr *shdr; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); struct TCP_Server_Info *server =3D wdata->server; struct kvec iov[1]; - struct smb_rqst rqst =3D { }; unsigned int total_len, xid =3D wdata->xid; - struct cifs_io_parms _io_parms; - struct cifs_io_parms *io_parms =3D NULL; int credit_request; + int rc =3D -EACCES, flags =3D 0; =20 /* * in future we may get cifs_io_parms passed in from the caller, * but for now we construct it here... */ - _io_parms =3D (struct cifs_io_parms) { - .tcon =3D tcon, - .server =3D server, - .offset =3D wdata->subreq.start, - .length =3D wdata->subreq.len, - .persistent_fid =3D wdata->req->cfile->fid.persistent_fid, - .volatile_fid =3D wdata->req->cfile->fid.volatile_fid, - .pid =3D wdata->req->pid, + struct cifs_io_parms io_parms =3D { + .tcon =3D tcon, + .server =3D server, + .offset =3D wdata->subreq.start, + .length =3D wdata->subreq.len, + .persistent_fid =3D wdata->req->cfile->fid.persistent_fid, + .volatile_fid =3D wdata->req->cfile->fid.volatile_fid, + .pid =3D wdata->req->pid, }; - io_parms =3D &_io_parms; + + smb =3D smb_message_alloc(smb2_command_trace_write, GFP_NOFS); + if (!smb) { + rc =3D -ENOMEM; + goto out; + } =20 rc =3D smb2_plain_req_init(SMB2_WRITE, tcon, server, (void **) &req, &total_len); - if (rc) + if (rc) { + mempool_free(smb, &smb_message_pool); goto out; + } =20 - rqst.rq_iov =3D iov; - iov_iter_bvec_queue(&rqst.rq_iter, ITER_SOURCE, + iov[0].iov_len =3D total_len; + iov[0].iov_base =3D (char *)req; + total_len +=3D wdata->subreq.len; + + smb->rqst.rq_iov =3D iov; + smb->rqst.rq_nvec =3D 1; + smb->command =3D SMB2_WRITE; + smb->request =3D req; + smb->total_len =3D total_len; + smb->callback =3D smb2_writev_callback; + smb->callback_data =3D wdata; + + iov_iter_bvec_queue(&smb->rqst.rq_iter, ITER_SOURCE, wdata->subreq.content.bvecq, wdata->subreq.content.slot, wdata->subreq.content.offset, wdata->subreq.len); =20 - rqst.rq_iov[0].iov_len =3D total_len - 1; - rqst.rq_iov[0].iov_base =3D (char *)req; - rqst.rq_nvec +=3D 1; - if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 shdr =3D (struct smb2_hdr *)req; - shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms->pid); - - req->PersistentFileId =3D io_parms->persistent_fid; - req->VolatileFileId =3D io_parms->volatile_fid; - req->WriteChannelInfoOffset =3D 0; - req->WriteChannelInfoLength =3D 0; - req->Channel =3D SMB2_CHANNEL_NONE; - req->Length =3D cpu_to_le32(io_parms->length); - req->Offset =3D cpu_to_le64(io_parms->offset); - req->DataOffset =3D cpu_to_le16( - offsetof(struct smb2_write_req, Buffer)); - req->RemainingBytes =3D 0; + shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms.pid); + + req->PersistentFileId =3D io_parms.persistent_fid; + req->VolatileFileId =3D io_parms.volatile_fid; + req->WriteChannelInfoOffset =3D 0; + req->WriteChannelInfoLength =3D 0; + req->Channel =3D SMB2_CHANNEL_NONE; + req->Length =3D cpu_to_le32(io_parms.length); + req->Offset =3D cpu_to_le64(io_parms.offset); + req->DataOffset =3D + cpu_to_le16(offsetof(struct smb2_write_req, Buffer)); + req->RemainingBytes =3D 0; =20 trace_smb3_write_enter(wdata->rreq->debug_id, wdata->subreq.debug_index, wdata->xid, - io_parms->persistent_fid, - io_parms->tcon->tid, - io_parms->tcon->ses->Suid, - io_parms->offset, - io_parms->length); + io_parms.persistent_fid, + io_parms.tcon->tid, + io_parms.tcon->ses->Suid, + io_parms.offset, + io_parms.length); =20 #ifdef CONFIG_CIFS_SMB_DIRECT /* * If we want to do a server RDMA read, fill in and append * smbdirect_buffer_descriptor_v1 to the end of write request */ - if (smb3_use_rdma_offload(io_parms)) { + if (smb3_use_rdma_offload(&io_parms)) { struct smbdirect_buffer_descriptor_v1 *v1; struct iov_iter iter; bool need_invalidate =3D server->dialect =3D=3D SMB30_PROT_ID; @@ -5199,13 +5226,13 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) v1 =3D (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0]; smbd_mr_fill_buffer_descriptor(wdata->mr, v1); =20 - rqst.rq_iov[0].iov_len +=3D sizeof(*v1); + smb->rqst.rq_iov[0].iov_len +=3D sizeof(*v1); =20 /* * We keep wdata->subreq.io_iter, * but we have to truncate rqst.rq_iter */ - iov_iter_truncate(&rqst.rq_iter, 0); + iov_iter_truncate(&smb->rqst.rq_iter, 0); } #endif =20 @@ -5213,11 +5240,11 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) /* Back-off before retry */ if (wdata->cur_sleep) msleep(wdata->cur_sleep); - smb2_set_replay(server, &rqst); + smb2_set_replay(server, &smb->rqst); } =20 - cifs_dbg(FYI, "async write at %llu %u bytes len=3D%zx\n", - io_parms->offset, io_parms->length, wdata->subreq.len); + cifs_dbg(FYI, "async write at %llu %u bytes iter=3D%zx\n", + io_parms.offset, io_parms.length, iov_iter_count(&smb->rqst.rq_iter)); =20 if (wdata->credits.value > 0) { shdr->CreditCharge =3D cpu_to_le16(DIV_ROUND_UP(wdata->subreq.len, @@ -5238,27 +5265,28 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) } =20 /* XXX: compression + encryption is unsupported for now */ - if (((flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && should_comp= ress(tcon, &rqst)) + if (((flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && + should_compress(tcon, smb)) flags |=3D CIFS_COMPRESS_REQ; =20 - rc =3D cifs_call_async(server, &rqst, smb2_writev_callback, wdata, flags, - &wdata->credits, NULL); + rc =3D cifs_call_async(server, smb, flags, &wdata->credits); /* Can't touch wdata if rc =3D=3D 0 */ if (rc) { trace_smb3_write_err(wdata->rreq->debug_id, wdata->subreq.debug_index, xid, - io_parms->persistent_fid, - io_parms->tcon->tid, - io_parms->tcon->ses->Suid, - io_parms->offset, - io_parms->length, + io_parms.persistent_fid, + io_parms.tcon->tid, + io_parms.tcon->ses->Suid, + io_parms.offset, + io_parms.length, rc); cifs_stats_fail_inc(tcon, SMB2_WRITE_HE); } =20 async_writev_out: cifs_small_buf_release(req); + smb_put_message(smb); out: /* if the send error is retryable, let netfs know about it */ if (is_replayable_error(rc) && diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index 3b4bc946d1bb..bac01d15b94a 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -35,16 +35,9 @@ char *smb2_get_data_area_len(struct cifs_receive *recv); __le16 *cifs_convert_path_to_utf16(const char *from, struct cifs_sb_info *cifs_sb); =20 -int smb2_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); -int smb2_verify_signature(struct smb_rqst *rqst, - struct TCP_Server_Info *server); -int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, - bool log_error); -struct smb_message *smb2_setup_request(struct cifs_ses *ses, - struct TCP_Server_Info *server, - struct smb_rqst *rqst); -struct smb_message *smb2_setup_async_request(struct TCP_Server_Info *serve= r, - struct smb_rqst *rqst); +int smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *serve= r, + struct smb_message *smb); +int smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_me= ssage *smb); struct cifs_tcon *smb2_find_smb_tcon(struct TCP_Server_Info *server, __u64 ses_id, __u32 tid); __le32 smb2_get_lease_state(struct cifsInodeInfo *cinode, unsigned int opl= ock); @@ -52,6 +45,10 @@ void smb2_is_valid_oplock_break(struct TCP_Server_Info *= server, union smb2_response_hdr *h); int smb3_handle_read_data(struct TCP_Server_Info *server, struct smb_message *smb); +int smb2_check_receive(struct smb_message *smb, struct TCP_Server_Info *se= rver, + bool log_error); +int smb2_verify_signature(struct smb_message *smb, struct TCP_Server_Info = *server); +int smb2_receive_pdu(struct TCP_Server_Info *server, unsigned int pdu_len); struct inode *smb2_create_reparse_inode(struct cifs_open_info_data *data, struct super_block *sb, const unsigned int xid, @@ -116,7 +113,7 @@ int smb2_push_mandatory_locks(struct cifsFileInfo *cfil= e); void smb2_reconnect_server(struct work_struct *work); int smb3_crypto_aead_allocate(struct TCP_Server_Info *server); int smb3_init_transform_rq(struct TCP_Server_Info *server, - int num_rqst, const struct smb_rqst *rqst, + struct smb_message *head_smb, struct smb2_transform_hdr *tr_hdr, struct iov_iter *iter); unsigned long smb_rqst_len(struct TCP_Server_Info *server, @@ -128,6 +125,7 @@ bool smb2_should_replay(struct cifs_tcon *tcon, int *pr= etries, int *pcur_sleep); void smb2_add_credits_from_hdr(struct smb2_hdr *shdr, struct TCP_Server_Info *server); +u64 smb2_get_next_mid(struct TCP_Server_Info *server, unsigned int count); struct smb_message *smb2_find_mid(struct TCP_Server_Info *server, struct smb2_hdr *shdr, bool dequeue); #ifdef CONFIG_CIFS_DEBUG2 @@ -274,7 +272,7 @@ void smb2_copy_fs_info_to_kstatfs(struct smb2_fs_full_s= ize_info *pfs_inf, struct kstatfs *kst); void smb311_update_preauth_hash(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct kvec *iov, int nvec); + struct smb_message *smb, bool hash_resp); int smb2_query_info_compound(const unsigned int xid, struct cifs_tcon *tco= n, const char *path, u32 desired_access, u32 class, u32 type, u32 output_len, struct kvec *rsp, @@ -288,4 +286,11 @@ int posix_info_sid_size(const void *beg, const void *e= nd); int smb2_rename_pending_delete(const char *full_path, struct dentry *dentr= y, const unsigned int xid); =20 +/* + * SMB2 Worker functions - most of protocol specific implementation details + * are contained within these calls. + */ + +/* query path info from the server using SMB311 POSIX extensions*/ + #endif /* _SMB2PROTO_H */ diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 874956515322..543b26135085 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -31,7 +31,7 @@ #include "smb2glob.h" =20 static void smb2_parse_pdu(struct TCP_Server_Info *server, - struct netfs_rxqueue *rxq); + struct netfs_rxqueue *rxq, bool decrypted); =20 static int smb3_get_sign_key(__u64 ses_id, struct TCP_Server_Info *server, u8 *ke= y) @@ -208,12 +208,13 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __= u64 ses_id, __u32 tid) } =20 static int -smb2_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) +smb2_calc_signature(struct smb_message *smb, struct TCP_Server_Info *serve= r, + bool for_recv) { int rc; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; - struct kvec *iov =3D rqst->rq_iov; - struct smb2_hdr *shdr =3D (struct smb2_hdr *)iov[0].iov_base; + struct kvec *iov =3D smb->rqst.rq_iov; + struct smb2_hdr *shdr =3D for_recv ? smb->response : smb->request; struct hmac_sha256_ctx hmac_ctx; struct smb_rqst drqst; __u64 sid =3D le64_to_cpu(shdr->SessionId); @@ -238,7 +239,7 @@ smb2_calc_signature(struct smb_rqst *rqst, struct TCP_S= erver_Info *server) * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to * __cifs_calc_signature(). */ - drqst =3D *rqst; + drqst =3D smb->rqst; if (drqst.rq_nvec >=3D 2 && iov[0].iov_len =3D=3D 4) { hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len); drqst.rq_iov++; @@ -460,19 +461,20 @@ generate_smb311signingkey(struct cifs_ses *ses, } =20 static int -smb3_calc_signature(struct smb_rqst *rqst, struct TCP_Server_Info *server) +smb3_calc_signature(struct smb_message *smb, struct TCP_Server_Info *serve= r, + bool for_recv) { int rc; unsigned char smb3_signature[SMB2_CMACAES_SIZE]; - struct kvec *iov =3D rqst->rq_iov; - struct smb2_hdr *shdr =3D (struct smb2_hdr *)iov[0].iov_base; + struct kvec kv; + struct smb2_hdr *shdr =3D for_recv ? smb->response : smb->request; struct aes_cmac_key cmac_key; struct aes_cmac_ctx cmac_ctx; struct smb_rqst drqst; u8 key[SMB3_SIGN_KEY_SIZE]; =20 if (server->vals->protocol_id <=3D SMB21_PROT_ID) - return smb2_calc_signature(rqst, server); + return smb2_calc_signature(smb, server, for_recv); =20 rc =3D smb3_get_sign_key(le64_to_cpu(shdr->SessionId), server, key); if (unlikely(rc)) { @@ -491,18 +493,15 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP= _Server_Info *server) =20 aes_cmac_init(&cmac_ctx, &cmac_key); =20 - /* - * For SMB2+, __cifs_calc_signature() expects to sign only the actual - * data, that is, iov[0] should not contain a rfc1002 length. - * - * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to - * __cifs_calc_signature(). - */ - drqst =3D *rqst; - if (drqst.rq_nvec >=3D 2 && iov[0].iov_len =3D=3D 4) { - aes_cmac_update(&cmac_ctx, iov[0].iov_base, iov[0].iov_len); - drqst.rq_iov++; - drqst.rq_nvec--; + if (for_recv) { + kv.iov_base =3D smb->response; + kv.iov_len =3D smb->resp_len; + drqst.rq_nvec =3D 1; + drqst.rq_iov =3D &kv; + drqst.rq_iter =3D smb->response_iter; + iov_iter_truncate(&drqst.rq_iter, smb->resp_data_len); + } else { + drqst =3D smb->rqst; } =20 rc =3D __cifs_calc_signature( @@ -515,22 +514,21 @@ smb3_calc_signature(struct smb_rqst *rqst, struct TCP= _Server_Info *server) =20 /* must be called with server->srv_mutex held */ static int -smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Server_Info *server) +smb2_sign_rqst(struct smb_message *smb, struct TCP_Server_Info *server) { - struct smb2_hdr *shdr; struct smb2_sess_setup_req *ssr; + struct smb2_hdr *shdr =3D smb->request; bool is_binding; bool is_signed; =20 - shdr =3D (struct smb2_hdr *)rqst->rq_iov[0].iov_base; ssr =3D (struct smb2_sess_setup_req *)shdr; =20 - is_binding =3D shdr->Command =3D=3D SMB2_SESSION_SETUP && + is_binding =3D smb->command =3D=3D SMB2_SESSION_SETUP && (ssr->Flags & SMB2_SESSION_REQ_FLAG_BINDING); is_signed =3D shdr->Flags & SMB2_FLAGS_SIGNED; - if (!is_signed) return 0; + spin_lock(&server->srv_lock); if (server->ops->need_neg && server->ops->need_neg(server)) { @@ -543,22 +541,20 @@ smb2_sign_rqst(struct smb_rqst *rqst, struct TCP_Serv= er_Info *server) return 0; } =20 - return smb3_calc_signature(rqst, server); + return smb3_calc_signature(smb, server, false); } =20 -int -smb2_verify_signature(struct smb_rqst *rqst, struct TCP_Server_Info *serve= r) +int smb2_verify_signature(struct smb_message *smb, struct TCP_Server_Info = *server) { - int rc; + struct smb2_hdr *shdr =3D smb->response; char server_response_sig[SMB2_SIGNATURE_SIZE]; - struct smb2_hdr *shdr =3D - (struct smb2_hdr *)rqst->rq_iov[0].iov_base; + int rc; =20 - if ((shdr->Command =3D=3D SMB2_NEGOTIATE) || - (shdr->Command =3D=3D SMB2_SESSION_SETUP) || - (shdr->Command =3D=3D SMB2_OPLOCK_BREAK) || + if (smb->command =3D=3D SMB2_NEGOTIATE || + smb->command =3D=3D SMB2_SESSION_SETUP || + smb->command =3D=3D SMB2_OPLOCK_BREAK || server->ignore_signature || - (!server->session_estab)) + !server->session_estab) return 0; =20 /* @@ -579,8 +575,7 @@ smb2_verify_signature(struct smb_rqst *rqst, struct TCP= _Server_Info *server) =20 memset(shdr->Signature, 0, SMB2_SIGNATURE_SIZE); =20 - rc =3D smb3_calc_signature(rqst, server); - + rc =3D smb3_calc_signature(smb, server, true); if (rc) return rc; =20 @@ -599,59 +594,42 @@ smb2_verify_signature(struct smb_rqst *rqst, struct T= CP_Server_Info *server) */ static inline void smb2_seq_num_into_buf(struct TCP_Server_Info *server, - struct smb2_hdr *shdr) + struct smb_message *smb) { - unsigned int i, num =3D le16_to_cpu(shdr->CreditCharge); + struct smb2_hdr *shdr =3D smb->request; + unsigned int num =3D le16_to_cpu(shdr->CreditCharge); =20 - shdr->MessageId =3D get_next_mid64(server); /* skip message numbers according to CreditCharge field */ - for (i =3D 1; i < num; i++) - get_next_mid(server); + smb->mid =3D smb2_get_next_mid(server, num); + shdr->MessageId =3D cpu_to_le64(smb->mid); } =20 -static struct smb_message * -smb2_mid_entry_alloc(const struct smb2_hdr *shdr, - struct TCP_Server_Info *server) +static void smb2_init_mid(struct smb_message *smb, + struct TCP_Server_Info *server) { - struct smb_message *smb; + const struct smb2_hdr *shdr =3D smb->request; unsigned int credits =3D le16_to_cpu(shdr->CreditCharge); =20 - if (server =3D=3D NULL) { - cifs_dbg(VFS, "Null TCP session in smb2_mid_entry_alloc\n"); - return NULL; - } - - smb =3D mempool_alloc(&smb_message_pool, GFP_NOFS); - memset(smb, 0, sizeof(*smb)); - refcount_set(&smb->ref, 1); - spin_lock_init(&smb->mid_lock); - smb->mid =3D le64_to_cpu(shdr->MessageId); smb->credits_consumed =3D credits > 0 ? credits : 1; - smb->pid =3D current->pid; - smb->command =3D shdr->Command; /* Always LE */ - smb->when_alloc =3D jiffies; =20 /* * The default is for the mid to be synchronous, so the * default callback just wakes up the current task. */ - get_task_struct(current); - smb->creator =3D current; - smb->callback =3D cifs_wake_up_task; - smb->callback_data =3D current; + smb->creator =3D get_task_struct(current); =20 atomic_inc(&mid_count); - smb->mid_state =3D MID_REQUEST_ALLOCATED; trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId), le64_to_cpu(shdr->SessionId), le16_to_cpu(shdr->Command), smb->mid); - return smb; } =20 static int smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb2_hdr *shdr, struct smb_message **smb) + struct smb_message *smb) { + const struct smb2_hdr *shdr =3D smb->request; + switch (READ_ONCE(server->tcpStatus)) { case CifsExiting: return -ENOENT; @@ -682,13 +660,12 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_S= erver_Info *server, break; } =20 - *smb =3D smb2_mid_entry_alloc(shdr, server); - if (*smb =3D=3D NULL) - return -ENOMEM; + smb2_init_mid(smb, server); + + smb_get_message(smb); spin_lock(&server->mid_queue_lock); - list_add_tail(&(*smb)->qhead, &server->pending_mid_q); + list_add_tail(&smb->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); - return 0; } =20 @@ -697,86 +674,66 @@ smb2_check_receive(struct smb_message *smb, struct TC= P_Server_Info *server, bool log_error) { unsigned int len =3D smb->resp_len; - struct kvec iov[1]; - struct smb_rqst rqst =3D { .rq_iov =3D iov, - .rq_nvec =3D 1 }; - - iov[0].iov_base =3D (char *)smb->response; - iov[0].iov_len =3D len; =20 dump_smb(smb->response, min_t(u32, 80, len)); /* convert the length into a more usable form */ if (len > 24 && server->sign && !smb->decrypted) { int rc; =20 - rc =3D smb2_verify_signature(&rqst, server); + rc =3D smb2_verify_signature(smb, server); if (rc) cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d\= n", rc); } =20 - return map_smb2_to_linux_error(smb->response, log_error); + return smb->error; } =20 -struct smb_message * +int smb2_setup_request(struct cifs_ses *ses, struct TCP_Server_Info *server, - struct smb_rqst *rqst) + struct smb_message *smb) { + struct smb2_hdr *shdr =3D smb->request; int rc; - struct smb2_hdr *shdr =3D - (struct smb2_hdr *)rqst->rq_iov[0].iov_base; - struct smb_message *smb; =20 - smb2_seq_num_into_buf(server, shdr); + smb2_seq_num_into_buf(server, smb); =20 - rc =3D smb2_get_mid_entry(ses, server, shdr, &smb); + rc =3D smb2_get_mid_entry(ses, server, smb); if (rc) { revert_current_mid_from_hdr(server, shdr); - return ERR_PTR(rc); + return rc; } =20 - rc =3D smb2_sign_rqst(rqst, server); - if (rc) { + rc =3D smb2_sign_rqst(smb, server); + if (rc) revert_current_mid_from_hdr(server, shdr); - delete_mid(server, smb); - return ERR_PTR(rc); - } - - return smb; + return rc; } =20 -struct smb_message * -smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_rqst *= rqst) +int +smb2_setup_async_request(struct TCP_Server_Info *server, struct smb_messag= e *smb) { + struct smb2_hdr *shdr =3D smb->request; int rc; - struct smb2_hdr *shdr =3D - (struct smb2_hdr *)rqst->rq_iov[0].iov_base; - struct smb_message *smb; =20 spin_lock(&server->srv_lock); if (server->tcpStatus =3D=3D CifsNeedNegotiate && - shdr->Command !=3D SMB2_NEGOTIATE) { + smb->command !=3D SMB2_NEGOTIATE) { spin_unlock(&server->srv_lock); - return ERR_PTR(-EAGAIN); + return -EAGAIN; } spin_unlock(&server->srv_lock); =20 - smb2_seq_num_into_buf(server, shdr); - - smb =3D smb2_mid_entry_alloc(shdr, server); - if (smb =3D=3D NULL) { - revert_current_mid_from_hdr(server, shdr); - return ERR_PTR(-ENOMEM); - } + smb2_seq_num_into_buf(server, smb); + smb2_init_mid(smb, server); =20 - rc =3D smb2_sign_rqst(rqst, server); + rc =3D smb2_sign_rqst(smb, server); if (rc) { revert_current_mid_from_hdr(server, shdr); - release_mid(server, smb); - return ERR_PTR(rc); + return rc; } =20 - return smb; + return 0; } =20 int @@ -817,6 +774,33 @@ smb3_crypto_aead_allocate(struct TCP_Server_Info *serv= er) return 0; } =20 +/* We can not use the normal sg_set_buf() as we will sometimes pass a + * stack object as buf. + */ +static void cifs_sg_set_buf(struct sg_table *sgtable, + const void *buf, unsigned int buflen) +{ + unsigned long addr =3D (unsigned long)buf; + unsigned int off =3D offset_in_page(addr); + + addr &=3D PAGE_MASK; + if (is_vmalloc_or_module_addr((void *)addr)) { + do { + unsigned int len =3D min_t(unsigned int, buflen, PAGE_SIZE - off); + + sg_set_page(&sgtable->sgl[sgtable->nents++], + vmalloc_to_page((void *)addr), len, off); + + off =3D 0; + addr +=3D PAGE_SIZE; + buflen -=3D len; + } while (buflen); + } else { + sg_set_page(&sgtable->sgl[sgtable->nents++], + virt_to_page((void *)addr), buflen, off); + } +} + /* * Allocate the context info needed for the encryption operation, along wi= th a * scatterlist to point to the buffer. @@ -958,10 +942,12 @@ encrypt_message(struct TCP_Server_Info *server, } =20 static void -fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, unsigned int orig_le= n, - const struct smb_rqst *old_rq, __le16 cipher_type) +fill_transform_hdr(struct smb2_transform_hdr *tr_hdr, + struct smb_message *head_smb, + unsigned int orig_len, + __le16 cipher_type) { - struct smb2_hdr *shdr =3D (struct smb2_hdr *)old_rq->rq_iov[0].iov_base; + struct smb2_hdr *shdr =3D head_smb->request; =20 *tr_hdr =3D (struct smb2_transform_hdr){ .ProtocolId =3D SMB2_TRANSFORM_PROTO_NUM, @@ -983,14 +969,14 @@ fill_transform_hdr(struct smb2_transform_hdr *tr_hdr,= unsigned int orig_len, */ int smb3_init_transform_rq(struct TCP_Server_Info *server, - int num_rqst, const struct smb_rqst *rqst, + struct smb_message *head_smb, struct smb2_transform_hdr *tr_hdr, struct iov_iter *iter) { size_t orig_len =3D iov_iter_count(iter) - sizeof(*tr_hdr); int rc; =20 - fill_transform_hdr(tr_hdr, orig_len, rqst, server->cipher_type); + fill_transform_hdr(tr_hdr, head_smb, orig_len, server->cipher_type); =20 iov_iter_advance(iter, offsetof(struct smb2_transform_hdr, Nonce)); =20 @@ -1105,7 +1091,7 @@ static void smb2_decrypt_offload(struct work_struct *= work) goto out; } =20 - smb2_parse_pdu(dw->server, rxq); + smb2_parse_pdu(dw->server, rxq, true); out: netfs_put_rx_bvecq(rxq->take_from); kfree(dw); @@ -1189,7 +1175,7 @@ static int smb3_reverse_transform(struct TCP_Server_I= nfo *server, =20 rxq->refillable =3D false; decrypt_pdu(server, &tr_hdr, rxq); - smb2_parse_pdu(server, rxq); + smb2_parse_pdu(server, rxq, true); return 0; } =20 @@ -1300,7 +1286,8 @@ static void smb2_copy_to_prepped_buffers(struct TCP_S= erver_Info *server, */ static void smb2_parse_one_message(struct TCP_Server_Info *server, struct cifs_receive *recv, - struct netfs_rxqueue *rxq) + struct netfs_rxqueue *rxq, + bool decrypted) { union smb2_response_hdr *h =3D recv->response; struct smb_message *smb; @@ -1314,6 +1301,7 @@ static void smb2_parse_one_message(struct TCP_Server_= Info *server, rxq->msg_id =3D 0; } else { rxq->msg_id =3D 0; /* TODO: smb->debug_id */ + smb->decrypted =3D decrypted; } =20 /* @@ -1347,12 +1335,12 @@ static void smb2_parse_one_message(struct TCP_Serve= r_Info *server, le64_to_cpu(shdr->MessageId)); cifs_dbg(FYI, "Session expired or deleted\n"); set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); - release_mid(server, smb); + smb_put_message(smb); return; case STATUS_PENDING: smb_rxqueue_consume(server, rxq, rxq->pdu_remain); smb2_status_pending(shdr, server); - release_mid(server, smb); + smb_put_message(smb); return; case STATUS_IO_TIMEOUT: int iotimo =3D atomic_inc_return(&server->num_io_timeout); @@ -1446,7 +1434,7 @@ static void smb2_parse_one_message(struct TCP_Server_= Info *server, dequeue_mid(server, smb, recv->malformed); mid_execute_callback(server, smb); =20 - release_mid(server, smb); + smb_put_message(smb); } else if (shdr->Command =3D=3D cpu_to_le32(SMB2_OPLOCK_BREAK)) { smb2_is_valid_oplock_break(server, h); smb2_add_credits_from_hdr(shdr, server); @@ -1474,7 +1462,7 @@ static void smb2_parse_one_message(struct TCP_Server_= Info *server, * though some may yet to be received. */ static void smb2_parse_pdu(struct TCP_Server_Info *server, - struct netfs_rxqueue *rxq) + struct netfs_rxqueue *rxq, bool decrypted) { u32 next_command, ssize2, next_len; int rc; @@ -1569,7 +1557,7 @@ static void smb2_parse_pdu(struct TCP_Server_Info *se= rver, recv.hdr_len +=3D ssize2; recv.extracted +=3D ssize2; =20 - smb2_parse_one_message(server, &recv, rxq); + smb2_parse_one_message(server, &recv, rxq, decrypted); =20 WARN(rxq->pdu_remain > 0, "MSG=3D%08x pdu_remain=3D%x", rxq->msg_id, rxq->pdu_remain); @@ -1612,6 +1600,6 @@ int smb2_receive_pdu(struct TCP_Server_Info *server, = unsigned int pdu_len) */ if (protocol_id =3D=3D SMB2_TRANSFORM_PROTO_NUM) return smb3_reverse_transform(server, rxq); - smb2_parse_pdu(server, rxq); + smb2_parse_pdu(server, rxq, false); return 0; } diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 7bd04ebbce5d..03ed4925df08 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -21,7 +21,31 @@ * Specify enums for tracing information. */ #define smb_command_traces \ - E_(smb_unknown_command, "unknown-command") + EM(smb2_command_trace_negotiate, "smb2-negotiate") \ + EM(smb2_command_trace_session_setup, "smb2-session_setup") \ + EM(smb2_command_trace_logoff, "smb2-logoff") \ + EM(smb2_command_trace_tree_connect, "smb2-tree_connect") \ + EM(smb2_command_trace_tree_disconnect, "smb2-tree_disconnect") \ + EM(smb2_command_trace_create, "smb2-create") \ + EM(smb2_command_trace_close, "smb2-close") \ + EM(smb2_command_trace_flush, "smb2-flush") \ + EM(smb2_command_trace_read, "smb2-read") \ + EM(smb2_command_trace_write, "smb2-write") \ + EM(smb2_command_trace_lock, "smb2-lock") \ + EM(smb2_command_trace_ioctl, "smb2-ioctl") \ + EM(smb2_command_trace_cancel, "smb2-cancel") \ + EM(smb2_command_trace_echo, "smb2-echo") \ + EM(smb2_command_trace_query_directory, "smb2-query_directory") \ + EM(smb2_command_trace_change_notify, "smb2-change_notify") \ + EM(smb2_command_trace_query_info, "smb2-query_info") \ + EM(smb2_command_trace_set_info, "smb2-set_info") \ + EM(smb2_command_trace_oplock_break, "smb2-oplock_break") \ + EM(smb2_command_trace_s2c_notification, "smb2-s2c-notification") \ + EM(smb1_command_trace_read, "smb1-read") \ + EM(smb1_command_trace_write, "smb1-write") \ + EM(smb1_command_trace_echo, "smb1-echo") \ + EM(smb1_command_trace_unknown, "smb1-unknown") \ + E_(smb_command_trace_unknown, "unknown-command") =20 #define smb_eio_traces \ EM(smb_eio_trace_compress_copy, "compress_copy") \ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 98dca2524376..d0bbd38970db 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -41,7 +41,18 @@ struct smb_message *smb_message_alloc(enum smb_command_t= race cmd, gfp_t gfp) if (smb) { memset(smb, 0, sizeof(*smb)); refcount_set(&smb->ref, 1); + spin_lock_init(&smb->mid_lock); smb->command_trace =3D cmd; + smb->when_alloc =3D jiffies; + smb->pid =3D current->pid; + + /* + * The default is for the mid to be synchronous, so the default + * callback just wakes up the current task. + */ + smb->callback =3D cifs_wake_up_task; + smb->callback_data =3D current; + smb->mid_state =3D MID_REQUEST_ALLOCATED; } return smb; } @@ -61,7 +72,8 @@ void smb_put_message(struct smb_message *smb) } =20 /* - * Dispose of a chain of compound messages. + * Dispose of a chain of compound messages. This should only be called by= the + * caller of smb_send_recv_messages(). */ void smb_put_messages(struct smb_message *smb) { @@ -81,7 +93,7 @@ cifs_wake_up_task(struct TCP_Server_Info *server, struct = smb_message *smb) wake_up_process(smb->callback_data); } =20 -void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb) +static void smb_clear_mid(struct TCP_Server_Info *server, struct smb_messa= ge *smb) { #ifdef CONFIG_CIFS_STATS2 __le16 command =3D server->vals->lock_cmd; @@ -156,22 +168,33 @@ void __release_mid(struct TCP_Server_Info *server, st= ruct smb_message *smb) } #endif put_task_struct(smb->creator); - - mempool_free(smb, &smb_message_pool); } =20 -void -delete_mid(struct TCP_Server_Info *server, struct smb_message *smb) +static bool discard_message(struct TCP_Server_Info *server, struct smb_mes= sage *smb) { + bool got_ref =3D false; + spin_lock(&server->mid_queue_lock); =20 if (!smb->deleted_from_q) { list_del_init(&smb->qhead); smb->deleted_from_q =3D true; + got_ref =3D true; } + spin_unlock(&server->mid_queue_lock); + return got_ref; +} + +static void smb_discard_messages(struct TCP_Server_Info *server, struct sm= b_message *head_smb) +{ + struct smb_message *smb, *next; =20 - release_mid(server, smb); + for (smb =3D head_smb; smb; smb =3D next) { + next =3D smb->next; + if (discard_message(server, smb)) + smb_put_message(smb); + } } =20 /* @@ -444,21 +467,18 @@ static size_t smb3_copy_data_iter(void *iter_from, si= ze_t progress, size_t len, * TODO: In future, the buffers should be allocated by the marshalling cod= e. */ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server, - int num_rqst, struct smb_rqst *rqst, + struct smb_message *head_smb, struct iov_iter *iter, struct bvecq **_bq, unsigned int flags) { + struct smb_message *smb; struct bvecq *bq; size_t total_len =3D 0, offset =3D 0; + int rc; =20 - for (int i =3D 0; i < num_rqst; i++) { - struct smb_rqst *req =3D &rqst[i]; - size_t size =3D iov_iter_count(&req->rq_iter); - - for (int j =3D 0; j < req->rq_nvec; j++) - size +=3D req->rq_iov[j].iov_len; + for (smb =3D head_smb; smb; smb =3D smb->next) { total_len =3D ALIGN8(total_len); - total_len +=3D size; + total_len +=3D smb->total_len; } =20 if (total_len <=3D PAGE_SIZE / 2) { @@ -489,9 +509,9 @@ static int smb_copy_data_into_buffer(struct TCP_Server_= Info *server, =20 iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); =20 - for (int i =3D 0; i < num_rqst; i++) { - struct smb_rqst *req =3D &rqst[i]; - size_t size =3D iov_iter_count(&req->rq_iter); + for (smb =3D head_smb; smb; smb =3D smb->next) { + size_t size =3D iov_iter_count(&smb->rqst.rq_iter); + size_t got; =20 if (offset & 7) { unsigned int tmp =3D offset; @@ -499,23 +519,30 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, iov_iter_zero(offset - tmp, iter); } =20 - for (int j =3D 0; j < req->rq_nvec; j++) { - size_t len =3D req->rq_iov[j].iov_len; - if (copy_to_iter(req->rq_iov[j].iov_base, len, iter) !=3D len) + for (int i =3D 0; i < smb->rqst.rq_nvec; i++) { + size_t len =3D smb->rqst.rq_iov[i].iov_len; + got =3D copy_to_iter(smb->rqst.rq_iov[i].iov_base, len, iter); + if (got !=3D len) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_to_buf, got, size); goto error; + } offset +=3D len; } =20 - if (iterate_and_advance_kernel(&req->rq_iter, - size, iter, NULL, - smb3_copy_data_iter) !=3D size) + got =3D iterate_and_advance_kernel(&smb->rqst.rq_iter, + size, iter, NULL, + smb3_copy_data_iter); + if (got !=3D size) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); goto error; + } =20 offset +=3D size; } =20 if (WARN_ONCE(offset !=3D total_len, "offset=3D%zx total_len=3D%zx\n", offset, total_len)) { + rc =3D smb_EIO2(smb_eio_trace_tx_miscopy_to_buf, offset, total_len); goto error; } =20 @@ -525,12 +552,11 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, error: bvecq_put(bq); *_bq =3D NULL; - return -EIO; + return rc; } =20 static int -smb_send_rqst(struct TCP_Server_Info *server, int num_rqst, - struct smb_rqst *rqst, int flags) +smb_send_rqst(struct TCP_Server_Info *server, struct smb_message *head_smb= , int flags) { struct iov_iter iter; struct bvecq *bq; @@ -543,7 +569,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_r= qst, return smb_EIO(smb_eio_trace_tx_need_transform); } =20 - rc =3D smb_copy_data_into_buffer(server, num_rqst, rqst, &iter, &bq, flag= s); + rc =3D smb_copy_data_into_buffer(server, head_smb, &iter, &bq, flags); if (rc) return rc; content_len =3D iov_iter_count(&iter); @@ -586,7 +612,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_r= qst, /* Fall back to uncompressed. */ } else { if (rc =3D=3D 0) - rc =3D -EIO; + rc =3D smb_EIO(smb_eio_trace_tx_compress_failed); goto error; } } @@ -598,7 +624,7 @@ smb_send_rqst(struct TCP_Server_Info *server, int num_r= qst, iov_iter_advance(&iter, troff); tr_hdr =3D hdr_blob + troff; =20 - rc =3D server->ops->init_transform_rq(server, num_rqst, rqst, tr_hdr, &= iter); + rc =3D server->ops->init_transform_rq(server, head_smb, tr_hdr, &iter); if (rc) goto error; content_len +=3D sizeof(*tr_hdr); @@ -858,16 +884,16 @@ int wait_for_response(struct TCP_Server_Info *server,= struct smb_message *smb) * the result. Caller is responsible for dealing with timeouts. */ int -cifs_call_async(struct TCP_Server_Info *server, struct smb_rqst *rqst, - mid_callback_t callback, void *cbdata, const int flags, - const struct cifs_credits *exist_credits, - struct iov_iter *resp_buf) +cifs_call_async(struct TCP_Server_Info *server, struct smb_message *smb, + const int flags, const struct cifs_credits *exist_credits) { - int rc; - struct smb_message *smb; struct cifs_credits credits =3D { .value =3D 0, .instance =3D 0 }; unsigned int instance; int optype; + int rc; + + if (WARN_ON_ONCE(smb->next)) + return smb_EIO(smb_eio_trace_tx_chained_async); =20 optype =3D flags & CIFS_OP_MASK; =20 @@ -893,23 +919,18 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, return -EAGAIN; } =20 - smb =3D server->ops->setup_async_request(server, rqst); - if (IS_ERR(smb)) { + rc =3D server->ops->setup_async_request(server, smb); + if (rc) { cifs_server_unlock(server); add_credits_and_wake_if(server, &credits, optype); - return PTR_ERR(smb); + return rc; } =20 smb->sr_flags =3D flags; - smb->callback =3D callback; - smb->callback_data =3D cbdata; smb->mid_state =3D MID_REQUEST_SUBMITTED; - if (resp_buf) { - smb->copy_to_bufs =3D true; - smb->response_iter =3D *resp_buf; - } =20 /* put it on the pending_mid_q */ + smb_get_message(smb); spin_lock(&server->mid_queue_lock); list_add_tail(&smb->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); @@ -919,12 +940,13 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_rqst *rqst, * I/O response may come back and free the mid entry on another thread. */ cifs_save_when_sent(smb); - rc =3D smb_send_rqst(server, 1, rqst, flags); + rc =3D smb_send_rqst(server, smb, flags); =20 if (rc < 0) { revert_current_mid(server, smb->credits_consumed); server->sequence_number -=3D 2; - delete_mid(server, smb); + if (discard_message(server, smb)) + smb_put_message(smb); } =20 cifs_server_unlock(server); @@ -974,19 +996,24 @@ int cifs_sync_mid_result(struct smb_message *smb, str= uct TCP_Server_Info *server spin_unlock(&server->mid_queue_lock); =20 sync_mid_done: - release_mid(server, smb); + smb_clear_mid(server, smb); return rc; } =20 static void cifs_compound_callback(struct TCP_Server_Info *server, struct smb_message = *smb) { - struct cifs_credits credits =3D { - .value =3D server->ops->get_credits(smb), - .instance =3D server->reconnect_instance, - }; + if (server) { + struct cifs_credits credits =3D { + .value =3D 1, + .instance =3D server->reconnect_instance, + }; + + if (!is_smb1(server)) + credits.value =3D server->ops->get_credits(smb); =20 - add_credits(server, &credits, smb->optype); + add_credits(server, &credits, smb->optype); + } =20 if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) smb->mid_state =3D MID_RESPONSE_READY; @@ -1003,7 +1030,6 @@ static void cifs_cancelled_callback(struct TCP_Server_Info *server, struct smb_message= *smb) { cifs_compound_callback(server, smb); - release_mid(server, smb); } =20 /* @@ -1059,30 +1085,28 @@ struct TCP_Server_Info *cifs_pick_channel(struct ci= fs_ses *ses) return server; } =20 -int -compound_send_recv(const unsigned int xid, struct cifs_ses *ses, - struct TCP_Server_Info *server, - const int flags, const int num_rqst, struct smb_rqst *rqst, - int *resp_buf_type, struct kvec *resp_iov) +/* + * Send a single message or a string of messages as a compound. + */ +static int smb_send_recv_messages(const unsigned int xid, struct cifs_ses = *ses, + struct TCP_Server_Info *server, + struct smb_message *head_smb, const int flags) { - int i, j, optype, rc =3D 0; - struct smb_message *smb[MAX_COMPOUND]; - bool cancelled_smb[MAX_COMPOUND] =3D {false}; - struct cifs_credits credits[MAX_COMPOUND] =3D { - { .value =3D 0, .instance =3D 0 } - }; unsigned int instance; - - optype =3D flags & CIFS_OP_MASK; - - for (i =3D 0; i < num_rqst; i++) - resp_buf_type[i] =3D CIFS_NO_BUFFER; /* no response buf yet */ + int nr_reqs, i, optype, rc =3D 0; =20 if (!ses || !ses->server || !server) { cifs_dbg(VFS, "Null session\n"); return smb_EIO(smb_eio_trace_null_pointers); } =20 + optype =3D flags & CIFS_OP_MASK; + + /* TODO: Stitch together the messages in a compound. */ + nr_reqs =3D 0; + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + nr_reqs++; + spin_lock(&server->srv_lock); if (server->tcpStatus =3D=3D CifsExiting) { spin_unlock(&server->srv_lock); @@ -1098,14 +1122,13 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, * other requests. * This can be handled by the eventual session reconnect. */ - rc =3D wait_for_compound_request(server, num_rqst, flags, - &instance); + rc =3D wait_for_compound_request(server, nr_reqs, flags, &instance); if (rc) return rc; =20 - for (i =3D 0; i < num_rqst; i++) { - credits[i].value =3D 1; - credits[i].instance =3D instance; + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) { + smb->credits.value =3D 1; + smb->credits.instance =3D instance; } =20 /* @@ -1125,45 +1148,46 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, */ if (instance !=3D server->reconnect_instance) { cifs_server_unlock(server); - for (j =3D 0; j < num_rqst; j++) - add_credits(server, &credits[j], optype); + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + add_credits(server, &smb->credits, optype); return -EAGAIN; } =20 - for (i =3D 0; i < num_rqst; i++) { - smb[i] =3D server->ops->setup_request(ses, server, &rqst[i]); - if (IS_ERR(smb[i])) { - revert_current_mid(server, i); - for (j =3D 0; j < i; j++) - delete_mid(server, smb[j]); - cifs_server_unlock(server); - - /* Update # of requests on wire to server */ - for (j =3D 0; j < num_rqst; j++) - add_credits(server, &credits[j], optype); - return PTR_ERR(smb[i]); - } - - smb[i]->sr_flags =3D flags; - smb[i]->mid_state =3D MID_REQUEST_SUBMITTED; - smb[i]->optype =3D optype; + i =3D 0; + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) { + smb->optype =3D optype; /* * Invoke callback for every part of the compound chain * to calculate credits properly. Wake up this thread only when * the last element is received. */ - if (i < num_rqst - 1) - smb[i]->callback =3D cifs_compound_callback; + if (smb->next) + smb->callback =3D cifs_compound_callback; else - smb[i]->callback =3D cifs_compound_last_callback; + smb->callback =3D cifs_compound_last_callback; + + rc =3D server->ops->setup_request(ses, server, smb); + if (rc) { + revert_current_mid(server, i); + smb_discard_messages(server, head_smb); + cifs_server_unlock(server); + + /* Update # of requests on wire to server */ + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + add_credits(server, &smb->credits, optype); + return rc; + } + + smb->mid_state =3D MID_REQUEST_SUBMITTED; } - rc =3D smb_send_rqst(server, num_rqst, rqst, flags); =20 - for (i =3D 0; i < num_rqst; i++) - cifs_save_when_sent(smb[i]); + rc =3D smb_send_rqst(server, head_smb, flags); + + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + cifs_save_when_sent(smb); =20 if (rc < 0) { - revert_current_mid(server, num_rqst); + revert_current_mid(server, nr_reqs); server->sequence_number -=3D 2; } =20 @@ -1174,8 +1198,8 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, * will not receive a response to - return credits back */ if (rc < 0 || (flags & CIFS_NO_SRV_RSP)) { - for (i =3D 0; i < num_rqst; i++) - add_credits(server, &credits[i], optype); + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + add_credits(server, &smb->credits, optype); goto out; } =20 @@ -1194,72 +1218,60 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, if ((ses->ses_status =3D=3D SES_NEW) || (optype & CIFS_NEG_OP) || (optype= & CIFS_SESS_OP)) { spin_unlock(&ses->ses_lock); =20 - if (WARN_ON_ONCE(num_rqst !=3D 1 || !resp_iov)) + if (WARN_ON_ONCE(head_smb->next)) return -EINVAL; =20 cifs_server_lock(server); - smb311_update_preauth_hash(ses, server, rqst[0].rq_iov, rqst[0].rq_nvec); + smb311_update_preauth_hash(ses, server, head_smb, false); cifs_server_unlock(server); - - spin_lock(&ses->ses_lock); + } else { + spin_unlock(&ses->ses_lock); } - spin_unlock(&ses->ses_lock); =20 - for (i =3D 0; i < num_rqst; i++) { - rc =3D wait_for_response(server, smb[i]); - if (rc !=3D 0) - break; + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) { + if (!smb->next) { + rc =3D wait_for_response(server, smb); + if (rc !=3D 0) + break; + } } if (rc !=3D 0) { - for (; i < num_rqst; i++) { + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) { cifs_server_dbg(FYI, "Cancelling wait for mid %llu cmd: %d\n", - smb[i]->mid, le16_to_cpu(smb[i]->command)); - send_cancel(ses, server, &rqst[i], smb[i], xid); - spin_lock(&smb[i]->mid_lock); - smb[i]->wait_cancelled =3D true; - if (smb[i]->mid_state =3D=3D MID_REQUEST_SUBMITTED || - smb[i]->mid_state =3D=3D MID_RESPONSE_RECEIVED) { - smb[i]->callback =3D cifs_cancelled_callback; - cancelled_smb[i] =3D true; - credits[i].value =3D 0; + smb->mid, le32_to_cpu(smb->command)); + send_cancel(ses, server, smb, xid); + spin_lock(&smb->mid_lock); + smb->wait_cancelled =3D true; + if (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED || + smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) { + smb->callback =3D cifs_cancelled_callback; + smb->cancelled =3D true; + smb->credits.value =3D 0; } - spin_unlock(&smb[i]->mid_lock); + spin_unlock(&smb->mid_lock); } } =20 - for (i =3D 0; i < num_rqst; i++) { + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) { if (rc < 0) goto out; =20 - rc =3D cifs_sync_mid_result(smb[i], server); + rc =3D cifs_sync_mid_result(smb, server); if (rc !=3D 0) { /* mark this mid as cancelled to not free it below */ - cancelled_smb[i] =3D true; + smb->cancelled =3D true; goto out; } =20 - if (!smb[i]->response || - smb[i]->mid_state !=3D MID_RESPONSE_READY) { - rc =3D smb_EIO1(smb_eio_trace_rx_mid_unready, smb[i]->mid_state); + if (!smb->response || + smb->mid_state !=3D MID_RESPONSE_READY) { + rc =3D smb_EIO1(smb_eio_trace_rx_mid_unready, smb->mid_state); cifs_dbg(FYI, "Bad MID state?\n"); goto out; } =20 - rc =3D server->ops->check_receive(smb[i], server, + rc =3D server->ops->check_receive(smb, server, flags & CIFS_LOG_ERROR); - if (resp_iov) { - resp_iov[i].iov_base =3D smb[i]->response; - resp_iov[i].iov_len =3D smb[i]->resp_len; - - if (smb[i]->large_buf) - resp_buf_type[i] =3D CIFS_LARGE_BUFFER; - else - resp_buf_type[i] =3D CIFS_SMALL_BUFFER; - - /* mark it so buf will not be freed by delete_mid */ - if ((flags & CIFS_NO_RSP_BUF) =3D=3D 0) - smb[i]->response =3D NULL; - } } =20 /* @@ -1267,17 +1279,13 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, */ spin_lock(&ses->ses_lock); if ((ses->ses_status =3D=3D SES_NEW) || (optype & CIFS_NEG_OP) || (optype= & CIFS_SESS_OP)) { - struct kvec iov =3D { - .iov_base =3D resp_iov[0].iov_base, - .iov_len =3D resp_iov[0].iov_len - }; spin_unlock(&ses->ses_lock); cifs_server_lock(server); - smb311_update_preauth_hash(ses, server, &iov, 1); + smb311_update_preauth_hash(ses, server, head_smb, true); cifs_server_unlock(server); - spin_lock(&ses->ses_lock); + } else { + spin_unlock(&ses->ses_lock); } - spin_unlock(&ses->ses_lock); =20 out: /* @@ -1286,11 +1294,79 @@ compound_send_recv(const unsigned int xid, struct c= ifs_ses *ses, * This is prevented above by using a noop callback that will not * wake this thread except for the very last PDU. */ - for (i =3D 0; i < num_rqst; i++) { - if (!cancelled_smb[i]) - delete_mid(server, smb[i]); + for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) + if (!smb->cancelled) + discard_message(server, smb); + + return rc; +} + +int +compound_send_recv(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server, + const int flags, const int num_rqst, struct smb_rqst *rqst, + int *resp_buf_type, struct kvec *resp_iov) +{ + struct smb_message *head_smb =3D NULL, **ppsmb =3D &head_smb, *smb; + int rc =3D -ENOMEM; + + if (!ses || !ses->server || !server) { + cifs_dbg(VFS, "Null session\n"); + return smb_EIO(smb_eio_trace_null_pointers); } =20 + for (int i =3D 0; i < num_rqst; i++) { + struct smb_rqst *rq =3D &rqst[i]; + void *request =3D rq->rq_iov[0].iov_base; + struct smb2_hdr *hdr =3D request; + enum smb_command_trace cmd =3D smb_command_trace_unknown; + + if (!is_smb1(server)) + cmd =3D le32_to_cpu(hdr->Command); + + smb =3D smb_message_alloc(cmd, GFP_NOFS); + if (!smb) + goto error; + + *ppsmb =3D smb; + ppsmb =3D &smb->next; + smb->request =3D request; + smb->rqst =3D *rq; + smb->sr_flags =3D flags; + + if (is_smb1(server)) { + smb->command =3D 0; + smb->command_trace =3D smb1_command_trace_unknown; + } + + for (int j =3D 0; j < rq->rq_nvec; j++) + smb->total_len +=3D rq->rq_iov[j].iov_len; + smb->total_len +=3D iov_iter_count(&rq->rq_iter); + } + + rc =3D smb_send_recv_messages(xid, ses, server, head_smb, flags); + + smb =3D head_smb; + for (int i =3D 0; i < num_rqst; i++) { + if (smb->response && !(flags & CIFS_NO_RSP_BUF)) { + resp_iov[i].iov_base =3D smb->response; + resp_iov[i].iov_len =3D smb->resp_len; + smb->response =3D NULL; + + if (smb->large_buf) + resp_buf_type[i] =3D CIFS_LARGE_BUFFER; + else + resp_buf_type[i] =3D CIFS_SMALL_BUFFER; + } else { + resp_iov[i].iov_base =3D NULL; + resp_buf_type[i] =3D 0; + resp_buf_type[i] =3D CIFS_NO_BUFFER; + } + smb =3D smb->next; + } + +error: + smb_put_messages(head_smb); return rc; } From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 5CF064BC03F for ; Tue, 19 May 2026 10:23:55 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186240; cv=none; b=WKH2UQbRuJvswabPdgGKCJyWPway0FkyMbxxFKlBPRBwPAOUQL0JfpG+p+QJForGbi42HHQWYr7zfz7QXepEaxpxCEMMPUC6dB+WbHVdKO/rMnUtR3vi9puKL3lQaNHXv/Hsgdl9lN9ohe7VrqaMOLrZBhlL+mSMUT3U3K0fVpA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186240; c=relaxed/simple; bh=lf0xJA10ZF1np6bpfINkHyQYEJMIrla0lxLV9B2lpug=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=V300WQ0WOrzLymlKwimfzSQZ+g0h/HuKMxYgqzm3jhXRj5LLPGOELM7Kiy+hqd35ih8E/EHcKw6DpBuO2h9OuDPrut0RaKsLRrSth2WbYYLUW+uuvGXPJ3Wm9EHSSxJJqKjWZbScBBPTJauMR7JJ/wiLhywnjQDAR7wZOHaFr7Y= 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=h5BcpZPu; arc=none smtp.client-ip=170.10.133.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="h5BcpZPu" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186235; 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=bwtmtV+/BP9WRUWfkBmBVGjokBH4hjCTpxEToiEclRI=; b=h5BcpZPuOuf2xcagkf+F+4z2eOcoDBGBg82FXz2pUd+sLJhd8nPE3VFAtb+OWB35oCNnJs abEB9o/SqkObAApjDcI6osGjQTRH/287TU0d4SQUXz820RkbKs+25YBrL4EqbBvg7asfjK T48oy0aNBKUrGC0PacemKLIGI1Z5v80= Received: from mx-prod-mc-06.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-444-wDgwadrONoGGemrHhjhj9A-1; Tue, 19 May 2026 06:23:51 -0400 X-MC-Unique: wDgwadrONoGGemrHhjhj9A-1 X-Mimecast-MFC-AGG-ID: wDgwadrONoGGemrHhjhj9A_1779186229 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A30991800283; Tue, 19 May 2026 10:23:49 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 3D3ED30001A2; Tue, 19 May 2026 10:23:46 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 21/36] cifs: Add a tracepoint to trace the smb_message refcount Date: Tue, 19 May 2026 11:21:39 +0100 Message-ID: <20260519102158.592165-22-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 Content-Type: text/plain; charset="utf-8" Add a tracepoint to trace the smb_message refcount and to log the various different reasons that things that can happen to it. 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/cifsglob.h | 1 + fs/smb/client/cifsproto.h | 5 ++- fs/smb/client/cifssmb.c | 6 +-- fs/smb/client/connect.c | 11 +++-- fs/smb/client/smb1ops.c | 2 +- fs/smb/client/smb1transport.c | 10 ++--- fs/smb/client/smb2ops.c | 2 +- fs/smb/client/smb2pdu.c | 10 ++--- fs/smb/client/smb2transport.c | 25 ++++++------ fs/smb/client/trace.h | 77 ++++++++++++++++++++++++++++++++--- fs/smb/client/transport.c | 50 +++++++++++++++++++---- 11 files changed, 151 insertions(+), 48 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index c444b7d81c23..6b90f17ae0fa 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1669,6 +1669,7 @@ struct smb_message { struct cifs_credits credits; /* Credit requirements for this message */ void *request; /* Pointer to request message body */ refcount_t ref; + unsigned int debug_id; /* Debugging ID for tracing */ bool sensitive; /* Request contains sensitive data */ bool cancelled; /* T if cancelled */ unsigned int sr_flags; /* Flags passed to send_recv() */ diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 47f78955796f..72ee5c5fd8b7 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -82,8 +82,9 @@ char *cifs_build_path_to_root(struct smb3_fs_context *ctx, char *cifs_build_devname(char *nodename, const char *prepath); void delete_mid(struct TCP_Server_Info *server, struct smb_message *smb); struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gf= p); -void smb_get_message(struct smb_message *smb); -void smb_put_message(struct smb_message *smb); +void smb_see_message(struct smb_message *smb, enum smb_message_trace trace= ); +void smb_get_message(struct smb_message *smb, enum smb_message_trace trace= ); +void smb_put_message(struct smb_message *smb, enum smb_message_trace trace= ); void smb_put_messages(struct smb_message *smb); void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb= ); void cifs_wake_up_task(struct TCP_Server_Info *server, diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index ebd95de2cd91..ca6410e1f39e 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -744,7 +744,7 @@ CIFSSMBEcho(struct TCP_Server_Info *server) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 cifs_small_buf_release(req); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_end); return rc; } =20 @@ -1614,7 +1614,7 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) if (rc =3D=3D 0) cifs_stats_inc(&tcon->stats.cifs_stats.num_reads); put_smb: - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_end); return rc; } =20 @@ -2022,7 +2022,7 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) async_writev_out: cifs_small_buf_release(req); out_put: - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_end); out: if (rc) { add_credits_and_wake_if(wdata->server, &wdata->credits, 0); diff --git a/fs/smb/client/connect.c b/fs/smb/client/connect.c index dd092f0a0515..99b7c3f165cb 100644 --- a/fs/smb/client/connect.c +++ b/fs/smb/client/connect.c @@ -364,6 +364,7 @@ cifs_abort_connection(struct TCP_Server_Info *server) cifs_dbg(FYI, "%s: moving mids to private list\n", __func__); spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { + smb_see_message(smb, smb_message_trace_see_abort_conn); if (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) smb->mid_state =3D MID_RETRY_NEEDED; list_move(&smb->qhead, &retry_list); @@ -376,7 +377,7 @@ cifs_abort_connection(struct TCP_Server_Info *server) list_for_each_entry_safe(smb, nsmb, &retry_list, qhead) { list_del_init(&smb->qhead); mid_execute_callback(server, smb); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_abort_conn); } } =20 @@ -821,6 +822,7 @@ static bool smb_decode_rfc1002(struct TCP_Server_Info *= server, u32 rfc1002_hdr) */ spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, nsmb, &server->pending_mid_q, qhead) { + smb_see_message(smb, smb_message_trace_see_is_smb_resp); list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; } @@ -854,7 +856,7 @@ static bool smb_decode_rfc1002(struct TCP_Server_Info *= server, u32 rfc1002_hdr) smb->mid_rc =3D mid_rc; smb->mid_state =3D MID_RC; mid_execute_callback(server, smb); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_is_smb_resp); } =20 /* @@ -908,7 +910,7 @@ dequeue_mid(struct TCP_Server_Info *server, struct smb_= message *smb, bool malfor spin_unlock(&server->mid_queue_lock); pr_warn_once("trying to dequeue a deleted mid\n"); } else { - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_dequeue_mid); list_del_init(&smb->qhead); smb->deleted_from_q =3D true; spin_unlock(&server->mid_queue_lock); @@ -1015,6 +1017,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) spin_lock(&server->mid_queue_lock); list_for_each_entry_safe(smb, smb2, &server->pending_mid_q, qhead) { cifs_dbg(FYI, "Clearing mid %llu\n", smb->mid); + smb_see_message(smb, smb_message_trace_see_clean_demux); smb->mid_state =3D MID_SHUTDOWN; list_move(&smb->qhead, &dispose_list); smb->deleted_from_q =3D true; @@ -1026,7 +1029,7 @@ clean_demultiplex_info(struct TCP_Server_Info *server) cifs_dbg(FYI, "Callback mid %llu\n", smb->mid); list_del_init(&smb->qhead); mid_execute_callback(server, smb); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_clean_demux); } /* 1/8th of sec is more than enough time for them to exit */ msleep(125); diff --git a/fs/smb/client/smb1ops.c b/fs/smb/client/smb1ops.c index fb3529a79c6b..a2a2167c0e22 100644 --- a/fs/smb/client/smb1ops.c +++ b/fs/smb/client/smb1ops.c @@ -236,7 +236,7 @@ cifs_find_mid(struct TCP_Server_Info *server, const str= uct smb_hdr *shdr) if (smb->mid =3D=3D mid && smb->mid_state =3D=3D MID_REQUEST_SUBMITTED && smb->command =3D=3D shdr->Command) { - smb_get_message(smb); + smb_get_message(smb, smb_message_trace_get_find_mid); spin_unlock(&server->mid_queue_lock); return smb; } diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 1bbfa0844e6f..ba887284fadd 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -58,7 +58,7 @@ static int allocate_mid(struct cifs_ses *ses, struct smb_= message *smb) } spin_unlock(&ses->ses_lock); =20 - smb_get_message(smb); + smb_get_message(smb, smb_message_trace_get_enqueue_sync); spin_lock(&ses->server->mid_queue_lock); list_add_tail(&smb->qhead, &ses->server->pending_mid_q); spin_unlock(&ses->server->mid_queue_lock); @@ -85,7 +85,7 @@ cifs_setup_async_request(struct TCP_Server_Info *server, = struct smb_message *smb =20 rc =3D cifs_sign_rqst(&smb->rqst, server, &smb->sequence_number); if (rc) { - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_end); return rc; } =20 @@ -891,7 +891,7 @@ static void smb1_parse_one_message(struct TCP_Server_In= fo *server, __func__, le16_to_cpu(shdr->Mid)); rxq->msg_id =3D 0; } else { - rxq->msg_id =3D 0; /* TODO: smb->debug_id */ + rxq->msg_id =3D smb->debug_id; } =20 /* No session expiry check. */ @@ -921,7 +921,7 @@ static void smb1_parse_one_message(struct TCP_Server_In= fo *server, /* Handle multipart trans2-class messages. */ rc =3D smb1_trans2_receive(server, smb, recv, rxq); if (rc =3D=3D 1) { - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_incomplete); return; /* Multipart, incomplete. */ } if (rc < 0) @@ -995,7 +995,7 @@ static void smb1_parse_one_message(struct TCP_Server_In= fo *server, dequeue_mid(server, smb, recv->malformed); mid_execute_callback(server, smb); =20 - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_delivered); } else if (smb1_is_valid_oplock_break(h, recv->msg_len, server)) { cifs_dbg(FYI, "Received oplock break\n"); smb_rxqueue_consume(server, rxq, rxq->pdu_remain); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 93ec64d67d54..0aaefe901fbd 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -439,7 +439,7 @@ smb2_find_mid(struct TCP_Server_Info *server, struct sm= b2_hdr *shdr, bool dequeu if ((smb->mid =3D=3D wire_mid) && (smb->mid_state =3D=3D MID_REQUEST_SUBMITTED) && (smb->command =3D=3D shdr->Command)) { - smb_get_message(smb); + smb_get_message(smb, smb_message_trace_get_find_mid); if (dequeue) { list_del_init(&smb->qhead); smb->deleted_from_q =3D true; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 5919cd99dec6..2a234df2fad5 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4395,7 +4395,7 @@ SMB2_echo(struct TCP_Server_Info *server) cifs_dbg(FYI, "Echo request failed: %d\n", rc); =20 cifs_small_buf_release(req); - smb_put_message(smb); + smb_put_messages(smb); return rc; } =20 @@ -4662,8 +4662,8 @@ smb2_readv_callback(struct TCP_Server_Info *server, s= truct smb_message *smb) =20 rc =3D smb2_verify_signature(smb, server); if (rc) { - cifs_tcon_dbg(VFS, "SMB signature verification returned error =3D %d\n= ", - rc); + cifs_tcon_dbg(VFS, "SMB signature verification returned error =3D %d (= MSG=3D%x)\n", + rc, smb->debug_id); rdata->subreq.error =3D rc; rdata->result =3D rc; =20 @@ -4887,7 +4887,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); } =20 - smb_put_message(smb); + smb_put_messages(smb); return rc; } =20 @@ -5286,7 +5286,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) =20 async_writev_out: cifs_small_buf_release(req); - smb_put_message(smb); + smb_put_messages(smb); out: /* if the send error is retryable, let netfs know about it */ if (is_replayable_error(rc) && diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 543b26135085..404bb8b1b3c3 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -579,13 +579,12 @@ int smb2_verify_signature(struct smb_message *smb, st= ruct TCP_Server_Info *serve if (rc) return rc; =20 - if (crypto_memneq(server_response_sig, shdr->Signature, - SMB2_SIGNATURE_SIZE)) { - cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx\n", - shdr->Command, shdr->MessageId); - return -EACCES; - } else + if (crypto_memneq(server_response_sig, shdr->Signature, SMB2_SIGNATURE_SI= ZE)) return 0; + + cifs_dbg(VFS, "sign fail cmd 0x%x message id 0x%llx MSG=3D%x\n", + shdr->Command, shdr->MessageId, smb->debug_id); + return -EACCES; } =20 /* @@ -662,7 +661,7 @@ smb2_get_mid_entry(struct cifs_ses *ses, struct TCP_Ser= ver_Info *server, =20 smb2_init_mid(smb, server); =20 - smb_get_message(smb); + smb_get_message(smb, smb_message_trace_get_enqueue_sync); spin_lock(&server->mid_queue_lock); list_add_tail(&smb->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); @@ -682,8 +681,8 @@ smb2_check_receive(struct smb_message *smb, struct TCP_= Server_Info *server, =20 rc =3D smb2_verify_signature(smb, server); if (rc) - cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d\= n", - rc); + cifs_server_dbg(VFS, "SMB signature verification returned error =3D %d = (MSG=3D%x)\n", + rc, smb->debug_id); } =20 return smb->error; @@ -1300,7 +1299,7 @@ static void smb2_parse_one_message(struct TCP_Server_= Info *server, __func__, le64_to_cpu(shdr->MessageId)); rxq->msg_id =3D 0; } else { - rxq->msg_id =3D 0; /* TODO: smb->debug_id */ + rxq->msg_id =3D smb->debug_id; smb->decrypted =3D decrypted; } =20 @@ -1335,12 +1334,12 @@ static void smb2_parse_one_message(struct TCP_Serve= r_Info *server, le64_to_cpu(shdr->MessageId)); cifs_dbg(FYI, "Session expired or deleted\n"); set_bit(SMB_SERVER_NEED_RECONNECT, &server->flags); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_session_expired); return; case STATUS_PENDING: smb_rxqueue_consume(server, rxq, rxq->pdu_remain); smb2_status_pending(shdr, server); - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_pending); return; case STATUS_IO_TIMEOUT: int iotimo =3D atomic_inc_return(&server->num_io_timeout); @@ -1434,7 +1433,7 @@ static void smb2_parse_one_message(struct TCP_Server_= Info *server, dequeue_mid(server, smb, recv->malformed); mid_execute_callback(server, smb); =20 - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_delivered); } else if (shdr->Command =3D=3D cpu_to_le32(SMB2_OPLOCK_BREAK)) { smb2_is_valid_oplock_break(server, h); smb2_add_credits_from_hdr(shdr, server); diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 03ed4925df08..2cdbd8249af0 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -178,6 +178,50 @@ EM(smb_eio_trace_write_rsp_malformed, "write_rsp_malformed") \ E_(smb_eio_trace_write_too_far, "write_too_far") =20 +#define smb_message_traces \ + EM(smb_message_trace_alloc_cancel, "AL Cancel ") \ + EM(smb_message_trace_alloc_change_notify, "AL Change-Nfy") \ + EM(smb_message_trace_alloc_close, "AL Close ") \ + EM(smb_message_trace_alloc_create, "AL Create ") \ + EM(smb_message_trace_alloc_echo, "AL Echo ") \ + EM(smb_message_trace_alloc_flush, "AL Flush ") \ + EM(smb_message_trace_alloc_ioctl, "AL Ioctl ") \ + EM(smb_message_trace_alloc_lock, "AL Lock ") \ + EM(smb_message_trace_alloc_logoff, "AL Logoff ") \ + EM(smb_message_trace_alloc_negotiate, "AL Negotiate ") \ + EM(smb_message_trace_alloc_oplock_break, "AL Oplock-Brk") \ + EM(smb_message_trace_alloc_query_directory, "AL Query-Dir ") \ + EM(smb_message_trace_alloc_query_info, "AL Query-Info") \ + EM(smb_message_trace_alloc_read, "AL Read ") \ + EM(smb_message_trace_alloc_session_setup, "AL Sess-setup") \ + EM(smb_message_trace_alloc_set_info, "AL Set-Info ") \ + EM(smb_message_trace_alloc_srv_to_cln_notif, "AL s2c-Notify") \ + EM(smb_message_trace_alloc_tree_connect, "AL Tree-conn ") \ + EM(smb_message_trace_alloc_tree_disconnect, "AL Tree-disc ") \ + EM(smb_message_trace_alloc_write, "AL Write ") \ + EM(smb_message_trace_free, "FREE ") \ + EM(smb_message_trace_get_call_async, "GET call-asyn") \ + EM(smb_message_trace_get_enqueue_sync, "GET enq-sync ") \ + EM(smb_message_trace_get_find_mid, "GET find-mid ") \ + EM(smb_message_trace_put_abort_conn, "PUT abrt-conn") \ + EM(smb_message_trace_put_clean_demux, "PUT cln-demux") \ + EM(smb_message_trace_put_decrypt_offload, "PUT decrypt-o") \ + EM(smb_message_trace_put_delivered, "PUT delivered") \ + EM(smb_message_trace_put_demux, "PUT demux ") \ + EM(smb_message_trace_put_demux_cb, "PUT demux-cb ") \ + EM(smb_message_trace_put_dequeue_mid, "SEE deque-mid") \ + EM(smb_message_trace_put_discard_message, "PUT disc-msg ") \ + EM(smb_message_trace_put_end, "PUT end ") \ + EM(smb_message_trace_put_incomplete, "PUT incomplet") \ + EM(smb_message_trace_put_is_smb_resp, "PUT is-s-resp") \ + EM(smb_message_trace_put_messages, "PUT messages ") \ + EM(smb_message_trace_put_pending, "PUT pending ") \ + EM(smb_message_trace_put_session_expired, "PUT sess-exp ") \ + EM(smb_message_trace_see_abort_conn, "SEE abrt-conn") \ + EM(smb_message_trace_see_clean_demux, "SEE cln-demux") \ + EM(smb_message_trace_see_is_smb_resp, "SEE is-s-resp") \ + E_(smb_message_trace_see_wake_up_task, "SEE wake-task") + #define smb3_rw_credits_traces \ EM(cifs_trace_rw_credits_call_readv_adjust, "rd-call-adj") \ EM(cifs_trace_rw_credits_call_writev_adjust, "wr-call-adj") \ @@ -241,6 +285,7 @@ =20 enum smb_command_trace { smb_command_traces } __mode(byte); enum smb_eio_trace { smb_eio_traces } __mode(byte); +enum smb_message_trace { smb_message_traces } __mode(byte); enum smb3_rw_credits_trace { smb3_rw_credits_traces } __mode(byte); enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mode(byte); =20 @@ -256,6 +301,7 @@ enum smb3_tcon_ref_trace { smb3_tcon_ref_traces } __mod= e(byte); =20 smb_command_traces; smb_eio_traces; +smb_message_traces; smb3_rw_credits_traces; smb3_tcon_ref_traces; =20 @@ -2030,26 +2076,47 @@ TRACE_EVENT(smb3_reply, TP_ARGS(smb, recv), TP_STRUCT__entry( __field(unsigned int, msg_id) - __field(unsigned int, cmd) + __field(enum smb_command_trace, cmd) __field(unsigned int, doff) __field(unsigned int, dlen) __field(unsigned int, len) __field(unsigned int, extr) ), TP_fast_assign( - __entry->msg_id =3D 0; /* TODO: fill in */ - __entry->cmd =3D smb->command; + __entry->msg_id =3D smb->debug_id; + __entry->cmd =3D smb->command_trace; __entry->doff =3D recv->data_offset; __entry->dlen =3D recv->data_len; __entry->len =3D recv->msg_len; __entry->extr =3D recv->extracted; ), - TP_printk("MSG=3D%08x cmd=3D%x d=3D%x-%x l=3D%x/%x", - __entry->msg_id, __entry->cmd, + TP_printk("MSG=3D%08x cmd=3D%s d=3D%x-%x l=3D%x/%x", + __entry->msg_id, + __print_symbolic(__entry->cmd, smb_command_traces), __entry->doff, __entry->doff + __entry->dlen, __entry->extr, __entry->len) ); =20 +TRACE_EVENT(smb3_message, + TP_PROTO(unsigned int smb_message_debug_id, int ref, + enum smb_message_trace trace), + TP_ARGS(smb_message_debug_id, ref, trace), + TP_STRUCT__entry( + __field(unsigned int, smb_message) + __field(int, ref) + __field(enum smb_message_trace, trace) + ), + TP_fast_assign( + __entry->smb_message =3D smb_message_debug_id; + __entry->ref =3D ref; + __entry->trace =3D trace; + ), + TP_printk("MSG=3D%08x %s r=3D%d", + __entry->smb_message, + __print_symbolic(__entry->trace, smb_message_traces), + __entry->ref) + ); + #undef EM #undef E_ #endif /* _CIFS_TRACE_H */ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index d0bbd38970db..0a7b2e7922cf 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -35,6 +35,7 @@ =20 struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gf= p) { + static atomic_t debug_ids; struct smb_message *smb; =20 smb =3D mempool_alloc(&smb_message_pool, gfp); @@ -42,6 +43,7 @@ struct smb_message *smb_message_alloc(enum smb_command_tr= ace cmd, gfp_t gfp) memset(smb, 0, sizeof(*smb)); refcount_set(&smb->ref, 1); spin_lock_init(&smb->mid_lock); + smb->debug_id =3D atomic_inc_return(&debug_ids); smb->command_trace =3D cmd; smb->when_alloc =3D jiffies; smb->pid =3D current->pid; @@ -53,22 +55,44 @@ struct smb_message *smb_message_alloc(enum smb_command_= trace cmd, gfp_t gfp) smb->callback =3D cifs_wake_up_task; smb->callback_data =3D current; smb->mid_state =3D MID_REQUEST_ALLOCATED; + trace_smb3_message(smb->debug_id, 1, (enum smb_message_trace)cmd); } return smb; } =20 -void smb_get_message(struct smb_message *smb) +void smb_see_message(struct smb_message *smb, enum smb_message_trace trace) { - refcount_inc(&smb->ref); + trace_smb3_message(smb->debug_id, refcount_read(&smb->ref), trace); +} + +void smb_get_message(struct smb_message *smb, enum smb_message_trace trace) +{ + int r; + + __refcount_inc(&smb->ref, &r); + trace_smb3_message(smb->debug_id, r + 1, trace); +} + +static void smb_free_message(struct smb_message *smb) +{ + trace_smb3_message(smb->debug_id, refcount_read(&smb->ref), + smb_message_trace_free); + mempool_free(smb, &smb_message_pool); } =20 /* * Drop a ref on a message. This does not touch the chained messages. */ -void smb_put_message(struct smb_message *smb) +void smb_put_message(struct smb_message *smb, enum smb_message_trace trace) { - if (refcount_dec_and_test(&smb->ref)) - mempool_free(smb, &smb_message_pool); + unsigned int debug_id =3D smb->debug_id; + bool dead; + int r; + + dead =3D __refcount_dec_and_test(&smb->ref, &r); + trace_smb3_message(debug_id, r - 1, trace); + if (dead) + smb_free_message(smb); } =20 /* @@ -80,8 +104,15 @@ void smb_put_messages(struct smb_message *smb) struct smb_message *next; =20 for (; smb; smb =3D next) { + unsigned int debug_id =3D smb->debug_id; + bool dead; + int r; + next =3D smb->next; - smb_put_message(smb); + dead =3D __refcount_dec_and_test(&smb->ref, &r); + trace_smb3_message(debug_id, r - 1, smb_message_trace_put_messages); + if (dead) + smb_free_message(smb); } } =20 @@ -90,6 +121,7 @@ cifs_wake_up_task(struct TCP_Server_Info *server, struct= smb_message *smb) { if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) smb->mid_state =3D MID_RESPONSE_READY; + smb_see_message(smb, smb_message_trace_see_wake_up_task); wake_up_process(smb->callback_data); } =20 @@ -193,7 +225,7 @@ static void smb_discard_messages(struct TCP_Server_Info= *server, struct smb_mess for (smb =3D head_smb; smb; smb =3D next) { next =3D smb->next; if (discard_message(server, smb)) - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_discard_message); } } =20 @@ -930,7 +962,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct = smb_message *smb, smb->mid_state =3D MID_REQUEST_SUBMITTED; =20 /* put it on the pending_mid_q */ - smb_get_message(smb); + smb_get_message(smb, smb_message_trace_get_call_async); spin_lock(&server->mid_queue_lock); list_add_tail(&smb->qhead, &server->pending_mid_q); spin_unlock(&server->mid_queue_lock); @@ -946,7 +978,7 @@ cifs_call_async(struct TCP_Server_Info *server, struct = smb_message *smb, revert_current_mid(server, smb->credits_consumed); server->sequence_number -=3D 2; if (discard_message(server, smb)) - smb_put_message(smb); + smb_put_message(smb, smb_message_trace_put_discard_message); } =20 cifs_server_unlock(server); From nobody Mon May 25 02:42:24 2026 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 A557F4DA534 for ; Tue, 19 May 2026 10:24:02 +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=1779186244; cv=none; b=ClWTQ7IIKtpgst37W4Jbb40YDsDRuLlkwjmqk7/oBrHxHMmUj6A/SulHCXxG0938lOcA8Jo8++pq2Ttkt3lXWy5d3IPiLZq8eAtrYZes40ATSWMhqRpJ3QTV9ebSkEvDHTFn1DfOr/tNVJpATRlAhoCY0ctJUuZv4n3FiicXoew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186244; c=relaxed/simple; bh=/kKkibd7I4UJ09vAtMQS+No+nXWxHYtsFqDZ55RCPY8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KTYlp22EddbdkRVeyyZR2h89Q8Vmc8maROgVE/yv4djjSZ90TBLTREjslENFuFW95gxnYN0sGfbj/3IetEoMhMZpXorSG9L3c8Y9eewDGoPJ//NgvDfcPYZzvmJR/lHgLAipEamioWo/6bNQRCbg/ghuZE6YUre7ZhVUIAggWvc= 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=A5ZTqLxK; 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="A5ZTqLxK" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186241; 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=rsISW/5Ynsi9gefanojoMknHhkwuwBucOgMcvE2JXxc=; b=A5ZTqLxKAprL5CKaWni3PfWin8kg5LGblC9+eOAF8+e/MuSB1IfroDeLW6t0wmtZsVEaQZ z2pORRv8TWFkLRdM0XIA969izE4lsamZHbvbLD+eTBhNvSfrvUazIf3cIzDa3y+aCNHfvX yC7ld9YWYgrWJH9vTb+EtZZh8xZ4zvU= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-497-I8skbF-WM5mTJBuWOjOFaA-1; Tue, 19 May 2026 06:23:56 -0400 X-MC-Unique: I8skbF-WM5mTJBuWOjOFaA-1 X-Mimecast-MFC-AGG-ID: I8skbF-WM5mTJBuWOjOFaA_1779186234 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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 7E4C519560A7; Tue, 19 May 2026 10:23:54 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 55FAB1956053; Tue, 19 May 2026 10:23:51 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 22/36] cifs: Trace smb1/2_copy_to_prepped_buffers() Date: Tue, 19 May 2026 11:21:40 +0100 Message-ID: <20260519102158.592165-23-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" Add a tracepoint to smb1/2_copy_to_prepped_buffers() so that bulk data read (such as a Read op) can be checked. Signed-off-by: David Howells cc: Steve French cc: Paulo Alcantara cc: Shyam Prasad N cc: linux-cifs@vger.kernel.org cc: netfs@lists.linux.dev cc: linux-fsdevel@vger.kernel.org --- fs/smb/client/smb1transport.c | 1 + fs/smb/client/smb2transport.c | 1 + fs/smb/client/trace.h | 21 +++++++++++++++++++++ 3 files changed, 23 insertions(+) diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index ba887284fadd..598579b564ae 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -829,6 +829,7 @@ static void smb1_copy_to_prepped_buffers(struct TCP_Ser= ver_Info *server, return; } =20 + trace_smb3_copy_to_buf(smb, &dest, skip, to_copy); if (!rxq->refillable) { size_t got; =20 diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 404bb8b1b3c3..73db90ab8a52 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -1236,6 +1236,7 @@ static void smb2_copy_to_prepped_buffers(struct TCP_S= erver_Info *server, return; } =20 + trace_smb3_copy_to_buf(smb, &dest, skip, to_copy); if (!rxq->refillable) { size_t got; =20 diff --git a/fs/smb/client/trace.h b/fs/smb/client/trace.h index 2cdbd8249af0..e9abcc5cf83a 100644 --- a/fs/smb/client/trace.h +++ b/fs/smb/client/trace.h @@ -2117,6 +2117,27 @@ TRACE_EVENT(smb3_message, __entry->ref) ); =20 +TRACE_EVENT(smb3_copy_to_buf, + TP_PROTO(const struct smb_message *smb, const struct iov_iter *dest, + unsigned int msg_offset, unsigned int len), + TP_ARGS(smb, dest, msg_offset, len), + TP_STRUCT__entry( + __field(unsigned int, smb_message) + __field(unsigned int, dest_len) + __field(unsigned int, msg_offset) + __field(unsigned int, len) + ), + TP_fast_assign( + __entry->smb_message =3D smb->debug_id; + __entry->dest_len =3D iov_iter_count(dest); + __entry->msg_offset =3D msg_offset; + __entry->len =3D len; + ), + TP_printk("MSG=3D%08x m=3D%x sl=3D%x dl=3D%x", + __entry->smb_message, + __entry->msg_offset, __entry->len, __entry->dest_len) + ); + #undef EM #undef E_ #endif /* _CIFS_TRACE_H */ From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 E9DE44DBD94 for ; Tue, 19 May 2026 10:24:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186252; cv=none; b=kYi14/hrqAeILGC8KqAwyMoTVnONKRRJCw/SuoYnKlqml998Mcl1Z0fUtMo/HXi+97LgFMU6nXGyISoNwUdAknSgzWT8MwR7nMYlTLG5Y15VaoY1Fjz5XwohN2bqY70Zgw7jXXcZW6OMliJA2QArPfbaLGC60/wqnxT9mMmsK8s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186252; c=relaxed/simple; bh=faGQwSUM6yKBa2MK0bDX+e2+5HxnYhgUgJ/1CbQpodo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eWyUXZ2XC87elox2+/ck8KLIGLSCJt+HllaNS8s55BvmN6v1MZ8X3hRUHVkDe19evVyGRAPwfvcEsHUEUlLEKIbqtkCuPJMQFY5+ZXAgU7qhUnS2uAwYhs5AkP51sBgDMu1bFzdSoMEFOj5QrXvs5EDyQcFkC3IuEIej49AdneM= 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=MOcs7Nrb; arc=none smtp.client-ip=170.10.133.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="MOcs7Nrb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186250; 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=D3jXBvMO59PswYv8ZOap0e6qgARMkc/adUXKXvMftmQ=; b=MOcs7NrbQFTXQQ23/HsHW/u3PJYxyD4IpUwm7CcrZkYMryaUbnvPcsQ29IH6RZ247wsR4N QTf6/mCaNp7a42M49PZ7BYKZx79bfOTT7IKWYHIc0Xq7xRyyz+V46Upx9duaAT243JCD4c 0MCc6xadY7Ac2ae/n+bkYEEOEDFECRI= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-568-8En05Y8GNeuIRCIk4Cm67Q-1; Tue, 19 May 2026 06:24:02 -0400 X-MC-Unique: 8En05Y8GNeuIRCIk4Cm67Q-1 X-Mimecast-MFC-AGG-ID: 8En05Y8GNeuIRCIk4Cm67Q_1779186239 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 585C41956050; Tue, 19 May 2026 10:23:59 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 324C51800576; Tue, 19 May 2026 10:23:55 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 23/36] cifs: Clean up mid->callback_data and kill off mid->creator Date: Tue, 19 May 2026 11:21:41 +0100 Message-ID: <20260519102158.592165-24-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" We shouldn't really be pinning a task_struct on the mid_q_struct. Better to provide a wait queue there and have the waiter wait on it. For synchronous operations, this allows them to remove themselves from it once this is absorbed into smb_message and smb_message is generated higher up the stack. This also gets rid of one of the uses of mid->callback_data. We can also get rid of the need for callback_data for the Echo command callback by passing a server pointer down into ->callback() from the callers (all of which have it available). This can also be used in the Read and Write callbacks. We then only need the callback_data for the Read and Write commands - and in both cases, it points to a cifs_io_subrequest struct. So replace callback_data with a specifically typed pointer in a union that other users can be added to as the need arises. 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/cifs_debug.c | 3 +-- fs/smb/client/cifsglob.h | 11 ++++++++--- fs/smb/client/cifssmb.c | 7 ++----- fs/smb/client/smb1debug.c | 7 ++++--- fs/smb/client/smb2ops.c | 5 +++-- fs/smb/client/smb2pdu.c | 9 ++++----- fs/smb/client/smb2transport.c | 6 ------ fs/smb/client/transport.c | 7 +++---- 8 files changed, 25 insertions(+), 30 deletions(-) diff --git a/fs/smb/client/cifs_debug.c b/fs/smb/client/cifs_debug.c index 47dadab67440..0e3e790bbdbc 100644 --- a/fs/smb/client/cifs_debug.c +++ b/fs/smb/client/cifs_debug.c @@ -659,11 +659,10 @@ static int cifs_debug_data_proc_show(struct seq_file = *m, void *v) chan_server->conn_id); spin_lock(&chan_server->mid_queue_lock); list_for_each_entry(smb, &chan_server->pending_mid_q, qhead) { - seq_printf(m, "\n\t\tState: %d com: %d pid: %d cbdata: %p mid %llu", + seq_printf(m, "\n\t\tState: %d com: %d pid: %d mid %llu", smb->mid_state, le16_to_cpu(smb->command), smb->pid, - smb->callback_data, smb->mid); } spin_unlock(&chan_server->mid_queue_lock); diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 6b90f17ae0fa..3a2f684cede9 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1636,7 +1636,8 @@ static inline void cifs_stats_bytes_read(struct cifs_= tcon *tcon, * - it will be called by cifsd, with no locks held * - the mid will be removed from any lists */ -typedef void (*mid_callback_t)(struct TCP_Server_Info *srv, struct smb_mes= sage *smb); +typedef void (*mid_callback_t)(struct TCP_Server_Info *server, + struct smb_message *smb); =20 /* * Definition of an SMB request message to be transmitted. These may be @@ -1668,12 +1669,18 @@ struct smb_message { struct smb_message *next; /* Next message in compound */ struct cifs_credits credits; /* Credit requirements for this message */ void *request; /* Pointer to request message body */ + wait_queue_head_t waitq; /* Wait queue for message events */ refcount_t ref; unsigned int debug_id; /* Debugging ID for tracing */ bool sensitive; /* Request contains sensitive data */ bool cancelled; /* T if cancelled */ unsigned int sr_flags; /* Flags passed to send_recv() */ =20 + /* PDU-type specific data */ + union { + struct cifs_io_subrequest *subreq; /* Read/write subrequest */ + }; + /* Queue state */ struct list_head qhead; /* mids waiting on reply from this server */ __u64 mid; /* multiplex id */ @@ -1687,8 +1694,6 @@ struct smb_message { unsigned long when_received; /* when demux complete (taken off wire) */ #endif mid_callback_t callback; /* call completion callback */ - void *callback_data; /* general purpose pointer for callback */ - struct task_struct *creator; int mid_state; /* wish this were enum but can not pass to wait_event */ int mid_rc; /* rc for MID_RC */ unsigned int optype; /* operation type */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index ca6410e1f39e..e36828359f67 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -737,7 +737,6 @@ CIFSSMBEcho(struct TCP_Server_Info *server) smb->request =3D req; smb->total_len =3D in_len; smb->callback =3D cifs_echo_callback; - smb->callback_data =3D server; =20 rc =3D cifs_call_async(server, smb, CIFS_NON_BLOCKING | CIFS_ECHO_OP, NUL= L); if (rc) @@ -1428,7 +1427,7 @@ CIFS_open(const unsigned int xid, struct cifs_open_pa= rms *oparms, int *oplock, static void cifs_readv_callback(struct TCP_Server_Info *server, struct smb_message *sm= b) { - struct cifs_io_subrequest *rdata =3D smb->callback_data; + struct cifs_io_subrequest *rdata =3D smb->subreq; struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct inode *inode =3D &ictx->inode; @@ -1595,7 +1594,6 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) smb->request =3D req; smb->total_len =3D in_len; smb->callback =3D cifs_readv_callback; - smb->callback_data =3D rdata; smb->copy_to_bufs =3D true; =20 iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, @@ -1860,7 +1858,7 @@ CIFSSMBWrite(const unsigned int xid, struct cifs_io_p= arms *io_parms, static void cifs_writev_callback(struct TCP_Server_Info *server, struct smb_message *s= mb) { - struct cifs_io_subrequest *wdata =3D smb->callback_data; + struct cifs_io_subrequest *wdata =3D smb->subreq; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); WRITE_RSP *rsp =3D (WRITE_RSP *)smb->response; struct cifs_credits credits =3D { @@ -1975,7 +1973,6 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) smb->total_len =3D in_len + 1; smb->total_len +=3D wdata->subreq.len; smb->callback =3D cifs_writev_callback; - smb->callback_data =3D wdata; =20 iov_iter_bvec_queue(&smb->rqst.rq_iter, ITER_DEST, wdata->subreq.content.bvecq, wdata->subreq.content.slot, diff --git a/fs/smb/client/smb1debug.c b/fs/smb/client/smb1debug.c index 048fe6303bc1..6eb87852bce7 100644 --- a/fs/smb/client/smb1debug.c +++ b/fs/smb/client/smb1debug.c @@ -40,11 +40,12 @@ void cifs_dump_mids(struct TCP_Server_Info *server) .data_offset =3D smb->resp_data_offset, }; =20 - cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", + cifs_dbg(VFS, "State: %d Cmd: %x Pid: %d R=3D%x[%x] Mid %llu\n", smb->mid_state, - le16_to_cpu(smb->command), + le32_to_cpu(smb->command), smb->pid, - smb->callback_data, + smb->subreq ? smb->subreq->rreq->debug_id : 0, + smb->subreq ? smb->subreq->subreq.debug_index : 0, smb->mid); #ifdef CONFIG_CIFS_STATS2 cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index 0aaefe901fbd..b655c0f626f5 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -485,11 +485,12 @@ void smb2_dump_mids(struct TCP_Server_Info *server) .data_offset =3D smb->resp_data_offset, }; =20 - cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d Cbdata: %p Mid %llu\n", + cifs_dbg(VFS, "State: %d Cmd: %d Pid: %d R=3D%x[%x] Mid %llu\n", smb->mid_state, smb->command, smb->pid, - smb->callback_data, + smb->subreq ? smb->subreq->rreq->debug_id : 0, + smb->subreq ? smb->subreq->subreq.debug_index : 0, smb->mid); #ifdef CONFIG_CIFS_STATS2 cifs_dbg(VFS, "IsLarge: %d buf: %p time rcv: %ld now: %ld\n", diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 2a234df2fad5..f4ea7256b09d 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4386,7 +4386,6 @@ SMB2_echo(struct TCP_Server_Info *server) smb->request =3D req; smb->total_len =3D total_len; smb->callback =3D smb2_echo_callback; - smb->callback_data =3D server; =20 req->hdr.CreditRequest =3D cpu_to_le16(1); =20 @@ -4629,7 +4628,7 @@ smb2_new_read_req(void **buf, unsigned int *total_len, static void smb2_readv_callback(struct TCP_Server_Info *server, struct smb_message *sm= b) { - struct cifs_io_subrequest *rdata =3D smb->callback_data; + struct cifs_io_subrequest *rdata =3D smb->subreq; struct netfs_inode *ictx =3D netfs_inode(rdata->rreq->inode); struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); struct smb2_hdr *shdr =3D smb->response; @@ -4828,7 +4827,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) smb->request =3D buf; smb->total_len =3D total_len; smb->callback =3D smb2_readv_callback; - smb->callback_data =3D rdata; + smb->subreq =3D rdata; smb->copy_to_bufs =3D true; =20 iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, @@ -4981,7 +4980,7 @@ SMB2_read(const unsigned int xid, struct cifs_io_parm= s *io_parms, static void smb2_writev_callback(struct TCP_Server_Info *server, struct smb_message *s= mb) { - struct cifs_io_subrequest *wdata =3D smb->callback_data; + struct cifs_io_subrequest *wdata =3D smb->subreq; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); struct smb2_write_rsp *rsp =3D (struct smb2_write_rsp *)smb->response; struct cifs_credits credits =3D { @@ -5160,7 +5159,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) smb->request =3D req; smb->total_len =3D total_len; smb->callback =3D smb2_writev_callback; - smb->callback_data =3D wdata; + smb->subreq =3D wdata; =20 iov_iter_bvec_queue(&smb->rqst.rq_iter, ITER_SOURCE, wdata->subreq.content.bvecq, wdata->subreq.content.slot, diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 73db90ab8a52..14ee09b33f2c 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -611,12 +611,6 @@ static void smb2_init_mid(struct smb_message *smb, =20 smb->credits_consumed =3D credits > 0 ? credits : 1; =20 - /* - * The default is for the mid to be synchronous, so the - * default callback just wakes up the current task. - */ - smb->creator =3D get_task_struct(current); - atomic_inc(&mid_count); trace_smb3_cmd_enter(le32_to_cpu(shdr->Id.SyncId.TreeId), le64_to_cpu(shdr->SessionId), diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 0a7b2e7922cf..68536de2c1a0 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -53,8 +53,8 @@ struct smb_message *smb_message_alloc(enum smb_command_tr= ace cmd, gfp_t gfp) * callback just wakes up the current task. */ smb->callback =3D cifs_wake_up_task; - smb->callback_data =3D current; smb->mid_state =3D MID_REQUEST_ALLOCATED; + init_waitqueue_head(&smb->waitq); trace_smb3_message(smb->debug_id, 1, (enum smb_message_trace)cmd); } return smb; @@ -122,7 +122,7 @@ cifs_wake_up_task(struct TCP_Server_Info *server, struc= t smb_message *smb) if (smb->mid_state =3D=3D MID_RESPONSE_RECEIVED) smb->mid_state =3D MID_RESPONSE_READY; smb_see_message(smb, smb_message_trace_see_wake_up_task); - wake_up_process(smb->callback_data); + wake_up_all(&smb->waitq); } =20 static void smb_clear_mid(struct TCP_Server_Info *server, struct smb_messa= ge *smb) @@ -199,7 +199,6 @@ static void smb_clear_mid(struct TCP_Server_Info *serve= r, struct smb_message *sm } } #endif - put_task_struct(smb->creator); } =20 static bool discard_message(struct TCP_Server_Info *server, struct smb_mes= sage *smb) @@ -901,7 +900,7 @@ int wait_for_response(struct TCP_Server_Info *server, s= truct smb_message *smb) if (smb->sr_flags & CIFS_INTERRUPTIBLE_WAIT) sleep_state =3D TASK_INTERRUPTIBLE; =20 - error =3D wait_event_state(server->response_q, + error =3D wait_event_state(smb->waitq, smb->mid_state !=3D MID_REQUEST_SUBMITTED && smb->mid_state !=3D MID_RESPONSE_RECEIVED, (sleep_state | TASK_FREEZABLE_UNSAFE)); From nobody Mon May 25 02:42:24 2026 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 48BDD4C0403 for ; Tue, 19 May 2026 10:24:10 +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=1779186251; cv=none; b=X90m7KhtbSVhipbpGHPcXqZICVku7uhDx37n2dNTGV7pIEnq0cyJhcd8Ah3aszdGEHQgGOFwkWs/PzhdOYHHuq8C53Y3+OmUTYy9mXdOphp5tER1NzyHQnFYm0AZBYg8WlCoHohEbZaAHSl2pSR1TzfANBz+ny+G2ULmHp03wpc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186251; c=relaxed/simple; bh=FdgNKyW6lzbKD2kPjjyXosRj5wLQFDlas3Z4+GXEdqk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=now0RqCt+qoqCmlTBlpZINBF3/9MTa7VecxlqqgWhMr8ZSru6RYs0s1WXu1K1hYk3s9dfWfyJ711jeUNRvNgKoj2BMgD+TiHzWkJeNi91wfB6zrTpci25fcp8x70JTNhAgKEuMJIukoioOAgbSiCXfxZvUPK0HJkJRM+p5EMU7k= 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=MM7nqdhv; 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="MM7nqdhv" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186249; 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=/vW+QQqFnZMgqNlEPMjFKe16EaUDVQZXcnVGSR2eEmE=; b=MM7nqdhvAY1E22sG2rF3YG2iWuJQAMQd+x1H7z3TxZgc5fVrNw9C5jO5OrPCj/QNcWtLx3 8UXBvlFk7ica75XCilZcEqNvHwp1Fa4psjN9ihgkRXA7WDIiDvF1gkNB3XHHYOuR6Ytd9R WGsP8XEHwn8GtGHpHhUA1PF/14k/Q4o= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-627-97T95onpNLaO5p_Wu1xHzQ-1; Tue, 19 May 2026 06:24:05 -0400 X-MC-Unique: 97T95onpNLaO5p_Wu1xHzQ-1 X-Mimecast-MFC-AGG-ID: 97T95onpNLaO5p_Wu1xHzQ_1779186244 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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 308E41956060; Tue, 19 May 2026 10:24:04 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 0A12B1956053; Tue, 19 May 2026 10:24:00 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 24/36] cifs: Add netmem allocation functions Date: Tue, 19 May 2026 11:21:42 +0100 Message-ID: <20260519102158.592165-25-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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" Add (stub) functions for doing netmem allocations. We want to allocate memory from the netmem buffering as that does bulk DMA and IOMMU management. 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/cifsproto.h | 2 ++ fs/smb/client/transport.c | 20 ++++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 72ee5c5fd8b7..3067056f8ef9 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -508,5 +508,7 @@ int smb_rxqueue_refill(struct TCP_Server_Info *server, = struct netfs_rxqueue *rxq size_t min_size); int smb_rxqueue_consume(struct TCP_Server_Info *server, struct netfs_rxque= ue *rxq, size_t amount); +void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size); +void cifs_free_tx_buf(void *p); =20 #endif /* _CIFSPROTO_H */ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 68536de2c1a0..1599afb9e5cf 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -33,6 +33,26 @@ #include "smbdirect.h" #include "compress.h" =20 +/* + * Allocate transmission buffers for a socket. This memory will be alloca= ted + * from the netmem buffers. It comes with a page ref that we need to drop. + * The networking layer can pin it by getting its own ref. + */ +void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size) +{ + void *p; + + mutex_lock(&server->tx_alloc_lock); + p =3D page_frag_alloc_align(&server->tx_alloc, size, GFP_NOFS, 8); + mutex_unlock(&server->tx_alloc_lock); + return p; +} + +void cifs_free_tx_buf(void *p) +{ + page_frag_free(p); +} + struct smb_message *smb_message_alloc(enum smb_command_trace cmd, gfp_t gf= p) { static atomic_t debug_ids; From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 679024C041B for ; Tue, 19 May 2026 10:24:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186256; cv=none; b=Omb9jpOZIXYQ4FdLseBoKDR8w3JjHlpep5EBUHUr7ui6DUfKGVd2RsWCFIjaHZxju4RHGyOGj4ONLR/kvR+SgUlfvTw925U+bZN7XKi/MeCyfhjBy+m31iCFWHCLBDq3C5a16kgzr0rkGHMyZ0eXQaC08V2Vv2pIit2VYmaUbFI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186256; c=relaxed/simple; bh=f4WRxdG84N2etKy2a2qq15CIkzWzlT8hx2eMOULwSn0=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=hmKKI4QUUWnRcnXVYVWFD+h8nxbwnT2jew7ae/NXrl8PTqqE9lVLtfa2iHLKntm3DA+yeDD2DX3TcpjQ0psIBY0fuUqaC+vFdx54KJaXxNlvwa0GsLFZ2OBfWrxhj4QrpV8Dr4DlxS5DoTbvOad0uavCVCmfFu9P/7EqPSDqu4Y= 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=Zb/aR/8a; arc=none smtp.client-ip=170.10.133.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="Zb/aR/8a" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186252; 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=TRBRzV+xax35OqnhgX9Zi8VtyvNmu1xd2MyN2serIt0=; b=Zb/aR/8az58Dx4ZHfM7+UIEqhYaqO9cbRx9Yy39pT5wqyL1NvLSJseHPqeUu7cqjeumbxA pSSASe+qAAZaLKPWhA8r/Lr5SLxWZZHWVQy2wX702imMcm6Z8PrwRI8D3j6ggrNqZsAlSL 9M6AVJsUeM4eHqlO9e1ojPI3fOzoBxg= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-608-_Rg32EOZPjK8yVRB3LAadQ-1; Tue, 19 May 2026 06:24:11 -0400 X-MC-Unique: _Rg32EOZPjK8yVRB3LAadQ-1 X-Mimecast-MFC-AGG-ID: _Rg32EOZPjK8yVRB3LAadQ_1779186249 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 659AC1956053; Tue, 19 May 2026 10:24:09 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id DF9351800352; Tue, 19 May 2026 10:24:05 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 25/36] cifs: Add more pieces to smb_message Date: Tue, 19 May 2026 11:21:43 +0100 Message-ID: <20260519102158.592165-26-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 Content-Type: text/plain; charset="utf-8" Add more pieces to the smb_message struct to facilitate future changes. 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/cifsglob.h | 10 ++ fs/smb/client/cifsproto.h | 18 +++ fs/smb/client/smb2misc.c | 15 +++ fs/smb/client/smb2ops.c | 10 ++ fs/smb/client/smb2pdu.c | 202 ++++++++++++++++++++++++++++++++++ fs/smb/client/smb2proto.h | 1 + fs/smb/client/smb2transport.c | 122 ++++++++++++++------ fs/smb/client/transport.c | 89 +++++++++++---- 8 files changed, 413 insertions(+), 54 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 3a2f684cede9..9aa9eb72ec6b 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1672,6 +1672,7 @@ struct smb_message { wait_queue_head_t waitq; /* Wait queue for message events */ refcount_t ref; unsigned int debug_id; /* Debugging ID for tracing */ + bool new_style; /* New style request (not using ->rqst) */ bool sensitive; /* Request contains sensitive data */ bool cancelled; /* T if cancelled */ unsigned int sr_flags; /* Flags passed to send_recv() */ @@ -1711,7 +1712,13 @@ struct smb_message { u8 command_trace; /* enum smb_command_trace - Command trace ID */ __le16 command; /* smb command code */ s16 pre_offset; /* Offset of pre-headers from ->body (negative) */ + u16 ext_offset; /* Offset of extensions from ->body */ + u16 latest_record; /* Offset of latest context record (or 0) */ + u16 offset; /* Running offset during assembly */ + u16 data_offset; /* Offset of data in message (maybe in ->body) */ unsigned int total_len; /* Total length of from hdr_offset onwards */ + struct iov_iter data_iter; /* Data iterator */ + struct iov_iter req_iter; /* Request iterator */ /* Response */ //u32 response_pdu_len; /* Size of response PDU */ void *response; /* Protocol part of response */ @@ -1724,6 +1731,9 @@ struct smb_message { struct bvecq *response_data; /* Storage for response data (or NULL) */ /* Compat with old code */ struct smb_rqst rqst; + /* Variable-length request fragment list - must be last! */ + struct bvecq bvecq; /* List of request frags (passed to socket) */ + struct bio_vec __bvecq_bv[3]; }; =20 struct close_cancelled_open { diff --git a/fs/smb/client/cifsproto.h b/fs/smb/client/cifsproto.h index 3067056f8ef9..bbb59761fb9f 100644 --- a/fs/smb/client/cifsproto.h +++ b/fs/smb/client/cifsproto.h @@ -86,6 +86,7 @@ void smb_see_message(struct smb_message *smb, enum smb_me= ssage_trace trace); void smb_get_message(struct smb_message *smb, enum smb_message_trace trace= ); void smb_put_message(struct smb_message *smb, enum smb_message_trace trace= ); void smb_put_messages(struct smb_message *smb); +void smb_clear_request(struct smb_message *smb); void __release_mid(struct TCP_Server_Info *server, struct smb_message *smb= ); void cifs_wake_up_task(struct TCP_Server_Info *server, struct smb_message *smb); @@ -93,6 +94,9 @@ char *smb3_fs_context_fullpath(const struct smb3_fs_conte= xt *ctx, char dirsep); int smb3_parse_devname(const char *devname, struct smb3_fs_context *ctx); int cifs_ipaddr_cmp(struct sockaddr *srcaddr, struct sockaddr *rhs); bool cifs_match_ipaddr(struct sockaddr *srcaddr, struct sockaddr *rhs); +int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server, + struct smb_message *head_smb, const int flags); int cifs_call_async(struct TCP_Server_Info *server, struct smb_message *sm= b, const int flags, const struct cifs_credits *exist_credits); struct TCP_Server_Info *cifs_pick_channel(struct cifs_ses *ses); @@ -511,4 +515,18 @@ int smb_rxqueue_consume(struct TCP_Server_Info *server= , struct netfs_rxqueue *rx void *cifs_allocate_tx_buf(struct TCP_Server_Info *server, size_t size); void cifs_free_tx_buf(void *p); =20 +/* + * Add a segment to a message. This should be allocated with + * cifs_allocate_tx_buf() so that it can be used with MSG_SPLICE_PAGES. + */ +static inline void smb_add_segment_to_tx_buf(struct smb_message *smb, + void *buf, size_t size) +{ + unsigned int nr =3D smb->bvecq.nr_slots; + + bvec_set_virt(&smb->bvecq.bv[nr], buf, size); + smb->bvecq.nr_slots =3D nr + 1; + smb->total_len +=3D size; +} + #endif /* _CIFSPROTO_H */ diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index d28812107e8f..7c9dc3ede8b8 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -9,6 +9,7 @@ */ #include #include +#include #include "cifsglob.h" #include "cifsproto.h" #include "smb2proto.h" @@ -836,6 +837,15 @@ smb2_handle_cancelled_mid(struct smb_message *smb, str= uct TCP_Server_Info *serve return rc; } =20 +static size_t smb_sha512_step(void *iter_base, size_t progress, size_t len, + void *priv, void *priv2) +{ + struct sha512_ctx *ctx =3D priv; + + sha512_update(ctx, iter_base, len); + return 0; +} + /** * smb311_update_preauth_hash - update @ses hash from the message * @ses: server session structure @@ -878,6 +888,11 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struc= t TCP_Server_Info *server, =20 if (hash_resp) { sha512_update(&sha_ctx, smb->response, smb->resp_len); + } else if (smb->new_style) { + struct iov_iter tmp =3D smb->req_iter; + + iterate_and_advance_kernel(&tmp, smb->total_len, + &sha_ctx, NULL, smb_sha512_step); } else { struct kvec *iov =3D smb->rqst.rq_iov; =20 diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index b655c0f626f5..f9cefc47d084 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -2729,6 +2729,16 @@ smb2_set_replay(struct TCP_Server_Info *server, stru= ct smb_rqst *rqst) shdr->Flags |=3D SMB2_FLAGS_REPLAY_OPERATION; } =20 +void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_messag= e *smb) +{ + struct smb2_hdr *shdr =3D smb->request; + + if (server->dialect < SMB30_PROT_ID) + return; + + shdr->Flags |=3D SMB2_FLAGS_REPLAY_OPERATION; +} + void smb2_set_related(struct smb_rqst *rqst) { diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index f4ea7256b09d..f907ee4faa3a 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -91,6 +91,208 @@ int smb3_encryption_required(const struct cifs_tcon *tc= on) return 0; } =20 +static void smb2_enc_header(struct smb_message *smb, + const struct cifs_tcon *tcon, + struct TCP_Server_Info *server) +{ + struct smb2_hdr *shdr =3D smb->request; + struct smb3_hdr_req *smb3_hdr =3D (struct smb3_hdr_req *)shdr; + + shdr->ProtocolId =3D SMB2_PROTO_NUMBER; + shdr->StructureSize =3D cpu_to_le16(64); + shdr->CreditCharge =3D 0; + shdr->Status =3D 0; /* ChanSeq for smb3 */ + shdr->Command =3D smb->command; + shdr->CreditRequest =3D cpu_to_le16(2); + shdr->Flags =3D 0; + shdr->NextCommand =3D 0; + shdr->MessageId =3D 0; + shdr->Id.SyncId.ProcessId =3D cpu_to_le32((__u16)current->tgid); + shdr->SessionId =3D 0; + + if (server) { + /* After reconnect SMB3 must set ChannelSequence on subsequent reqs */ + if (server->dialect >=3D SMB30_PROT_ID) { + /* + * if primary channel is not set yet, use default + * channel for chan sequence num + */ + if (SERVER_IS_CHAN(server)) + smb3_hdr->ChannelSequence =3D + cpu_to_le16(server->primary_server->channel_sequence_num); + else + smb3_hdr->ChannelSequence =3D + cpu_to_le16(server->channel_sequence_num); + } + spin_lock(&server->req_lock); + /* Request up to 10 credits but don't go over the limit. */ + if (server->credits >=3D server->max_credits) + shdr->CreditRequest =3D cpu_to_le16(0); + else + shdr->CreditRequest =3D cpu_to_le16( + min_t(int, server->max_credits - + server->credits, 10)); + spin_unlock(&server->req_lock); + } + + if (tcon) { + /* GLOBAL_CAP_LARGE_MTU will only be set if dialect > SMB2.02 */ + /* See sections 2.2.4 and 3.2.4.1.5 of MS-SMB2 */ + if (server && (server->capabilities & SMB2_GLOBAL_CAP_LARGE_MTU)) + shdr->CreditCharge =3D cpu_to_le16(1); + /* else CreditCharge MBZ */ + + shdr->Id.SyncId.TreeId =3D cpu_to_le32(tcon->tid); + /* Uid is not converted */ + if (tcon->ses) + shdr->SessionId =3D cpu_to_le64(tcon->ses->Suid); + + /* + * If we would set SMB2_FLAGS_DFS_OPERATIONS on open we also + * would have to pass the path on the Open SMB prefixed by + * \\server\share. Not sure when we would need to do the + * augmented path (if ever) and setting this flag breaks the + * SMB2 open operation since it is illegal to send an empty + * path name (without \\server\share prefix) when the DFS flag + * is set in the SMB open header. We could consider setting the + * flag on all operations other than open but it is safer to + * net set it for now. + */ +/* if (tcon->share_flags & SHI1005_FLAGS_DFS) + shdr->Flags |=3D SMB2_FLAGS_DFS_OPERATIONS; */ + + if (server && server->sign && !smb3_encryption_required(tcon)) + shdr->Flags |=3D SMB2_FLAGS_SIGNED; + } +} + +/* Flags for smb2_create_request() */ +#define SMB2_REQ_DYNAMIC 0x01 /* Dynamic request */ +#define SMB2_REQ_HEAD 0x02 /* Head of compound */ +#define SMB2_REQ_SENSITIVE 0x04 /* May contain sensitive crypto data */ + +/* + * smb2_create_request: Allocate and set up a request + * @command: The command type we're going to issue + * @server: The server the command is going to go to + * @header_size: The size of the base protocol structure + * @protocol_size: The size of the header plus extensions + * @data_size: The size of the data payload + * @head: If this is the head of a compound + * @flags: Mask of SMB2_REQ_* flags + * + * Create a request and allocate netmem memory to hold the netbios header = (if + * appropriate) and the protocol part of the message. Memory will also be + * allocated for the data part of the message if this is to be encrypted b= y the + * CPU. The allocated buffers will be attached to a bvec-queue struct so = that + * they can be chained together and passed to the socket. + */ +static struct smb_message *smb2_create_request(__le16 command, + struct TCP_Server_Info *server, + struct cifs_tcon *tcon, + size_t header_size, + size_t protocol_size, + size_t data_size, + unsigned int flags) +{ + struct smb_message *smb; + const size_t max_slots =3D ARRAY_SIZE(smb->__bvecq_bv); // Preallocated s= lots + size_t pre_size; + void *body; + bool encrypted =3D false; //, rdma =3D false; + u16 ssize; + + smb =3D smb_message_alloc(command, GFP_NOFS); + if (!smb) + return NULL; + + smb->new_style =3D true; /* I.e. we're not using smb->rqst. */ + smb->command =3D command; + smb->command_trace =3D command; + smb->sensitive =3D flags & SMB2_REQ_SENSITIVE; + + /* We allocate space for inter-SMB padding or rfc1002 header plus + * transform headers (as needed), but don't add them in at this time. + */ + pre_size =3D 8; + if (encrypted) + pre_size +=3D sizeof(struct smb2_transform_hdr); + smb->pre_offset =3D -pre_size; + + if (encrypted) + /* We want the encrypted blob to be correctly aligned. */ + pre_size =3D round_up(pre_size, 16); + + /* Allocate space for the SMB header, the request struct (both in + * header_size) plus any extension bits, bearing in mind that some bits + * may follow the header directly (header_added_size) and some may have + * to be padded to an 8-byte alignment first (extension_size). The + * Negotiate Request has both. + */ + smb->ext_offset =3D header_size; + smb->offset =3D header_size; + smb->data_offset =3D protocol_size; + smb->total_len =3D data_size; + + body =3D cifs_allocate_tx_buf(server, pre_size + protocol_size); + if (!body) { + kfree(smb); + return NULL; + } + + smb->bvecq.max_slots =3D max_slots; + smb_add_segment_to_tx_buf(smb, body + pre_size, protocol_size); + smb->request =3D body + pre_size; + + struct smb2_pdu *spdu =3D smb->request; + memset(spdu, 0, header_size); + + smb2_enc_header(smb, tcon, server); + ssize =3D header_size - sizeof(spdu->hdr); + if (flags & SMB2_REQ_DYNAMIC) + ssize |=3D SMB2_STRUCT_HAS_DYNAMIC_PART; + spdu->StructureSize2 =3D cpu_to_le16(ssize); + + if (tcon) { + cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_sent[command]); + cifs_stats_inc(&tcon->num_smbs_sent); + } + +#if 0 + /* Include the buffer from the start of the RFC1002 header in the + * iterator, but may need to adjust it later. + */ + iov_iter_bvec_queue(&smb->iter, ITER_SOURCE, &smb->bvecq, 0, + pre_size, protocol_size); +#endif + return smb; +} + +static void cifs_pad_to_8(struct smb_message *smb) +{ + size_t offset =3D smb->offset; + u8 *p =3D smb->request; + + while (offset & 7) + p[offset++] =3D 0; + smb->offset =3D offset; +} + +/* + * Begin adding an extension to a message. The offset is padded to an 8-b= yte + * alignment; + */ +static void *cifs_begin_extension(struct smb_message *smb) +{ + cifs_pad_to_8(smb); + return smb->request + smb->offset; +} + +static void cifs_end_extension(struct smb_message *smb, size_t size) +{ + smb->offset +=3D size; +} + static void smb2_hdr_assemble(struct smb2_hdr *shdr, __le16 smb2_cmd, const struct cifs_tcon *tcon, diff --git a/fs/smb/client/smb2proto.h b/fs/smb/client/smb2proto.h index bac01d15b94a..6571a6a7b147 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -121,6 +121,7 @@ unsigned long smb_rqst_len(struct TCP_Server_Info *serv= er, void smb2_set_next_command(struct cifs_tcon *tcon, struct smb_rqst *rqst); void smb2_set_related(struct smb_rqst *rqst); void smb2_set_replay(struct TCP_Server_Info *server, struct smb_rqst *rqst= ); +void smb2_set_replay_smb(struct TCP_Server_Info *server, struct smb_messag= e *smb); bool smb2_should_replay(struct cifs_tcon *tcon, int *pretries, int *pcur_sleep); void smb2_add_credits_from_hdr(struct smb2_hdr *shdr, diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index 14ee09b33f2c..f63eaff4935a 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -207,16 +207,24 @@ smb2_find_smb_tcon(struct TCP_Server_Info *server, __= u64 ses_id, __u32 tid) return tcon; } =20 +static inline size_t smb2_hmac_sha256_step(void *iter_base, size_t progres= s, + size_t len, void *priv, void *priv2) +{ + struct hmac_sha256_ctx *hmac_ctx =3D priv; + + hmac_sha256_update(hmac_ctx, iter_base, len); + return 0; +} + static int smb2_calc_signature(struct smb_message *smb, struct TCP_Server_Info *serve= r, bool for_recv) { int rc; unsigned char smb2_signature[SMB2_HMACSHA256_SIZE]; - struct kvec *iov =3D smb->rqst.rq_iov; struct smb2_hdr *shdr =3D for_recv ? smb->response : smb->request; struct hmac_sha256_ctx hmac_ctx; - struct smb_rqst drqst; + size_t size, did; __u64 sid =3D le64_to_cpu(shdr->SessionId); u8 key[SMB2_NTLMV2_SESSKEY_SIZE]; =20 @@ -232,27 +240,32 @@ smb2_calc_signature(struct smb_message *smb, struct T= CP_Server_Info *server, =20 hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key)); =20 - /* - * For SMB2+, __cifs_calc_signature() expects to sign only the actual - * data, that is, iov[0] should not contain a rfc1002 length. - * - * Sign the rfc1002 length prior to passing the data (iov[1-N]) down to - * __cifs_calc_signature(). - */ - drqst =3D smb->rqst; - if (drqst.rq_nvec >=3D 2 && iov[0].iov_len =3D=3D 4) { - hmac_sha256_update(&hmac_ctx, iov[0].iov_base, iov[0].iov_len); - drqst.rq_iov++; - drqst.rq_nvec--; + if (smb->new_style) { + struct iov_iter req_iter =3D smb->req_iter; + + size =3D iov_iter_count(&req_iter); + did =3D iterate_and_advance_kernel(&req_iter, size, &hmac_ctx, NULL, + smb2_hmac_sha256_step); + if (did !=3D size) + return smb_EIO2(smb_eio_trace_sig_iter, did, size); + } else { + for (int i =3D 0; i < smb->rqst.rq_nvec; i++) + hmac_sha256_update(&hmac_ctx, + smb->rqst.rq_iov[i].iov_base, + smb->rqst.rq_iov[i].iov_len); } =20 - rc =3D __cifs_calc_signature( - &drqst, server, smb2_signature, - &(struct cifs_calc_sig_ctx){ .hmac =3D &hmac_ctx }); - if (!rc) - memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE); + struct iov_iter data_iter =3D smb->data_iter; =20 - return rc; + size =3D iov_iter_count(&data_iter); + did =3D iterate_and_advance_kernel(&data_iter, size, &hmac_ctx, NULL, + smb2_hmac_sha256_step); + if (did !=3D size) + return smb_EIO2(smb_eio_trace_sig_iter, did, size); + + hmac_sha256_final(&hmac_ctx, smb2_signature); + memcpy(shdr->Signature, smb2_signature, SMB2_SIGNATURE_SIZE); + return 0; } =20 static void generate_key(struct cifs_ses *ses, struct kvec label, @@ -460,17 +473,25 @@ generate_smb311signingkey(struct cifs_ses *ses, return generate_smb3signingkey(ses, server, &triplet); } =20 +static inline size_t smb3_aes_cmac_step(void *iter_base, size_t progress, + size_t len, void *priv, void *priv2) +{ + struct aes_cmac_ctx *cmac_ctx =3D priv; + + aes_cmac_update(cmac_ctx, iter_base, len); + return 0; +} + static int smb3_calc_signature(struct smb_message *smb, struct TCP_Server_Info *serve= r, bool for_recv) { int rc; unsigned char smb3_signature[SMB2_CMACAES_SIZE]; - struct kvec kv; struct smb2_hdr *shdr =3D for_recv ? smb->response : smb->request; struct aes_cmac_key cmac_key; struct aes_cmac_ctx cmac_ctx; - struct smb_rqst drqst; + size_t size, did; u8 key[SMB3_SIGN_KEY_SIZE]; =20 if (server->vals->protocol_id <=3D SMB21_PROT_ID) @@ -494,22 +515,55 @@ smb3_calc_signature(struct smb_message *smb, struct T= CP_Server_Info *server, aes_cmac_init(&cmac_ctx, &cmac_key); =20 if (for_recv) { - kv.iov_base =3D smb->response; - kv.iov_len =3D smb->resp_len; - drqst.rq_nvec =3D 1; - drqst.rq_iov =3D &kv; - drqst.rq_iter =3D smb->response_iter; - iov_iter_truncate(&drqst.rq_iter, smb->resp_data_len); + struct iov_iter resp_iter =3D smb->response_iter; + + size =3D smb->resp_len; + did =3D 0; + + aes_cmac_update(&cmac_ctx, smb->response, size); + rc =3D -EIO; + size =3D iov_iter_count(&resp_iter); + did =3D iterate_and_advance_kernel(&resp_iter, size, &cmac_ctx, + NULL, smb3_aes_cmac_step); + if (did !=3D size) + goto eio; } else { - drqst =3D smb->rqst; + if (smb->new_style) { + struct iov_iter req_iter =3D smb->req_iter; + + size =3D iov_iter_count(&req_iter); + did =3D iterate_and_advance_kernel(&req_iter, size, + &cmac_ctx, NULL, + smb3_aes_cmac_step); + if (did !=3D size) + goto eio; + } else { + for (int i =3D 0; i < smb->rqst.rq_nvec; i++) { + size =3D smb->rqst.rq_iov[i].iov_len; + aes_cmac_update(&cmac_ctx, + smb->rqst.rq_iov[i].iov_base, + size); + } + } + + struct iov_iter data_iter =3D smb->data_iter; + + size =3D iov_iter_count(&data_iter); + did =3D iterate_and_advance_kernel(&data_iter, size, &cmac_ctx, + NULL, smb3_aes_cmac_step); + if (did !=3D size) + return smb_EIO2(smb_eio_trace_sig_iter, did, size); } =20 - rc =3D __cifs_calc_signature( - &drqst, server, smb3_signature, - &(struct cifs_calc_sig_ctx){ .cmac =3D &cmac_ctx }); - if (!rc) - memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE); + aes_cmac_final(&cmac_ctx, smb3_signature); + + memcpy(shdr->Signature, smb3_signature, SMB2_SIGNATURE_SIZE); + rc =3D 0; +out: return rc; +eio: + smb_EIO2(smb_eio_trace_sig_iter, did, size); + goto out; } =20 /* must be called with server->srv_mutex held */ diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 1599afb9e5cf..212894c8d2bd 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -67,6 +67,7 @@ struct smb_message *smb_message_alloc(enum smb_command_tr= ace cmd, gfp_t gfp) smb->command_trace =3D cmd; smb->when_alloc =3D jiffies; smb->pid =3D current->pid; + smb->bvecq.bv =3D smb->__bvecq_bv; =20 /* * The default is for the mid to be synchronous, so the default @@ -97,9 +98,26 @@ static void smb_free_message(struct smb_message *smb) { trace_smb3_message(smb->debug_id, refcount_read(&smb->ref), smb_message_trace_free); + if (smb->new_style) + cifs_free_tx_buf(smb->request + smb->pre_offset); mempool_free(smb, &smb_message_pool); } =20 +/* + * Clear the request parts of a message. + */ +void smb_clear_request(struct smb_message *smb) +{ + for (; smb; smb =3D smb->next) { + if (smb->request) { + if (smb->sensitive) + memzero_explicit(smb->request, smb->data_offset); + cifs_free_tx_buf(smb->request); + smb->request =3D NULL; + } + } +} + /* * Drop a ref on a message. This does not touch the chained messages. */ @@ -123,6 +141,8 @@ void smb_put_messages(struct smb_message *smb) { struct smb_message *next; =20 + smb_clear_request(smb); + for (; smb; smb =3D next) { unsigned int debug_id =3D smb->debug_id; bool dead; @@ -561,8 +581,7 @@ static int smb_copy_data_into_buffer(struct TCP_Server_= Info *server, iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); =20 for (smb =3D head_smb; smb; smb =3D smb->next) { - size_t size =3D iov_iter_count(&smb->rqst.rq_iter); - size_t got; + size_t size, got; =20 if (offset & 7) { unsigned int tmp =3D offset; @@ -570,25 +589,54 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, iov_iter_zero(offset - tmp, iter); } =20 - for (int i =3D 0; i < smb->rqst.rq_nvec; i++) { - size_t len =3D smb->rqst.rq_iov[i].iov_len; - got =3D copy_to_iter(smb->rqst.rq_iov[i].iov_base, len, iter); - if (got !=3D len) { - rc =3D smb_EIO2(smb_eio_trace_tx_copy_to_buf, got, size); + if (smb->new_style) { + struct iov_iter req_iter =3D smb->req_iter; + + size =3D iov_iter_count(&req_iter); + got =3D iterate_and_advance_kernel(&req_iter, + size, iter, NULL, + smb3_copy_data_iter); + if (got !=3D size) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); goto error; } - offset +=3D len; - } + offset +=3D size; =20 - got =3D iterate_and_advance_kernel(&smb->rqst.rq_iter, - size, iter, NULL, - smb3_copy_data_iter); - if (got !=3D size) { - rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); - goto error; - } + struct iov_iter data_iter =3D smb->data_iter; =20 - offset +=3D size; + size =3D iov_iter_count(&data_iter); + got =3D iterate_and_advance_kernel(&data_iter, + size, iter, NULL, + smb3_copy_data_iter); + if (got !=3D size) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); + goto error; + } + offset +=3D size; + } else { + /* Old-style with an rqst. */ + size =3D iov_iter_count(&smb->rqst.rq_iter); + + for (int i =3D 0; i < smb->rqst.rq_nvec; i++) { + size_t len =3D smb->rqst.rq_iov[i].iov_len; + got =3D copy_to_iter(smb->rqst.rq_iov[i].iov_base, + len, iter); + if (got !=3D len) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_to_buf, got, size); + goto error; + } + offset +=3D len; + } + + got =3D iterate_and_advance_kernel(&smb->rqst.rq_iter, + size, iter, NULL, + smb3_copy_data_iter); + if (got !=3D size) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); + goto error; + } + offset +=3D size; + } } =20 if (WARN_ONCE(offset !=3D total_len, @@ -1139,9 +1187,9 @@ struct TCP_Server_Info *cifs_pick_channel(struct cifs= _ses *ses) /* * Send a single message or a string of messages as a compound. */ -static int smb_send_recv_messages(const unsigned int xid, struct cifs_ses = *ses, - struct TCP_Server_Info *server, - struct smb_message *head_smb, const int flags) +int smb_send_recv_messages(const unsigned int xid, struct cifs_ses *ses, + struct TCP_Server_Info *server, + struct smb_message *head_smb, const int flags) { unsigned int instance; int nr_reqs, i, optype, rc =3D 0; @@ -1384,6 +1432,7 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, smb->request =3D request; smb->rqst =3D *rq; smb->sr_flags =3D flags; + smb->data_iter =3D rq->rq_iter; =20 if (is_smb1(server)) { smb->command =3D 0; From nobody Mon May 25 02:42:24 2026 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 4298D4E3766 for ; Tue, 19 May 2026 10:24:20 +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=1779186262; cv=none; b=uf8kxDLlMHk3TXE1kfYTTW5y8m2dlGtS+zIjHFaS++mjftTr+PwFZR05kcuR0gLzeEMgDUujOYifne5wGlWjWDcfaYNGJUwK/+XAL7wSfQxQwGM8m69r7yWKEuEKlwOk3db23r0/iWSwygWIl7JkSz7D0yE2uMRlhz+mwDYLM0w= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186262; c=relaxed/simple; bh=H6kla4VLl7yMi07Jc/XRQGXhi1fMX7L65B/Mtpah+/U=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=sfrFVFE51CuXERR63HLxgsLVNLjugyp/iR/JeSfQFDGIm0pJmZ4gLcDY+IRbZlmhGWVbENWhYq0LL9nrKn8F4VNDmRAJQgq6L5bpmt/ew6bydMhBkfsZCdbgUewN6pFBafx3pGP6LSKQcHGwzqlF4ey8i8tLO/pF4pdDLAERp0g= 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=ZWXm8f2E; 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="ZWXm8f2E" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186259; 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=K7nfvFwOIfNiLfqP5Z8DcxxoUTnadliouKIJXQNcBCY=; b=ZWXm8f2ExQadhEUaIFEtw24Elm2appgO/siFCgN5djCntNmaS4+AAHktZXF+51QU5asBnR nKELqOdVyKF1vpGMgbnYLiRLnrQSktY/6tngpR2cdjxnqXJUFNYwyBZn1zYLnEEFb57DZW ywy4ysEaOiCfsT6DvI7fyEv/5Xc/wSc= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-121-qc4e03XGPWeVBbCeSE9m_Q-1; Tue, 19 May 2026 06:24:16 -0400 X-MC-Unique: qc4e03XGPWeVBbCeSE9m_Q-1 X-Mimecast-MFC-AGG-ID: qc4e03XGPWeVBbCeSE9m_Q_1779186254 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 781051956096; Tue, 19 May 2026 10:24:14 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 10B8519560A2; Tue, 19 May 2026 10:24:10 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 26/36] cifs: Convert SMB2 Negotiate Protocol request Date: Tue, 19 May 2026 11:21:44 +0100 Message-ID: <20260519102158.592165-27-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.12 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/smb2pdu.c | 497 +++++++++++++++++++++++----------------- fs/smb/common/smb2pdu.h | 24 +- fs/smb/server/smb2pdu.c | 22 +- 3 files changed, 310 insertions(+), 233 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index f907ee4faa3a..193dca577fa1 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -825,144 +825,203 @@ static int smb2_ioctl_req_init(u32 opcode, struct c= ifs_tcon *tcon, =20 /* For explanation of negotiate contexts see MS-SMB2 section 2.2.3.1 */ =20 -static void -build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt) +static void *cifs_begin_neg_context(struct smb_message *smb, + __le16 context_type) { - pneg_ctxt->ContextType =3D SMB2_PREAUTH_INTEGRITY_CAPABILITIES; - pneg_ctxt->DataLength =3D cpu_to_le16(38); - pneg_ctxt->HashAlgorithmCount =3D cpu_to_le16(1); - pneg_ctxt->SaltLength =3D cpu_to_le16(SMB311_SALT_SIZE); - get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE); - pneg_ctxt->HashAlgorithms =3D SMB2_PREAUTH_INTEGRITY_SHA512; + struct smb2_neg_context *neg; + + neg =3D cifs_begin_extension(smb); + neg->ContextType =3D context_type; + neg->Reserved =3D 0; + return (void *)neg; } =20 -static void -build_compression_ctxt(struct smb2_compression_capabilities_context *pneg_= ctxt) +static void cifs_end_neg_context(struct smb_message *smb, void *p, size_t = size) { - pneg_ctxt->ContextType =3D SMB2_COMPRESSION_CAPABILITIES; - pneg_ctxt->DataLength =3D - cpu_to_le16(sizeof(struct smb2_compression_capabilities_context) - - sizeof(struct smb2_neg_context)); - pneg_ctxt->CompressionAlgorithmCount =3D cpu_to_le16(3); - pneg_ctxt->CompressionAlgorithms[0] =3D SMB3_COMPRESS_LZ77; - pneg_ctxt->CompressionAlgorithms[1] =3D SMB3_COMPRESS_LZ77_HUFF; - pneg_ctxt->CompressionAlgorithms[2] =3D SMB3_COMPRESS_LZNT1; + struct smb2_neg_context *neg =3D p; + + neg->DataLength =3D cpu_to_le16(size - sizeof(*neg)); + cifs_end_extension(smb, size); } =20 -static unsigned int -build_signing_ctxt(struct smb2_signing_capabilities *pneg_ctxt) +static void build_preauth_ctxt(struct smb_message *smb) +{ + struct smb2_preauth_neg_context *preauth; + + preauth =3D cifs_begin_neg_context(smb, SMB2_PREAUTH_INTEGRITY_CAPABILITI= ES); + preauth->HashAlgorithmCount =3D cpu_to_le16(1); + preauth->SaltLength =3D cpu_to_le16(SMB311_SALT_SIZE); + preauth->HashAlgorithms =3D SMB2_PREAUTH_INTEGRITY_SHA512; + get_random_bytes(preauth->Salt, SMB311_SALT_SIZE); + cifs_end_neg_context(smb, preauth, sizeof(*preauth)); +} + +static void build_compression_ctxt(struct smb_message *smb) +{ + struct smb2_compression_capabilities_context *compr; + + compr =3D cifs_begin_neg_context(smb, SMB2_COMPRESSION_CAPABILITIES); + compr->CompressionAlgorithmCount =3D cpu_to_le16(3); + compr->CompressionAlgorithms[0] =3D SMB3_COMPRESS_LZ77; + compr->CompressionAlgorithms[1] =3D SMB3_COMPRESS_LZ77_HUFF; + compr->CompressionAlgorithms[2] =3D SMB3_COMPRESS_LZNT1; + cifs_end_neg_context(smb, compr, sizeof(*compr)); +} + +static size_t smb2_size_signing_ctxt(void) +{ + size_t ctxt_len =3D sizeof(struct smb2_signing_capabilities); + unsigned short num_algs =3D 1; /* number of signing algorithms sent */ + + ctxt_len +=3D sizeof(__le16) * num_algs; + return ALIGN8(ctxt_len); +} + +static void build_signing_ctxt(struct smb_message *smb) { - unsigned int ctxt_len =3D sizeof(struct smb2_signing_capabilities); + struct smb2_signing_capabilities *scap; unsigned short num_algs =3D 1; /* number of signing algorithms sent */ =20 - pneg_ctxt->ContextType =3D SMB2_SIGNING_CAPABILITIES; + scap =3D cifs_begin_neg_context(smb, SMB2_SIGNING_CAPABILITIES); + scap->SigningAlgorithmCount =3D cpu_to_le16(num_algs); + scap->SigningAlgorithms[0] =3D cpu_to_le16(SIGNING_ALG_AES_CMAC); + /* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */ + /* * Context Data length must be rounded to multiple of 8 for some servers */ - pneg_ctxt->DataLength =3D cpu_to_le16(ALIGN8(sizeof(struct smb2_signing_c= apabilities) - - sizeof(struct smb2_neg_context) + - (num_algs * sizeof(u16)))); - pneg_ctxt->SigningAlgorithmCount =3D cpu_to_le16(num_algs); - pneg_ctxt->SigningAlgorithms[0] =3D cpu_to_le16(SIGNING_ALG_AES_CMAC); - - ctxt_len +=3D sizeof(__le16) * num_algs; - ctxt_len =3D ALIGN8(ctxt_len); - return ctxt_len; - /* TBD add SIGNING_ALG_AES_GMAC and/or SIGNING_ALG_HMAC_SHA256 */ + cifs_end_neg_context(smb, scap, + ALIGN8(struct_size(scap, SigningAlgorithms, num_algs))); } =20 -static void -build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ctxt) +static void build_encrypt_ctxt(struct smb_message *smb) { - pneg_ctxt->ContextType =3D SMB2_ENCRYPTION_CAPABILITIES; - if (require_gcm_256) { - pneg_ctxt->DataLength =3D cpu_to_le16(4); /* Cipher Count + 1 cipher */ - pneg_ctxt->CipherCount =3D cpu_to_le16(1); - pneg_ctxt->Ciphers[0] =3D SMB2_ENCRYPTION_AES256_GCM; - } else if (enable_gcm_256) { - pneg_ctxt->DataLength =3D cpu_to_le16(8); /* Cipher Count + 3 ciphers */ - pneg_ctxt->CipherCount =3D cpu_to_le16(3); - pneg_ctxt->Ciphers[0] =3D SMB2_ENCRYPTION_AES128_GCM; - pneg_ctxt->Ciphers[1] =3D SMB2_ENCRYPTION_AES256_GCM; - pneg_ctxt->Ciphers[2] =3D SMB2_ENCRYPTION_AES128_CCM; + struct smb2_encryption_neg_context *ecap; + size_t count; + + ecap =3D cifs_begin_neg_context(smb, SMB2_ENCRYPTION_CAPABILITIES); + + if (READ_ONCE(require_gcm_256)) { + ecap->Ciphers[0] =3D SMB2_ENCRYPTION_AES256_GCM; + count =3D 1; + } else if (READ_ONCE(enable_gcm_256)) { + ecap->Ciphers[0] =3D SMB2_ENCRYPTION_AES128_GCM; + ecap->Ciphers[1] =3D SMB2_ENCRYPTION_AES256_GCM; + ecap->Ciphers[2] =3D SMB2_ENCRYPTION_AES128_CCM; + count =3D 3; } else { - pneg_ctxt->DataLength =3D cpu_to_le16(6); /* Cipher Count + 2 ciphers */ - pneg_ctxt->CipherCount =3D cpu_to_le16(2); - pneg_ctxt->Ciphers[0] =3D SMB2_ENCRYPTION_AES128_GCM; - pneg_ctxt->Ciphers[1] =3D SMB2_ENCRYPTION_AES128_CCM; + ecap->Ciphers[0] =3D SMB2_ENCRYPTION_AES128_GCM; + ecap->Ciphers[1] =3D SMB2_ENCRYPTION_AES128_CCM; + count =3D 2; } + ecap->CipherCount =3D cpu_to_le16(count); + cifs_end_neg_context(smb, ecap, struct_size(ecap, Ciphers, count)); } =20 -static unsigned int -build_netname_ctxt(struct smb2_netname_neg_context *pneg_ctxt, char *hostn= ame) +static size_t smb2_size_netname_ctxt(struct TCP_Server_Info *server) { + size_t data_len; + +#if 0 struct nls_table *cp =3D load_nls_default(); + const char *hostname; =20 - pneg_ctxt->ContextType =3D SMB2_NETNAME_NEGOTIATE_CONTEXT_ID; + /* Only include up to first 100 bytes of server name in the NetName + * field. + */ + cifs_server_lock(pserver); + hostname =3D pserver->hostname; + if (hostname && hostname[0]) + data_len =3D cifs_size_strtoUTF16(hostname, 100, cp); + cifs_server_unlock(pserver); +#else + /* Now, we can't just measure the length of hostname as, unless we hold + * the lock, it may change under us, so allow maximum space for it. + */ + data_len =3D 400; +#endif + return ALIGN8(sizeof(struct smb2_neg_context) + data_len); +} + +static void build_netname_ctxt(struct smb_message *smb, const char *hostna= me) +{ + struct smb2_netname_neg_context *name; + struct nls_table *cp =3D load_nls_default(); + size_t count; + + name =3D cifs_begin_neg_context(smb, SMB2_NETNAME_NEGOTIATE_CONTEXT_ID); =20 /* copy up to max of first 100 bytes of server name to NetName field */ - pneg_ctxt->DataLength =3D cpu_to_le16(2 * cifs_strtoUTF16(pneg_ctxt->NetN= ame, hostname, 100, cp)); - /* context size is DataLength + minimal smb2_neg_context */ - return ALIGN8(le16_to_cpu(pneg_ctxt->DataLength) + sizeof(struct smb2_neg= _context)); + count =3D cifs_strtoUTF16(name->NetName, hostname, 100, cp); + cifs_end_neg_context(smb, name, struct_size(name, NetName, count)); } =20 -static void -build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) +static void build_posix_ctxt(struct smb_message *smb) { - pneg_ctxt->ContextType =3D SMB2_POSIX_EXTENSIONS_AVAILABLE; - pneg_ctxt->DataLength =3D cpu_to_le16(POSIX_CTXT_DATA_LEN); + struct smb2_posix_neg_context *posix; + + posix =3D cifs_begin_neg_context(smb, SMB2_POSIX_EXTENSIONS_AVAILABLE); /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ - pneg_ctxt->Name[0] =3D 0x93; - pneg_ctxt->Name[1] =3D 0xAD; - pneg_ctxt->Name[2] =3D 0x25; - pneg_ctxt->Name[3] =3D 0x50; - pneg_ctxt->Name[4] =3D 0x9C; - pneg_ctxt->Name[5] =3D 0xB4; - pneg_ctxt->Name[6] =3D 0x11; - pneg_ctxt->Name[7] =3D 0xE7; - pneg_ctxt->Name[8] =3D 0xB4; - pneg_ctxt->Name[9] =3D 0x23; - pneg_ctxt->Name[10] =3D 0x83; - pneg_ctxt->Name[11] =3D 0xDE; - pneg_ctxt->Name[12] =3D 0x96; - pneg_ctxt->Name[13] =3D 0x8B; - pneg_ctxt->Name[14] =3D 0xCD; - pneg_ctxt->Name[15] =3D 0x7C; + posix->Name[0] =3D 0x93; + posix->Name[1] =3D 0xAD; + posix->Name[2] =3D 0x25; + posix->Name[3] =3D 0x50; + posix->Name[4] =3D 0x9C; + posix->Name[5] =3D 0xB4; + posix->Name[6] =3D 0x11; + posix->Name[7] =3D 0xE7; + posix->Name[8] =3D 0xB4; + posix->Name[9] =3D 0x23; + posix->Name[10] =3D 0x83; + posix->Name[11] =3D 0xDE; + posix->Name[12] =3D 0x96; + posix->Name[13] =3D 0x8B; + posix->Name[14] =3D 0xCD; + posix->Name[15] =3D 0x7C; + cifs_end_neg_context(smb, posix, sizeof(*posix)); } =20 -static void -assemble_neg_contexts(struct smb2_negotiate_req *req, - struct TCP_Server_Info *server, unsigned int *total_len) +static size_t smb2_size_neg_contexts(struct TCP_Server_Info *server, + size_t offset) { - unsigned int ctxt_len, neg_context_count; struct TCP_Server_Info *pserver; - char *pneg_ctxt; - char *hostname; - - if (*total_len > 200) { - /* In case length corrupted don't want to overrun smb buffer */ - cifs_server_dbg(VFS, "Bad frame length assembling neg contexts\n"); - return; - } =20 /* * round up total_len of fixed part of SMB3 negotiate request to 8 * byte boundary before adding negotiate contexts */ - *total_len =3D ALIGN8(*total_len); + offset =3D ALIGN8(offset); + offset +=3D ALIGN8(sizeof(struct smb2_preauth_neg_context)); + offset +=3D ALIGN8(sizeof(struct smb2_encryption_neg_context)); + + /* + * secondary channels don't have the hostname field populated + * use the hostname field in the primary channel instead + */ + pserver =3D SERVER_IS_CHAN(server) ? server->primary_server : server; + offset +=3D smb2_size_netname_ctxt(pserver); + + offset +=3D ALIGN8(sizeof(struct smb2_posix_neg_context)); + if (server->compression.requested) + offset +=3D ALIGN8(sizeof(struct smb2_compression_capabilities_context)); + if (enable_negotiate_signing) + offset +=3D smb2_size_signing_ctxt(); + return offset; +} =20 - pneg_ctxt =3D (*total_len) + (char *)req; - req->NegotiateContextOffset =3D cpu_to_le32(*total_len); +static void +assemble_neg_contexts(struct smb_message *smb, struct TCP_Server_Info *ser= ver) +{ + struct smb2_negotiate_req *req =3D smb->request; + struct TCP_Server_Info *pserver; + const char *hostname; + unsigned int neg_context_count =3D 2; =20 - build_preauth_ctxt((struct smb2_preauth_neg_context *)pneg_ctxt); - ctxt_len =3D ALIGN8(sizeof(struct smb2_preauth_neg_context)); - *total_len +=3D ctxt_len; - pneg_ctxt +=3D ctxt_len; + cifs_pad_to_8(smb); + req->NegotiateContextOffset =3D cpu_to_le32(smb->offset); =20 - build_encrypt_ctxt((struct smb2_encryption_neg_context *)pneg_ctxt); - ctxt_len =3D ALIGN8(sizeof(struct smb2_encryption_neg_context)); - *total_len +=3D ctxt_len; - pneg_ctxt +=3D ctxt_len; + build_preauth_ctxt(smb); + build_encrypt_ctxt(smb); =20 /* * secondary channels don't have the hostname field populated @@ -971,47 +1030,35 @@ assemble_neg_contexts(struct smb2_negotiate_req *req, pserver =3D SERVER_IS_CHAN(server) ? server->primary_server : server; cifs_server_lock(pserver); hostname =3D pserver->hostname; - if (hostname && (hostname[0] !=3D 0)) { - ctxt_len =3D build_netname_ctxt((struct smb2_netname_neg_context *)pneg_= ctxt, - hostname); - *total_len +=3D ctxt_len; - pneg_ctxt +=3D ctxt_len; - neg_context_count =3D 3; - } else - neg_context_count =3D 2; + if (hostname && hostname[0]) { + build_netname_ctxt(smb, hostname); + neg_context_count++; + } cifs_server_unlock(pserver); =20 - build_posix_ctxt((struct smb2_posix_neg_context *)pneg_ctxt); - *total_len +=3D sizeof(struct smb2_posix_neg_context); - pneg_ctxt +=3D sizeof(struct smb2_posix_neg_context); + build_posix_ctxt(smb); neg_context_count++; =20 if (server->compression.requested) { - build_compression_ctxt((struct smb2_compression_capabilities_context *) - pneg_ctxt); - ctxt_len =3D ALIGN8(sizeof(struct smb2_compression_capabilities_context)= ); - *total_len +=3D ctxt_len; - pneg_ctxt +=3D ctxt_len; + build_compression_ctxt(smb); neg_context_count++; } =20 if (enable_negotiate_signing) { - ctxt_len =3D build_signing_ctxt((struct smb2_signing_capabilities *) - pneg_ctxt); - *total_len +=3D ctxt_len; - pneg_ctxt +=3D ctxt_len; + build_signing_ctxt(smb); neg_context_count++; } =20 /* check for and add transport_capabilities and signing capabilities */ req->NegotiateContextCount =3D cpu_to_le16(neg_context_count); - } =20 /* If invalid preauth context warn but use what we requested, SHA-512 */ -static void decode_preauth_context(struct smb2_preauth_neg_context *ctxt) +static void decode_preauth_context(struct smb2_neg_context *neg) { - unsigned int len =3D le16_to_cpu(ctxt->DataLength); + struct smb2_preauth_neg_context *ctxt =3D + container_of(neg, struct smb2_preauth_neg_context, neg); + unsigned int len =3D le16_to_cpu(ctxt->neg.DataLength); =20 /* * Caller checked that DataLength remains within SMB boundary. We still @@ -1031,9 +1078,11 @@ static void decode_preauth_context(struct smb2_preau= th_neg_context *ctxt) } =20 static void decode_compress_ctx(struct TCP_Server_Info *server, - struct smb2_compression_capabilities_context *ctxt) + struct smb2_neg_context *neg) { - unsigned int len =3D le16_to_cpu(ctxt->DataLength); + struct smb2_compression_capabilities_context *ctxt =3D + container_of(neg, struct smb2_compression_capabilities_context, neg); + unsigned int len =3D le16_to_cpu(ctxt->neg.DataLength); __le16 alg; =20 server->compression.enabled =3D false; @@ -1066,9 +1115,11 @@ static void decode_compress_ctx(struct TCP_Server_In= fo *server, } =20 static int decode_encrypt_ctx(struct TCP_Server_Info *server, - struct smb2_encryption_neg_context *ctxt) + struct smb2_neg_context *neg) { - unsigned int len =3D le16_to_cpu(ctxt->DataLength); + struct smb2_encryption_neg_context *ctxt =3D + container_of(neg, struct smb2_encryption_neg_context, neg); + unsigned int len =3D le16_to_cpu(ctxt->neg.DataLength); =20 cifs_dbg(FYI, "decode SMB3.11 encryption neg context of len %d\n", len); /* @@ -1118,9 +1169,11 @@ static int decode_encrypt_ctx(struct TCP_Server_Info= *server, } =20 static void decode_signing_ctx(struct TCP_Server_Info *server, - struct smb2_signing_capabilities *pctxt) + struct smb2_neg_context *neg) { - unsigned int len =3D le16_to_cpu(pctxt->DataLength); + struct smb2_signing_capabilities *pctxt =3D + container_of(neg, struct smb2_signing_capabilities, neg); + unsigned int len =3D le16_to_cpu(pctxt->neg.DataLength); =20 /* * Caller checked that DataLength remains within SMB boundary. We still @@ -1147,11 +1200,12 @@ static void decode_signing_ctx(struct TCP_Server_In= fo *server, } =20 =20 -static int smb311_decode_neg_context(struct smb2_negotiate_rsp *rsp, - struct TCP_Server_Info *server, - unsigned int len_of_smb) +static int smb311_decode_neg_context(struct smb_message *smb, + struct TCP_Server_Info *server) { + struct smb2_negotiate_rsp *rsp =3D smb->response; struct smb2_neg_context *pctx; + unsigned int len_of_smb =3D smb->resp_len; unsigned int offset =3D le32_to_cpu(rsp->NegotiateContextOffset); unsigned int ctxt_cnt =3D le16_to_cpu(rsp->NegotiateContextCount); unsigned int len_of_ctxts, i; @@ -1184,23 +1238,26 @@ static int smb311_decode_neg_context(struct smb2_ne= gotiate_rsp *rsp, if (clen > len_of_ctxts) break; =20 - if (pctx->ContextType =3D=3D SMB2_PREAUTH_INTEGRITY_CAPABILITIES) - decode_preauth_context( - (struct smb2_preauth_neg_context *)pctx); - else if (pctx->ContextType =3D=3D SMB2_ENCRYPTION_CAPABILITIES) - rc =3D decode_encrypt_ctx(server, - (struct smb2_encryption_neg_context *)pctx); - else if (pctx->ContextType =3D=3D SMB2_COMPRESSION_CAPABILITIES) - decode_compress_ctx(server, - (struct smb2_compression_capabilities_context *)pctx); - else if (pctx->ContextType =3D=3D SMB2_POSIX_EXTENSIONS_AVAILABLE) + switch (pctx->ContextType) { + case SMB2_PREAUTH_INTEGRITY_CAPABILITIES: + decode_preauth_context(pctx); + break; + case SMB2_ENCRYPTION_CAPABILITIES: + rc =3D decode_encrypt_ctx(server, pctx); + break; + case SMB2_COMPRESSION_CAPABILITIES: + decode_compress_ctx(server, pctx); + break; + case SMB2_POSIX_EXTENSIONS_AVAILABLE: server->posix_ext_supported =3D true; - else if (pctx->ContextType =3D=3D SMB2_SIGNING_CAPABILITIES) - decode_signing_ctx(server, - (struct smb2_signing_capabilities *)pctx); - else + break; + case SMB2_SIGNING_CAPABILITIES: + decode_signing_ctx(server, pctx); + break; + default: cifs_server_dbg(VFS, "unknown negcontext of type %d ignored\n", le16_to_cpu(pctx->ContextType)); + } if (rc) break; =20 @@ -1284,16 +1341,15 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses, struct TCP_Server_Info *server) { - struct smb_rqst rqst; struct smb2_negotiate_req *req; struct smb2_negotiate_rsp *rsp; - struct kvec iov[1]; - struct kvec rsp_iov; + struct smb_message *smb; + const char *vs; + size_t estimate, num_dialects; int rc; - int resp_buftype; char *security_blob; int flags =3D CIFS_NEG_OP; - unsigned int total_len; + enum { DEF, ANY3, SPEC } version; =20 cifs_dbg(FYI, "Negotiate protocol\n"); =20 @@ -1302,38 +1358,71 @@ SMB2_negotiate(const unsigned int xid, return smb_EIO(smb_eio_trace_null_pointers); } =20 - rc =3D smb2_plain_req_init(SMB2_NEGOTIATE, NULL, server, - (void **) &req, &total_len); + rc =3D smb2_reconnect(SMB2_SESSION_SETUP, NULL, server, false); if (rc) return rc; =20 + /* Calculate how much space we need for a Negotiate Request message. + * We can't do this exactly as the hostname might change, but we don't + * want to hold the lock across the allocation. + */ + vs =3D server->vals->version_string; + if (strcmp(vs, SMB3ANY_VERSION_STRING) =3D=3D 0) { + version =3D ANY3; + num_dialects =3D 3; + } else if (strcmp(vs, SMBDEFAULT_VERSION_STRING) =3D=3D 0) { + version =3D DEF; + num_dialects =3D 4; + } else { + version =3D SPEC; + num_dialects =3D 1; + } + + estimate =3D struct_size(req, Dialects, num_dialects); + + if ((server->vals->protocol_id =3D=3D SMB311_PROT_ID) || + (version =3D=3D ANY3) || + (version =3D=3D DEF)) + estimate =3D smb2_size_neg_contexts(server, estimate); + + smb =3D smb2_create_request(SMB2_NEGOTIATE, server, NULL, + sizeof(*req), estimate, 0, + SMB2_REQ_HEAD); + if (!smb) + return -ENOMEM; + + smb->sr_flags =3D flags; + + /* Fill in the message. */ + req =3D smb->request; req->hdr.SessionId =3D 0; =20 memset(server->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); memset(ses->preauth_sha_hash, 0, SMB2_PREAUTH_HASH_SIZE); =20 - if (strcmp(server->vals->version_string, - SMB3ANY_VERSION_STRING) =3D=3D 0) { + switch (version) { + case ANY3: + req->DialectCount =3D cpu_to_le16(3); req->Dialects[0] =3D cpu_to_le16(SMB30_PROT_ID); req->Dialects[1] =3D cpu_to_le16(SMB302_PROT_ID); req->Dialects[2] =3D cpu_to_le16(SMB311_PROT_ID); - req->DialectCount =3D cpu_to_le16(3); - total_len +=3D 6; - } else if (strcmp(server->vals->version_string, - SMBDEFAULT_VERSION_STRING) =3D=3D 0) { + break; + case DEF: + req->DialectCount =3D cpu_to_le16(4); req->Dialects[0] =3D cpu_to_le16(SMB21_PROT_ID); req->Dialects[1] =3D cpu_to_le16(SMB30_PROT_ID); req->Dialects[2] =3D cpu_to_le16(SMB302_PROT_ID); req->Dialects[3] =3D cpu_to_le16(SMB311_PROT_ID); - req->DialectCount =3D cpu_to_le16(4); - total_len +=3D 8; - } else { + break; + case SPEC: /* otherwise send specific dialect */ - req->Dialects[0] =3D cpu_to_le16(server->vals->protocol_id); req->DialectCount =3D cpu_to_le16(1); - total_len +=3D 2; + req->Dialects[0] =3D cpu_to_le16(server->vals->protocol_id); + break; } =20 + smb->offset +=3D num_dialects * sizeof(__le16); + /* only one of SMB2 signing flags may be set in SMB2 request */ if (ses->sign) req->SecurityMode =3D cpu_to_le16(SMB2_NEGOTIATE_SIGNING_REQUIRED); @@ -1346,42 +1435,46 @@ SMB2_negotiate(const unsigned int xid, req->Capabilities |=3D cpu_to_le32(SMB2_GLOBAL_CAP_MULTI_CHANNEL); =20 /* ClientGUID must be zero for SMB2.02 dialect */ - if (server->vals->protocol_id =3D=3D SMB20_PROT_ID) + if (server->vals->protocol_id =3D=3D SMB20_PROT_ID) { memset(req->ClientGUID, 0, SMB2_CLIENT_GUID_SIZE); - else { + } else { memcpy(req->ClientGUID, server->client_guid, SMB2_CLIENT_GUID_SIZE); if ((server->vals->protocol_id =3D=3D SMB311_PROT_ID) || - (strcmp(server->vals->version_string, - SMB3ANY_VERSION_STRING) =3D=3D 0) || - (strcmp(server->vals->version_string, - SMBDEFAULT_VERSION_STRING) =3D=3D 0)) - assemble_neg_contexts(req, server, &total_len); + (version =3D=3D ANY3) || + (version =3D=3D DEF)) + assemble_neg_contexts(smb, server); } - iov[0].iov_base =3D (char *)req; - iov[0].iov_len =3D total_len; =20 - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 1; + smb->data_offset =3D smb->offset; + smb->total_len =3D smb->offset; + smb->bvecq.bv[0].bv_len =3D smb->offset; + + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); + + rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); + smb_clear_request(smb); =20 - rc =3D cifs_send_recv(xid, ses, server, - &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); - rsp =3D (struct smb2_negotiate_rsp *)rsp_iov.iov_base; /* * No tcon so can't do * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); */ - if (rc =3D=3D -EOPNOTSUPP) { - cifs_server_dbg(VFS, "Dialect not supported by server. Consider specify= ing vers=3D1.0 or vers=3D2.0 on mount for accessing older servers\n"); - goto neg_exit; - } else if (rc !=3D 0) + if (rc !=3D 0) { + if (rc =3D=3D -EOPNOTSUPP) + cifs_server_dbg(VFS, "Dialect not supported by server. Consider specif= ying vers=3D1.0 or vers=3D2.0 on mount for accessing older servers\n"); goto neg_exit; + } + + /* ________________________________________ + * Decode the response. + */ + rsp =3D (struct smb2_negotiate_rsp *)smb->response; =20 u16 dialect =3D le16_to_cpu(rsp->DialectRevision); - if (strcmp(server->vals->version_string, - SMB3ANY_VERSION_STRING) =3D=3D 0) { + rc =3D -EIO; + switch (version) { + case ANY3: switch (dialect) { case SMB20_PROT_ID: cifs_server_dbg(VFS, @@ -1398,11 +1491,9 @@ SMB2_negotiate(const unsigned int xid, server->ops =3D &smb311_operations; server->vals =3D &smb311_values; break; - default: - break; } - } else if (strcmp(server->vals->version_string, - SMBDEFAULT_VERSION_STRING) =3D=3D 0) { + break; + case DEF: switch (dialect) { case SMB20_PROT_ID: cifs_server_dbg(VFS, @@ -1421,10 +1512,14 @@ SMB2_negotiate(const unsigned int xid, default: break; } - } else if (dialect !=3D server->vals->protocol_id) { - /* if requested single dialect ensure returned dialect matched */ - cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", - dialect); + break; + default: + if (dialect !=3D server->vals->protocol_id) { + /* if requested single dialect ensure returned dialect matched */ + cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", + dialect); + goto neg_exit; + } rc =3D smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, server->vals->protocol_id); goto neg_exit; @@ -1490,13 +1585,8 @@ SMB2_negotiate(const unsigned int xid, (server->capabilities & SMB2_GLOBAL_CAP_ENCRYPTION)) server->cipher_type =3D SMB2_ENCRYPTION_AES128_CCM; =20 - struct cifs_receive recv =3D { - /* TODO: This should be returned into smb_message */ - .response =3D rsp_iov.iov_base, - .msg_len =3D rsp_iov.iov_len, - }; + security_blob =3D smb->response + smb->resp_data_offset; =20 - security_blob =3D smb2_get_data_area_len(&recv); /* * See MS-SMB2 section 2.2.4: if no blob, client picks default which * for us will be @@ -1504,7 +1594,7 @@ SMB2_negotiate(const unsigned int xid, * but for time being this is our only auth choice so doesn't matter. * We just found a server which sets blob length to zero expecting raw. */ - if (recv.data_len =3D=3D 0) { + if (smb->resp_data_len =3D=3D 0) { cifs_dbg(FYI, "missing security blob on negprot\n"); server->sec_ntlmssp =3D true; } @@ -1512,8 +1602,8 @@ SMB2_negotiate(const unsigned int xid, rc =3D cifs_enable_signing(server, ses->sign); if (rc) goto neg_exit; - if (recv.data_len) { - rc =3D decode_negTokenInit(security_blob, recv.data_len, server); + if (smb->resp_data_len) { + rc =3D decode_negTokenInit(security_blob, smb->resp_data_len, server); if (rc =3D=3D 1) rc =3D 0; else if (rc =3D=3D 0) @@ -1522,8 +1612,7 @@ SMB2_negotiate(const unsigned int xid, =20 if (server->dialect =3D=3D SMB311_PROT_ID) { if (rsp->NegotiateContextCount) - rc =3D smb311_decode_neg_context(rsp, server, - rsp_iov.iov_len); + rc =3D smb311_decode_neg_context(smb, server); else cifs_server_dbg(VFS, "Missing expected negotiate contexts\n"); } @@ -1531,7 +1620,7 @@ SMB2_negotiate(const unsigned int xid, if (server->cipher_type && !rc) rc =3D smb3_crypto_aead_allocate(server); neg_exit: - free_rsp_buf(resp_buftype, rsp); + smb_put_messages(smb); return rc; } =20 diff --git a/fs/smb/common/smb2pdu.h b/fs/smb/common/smb2pdu.h index 3d69daf8d7ef..d04a343c15c3 100644 --- a/fs/smb/common/smb2pdu.h +++ b/fs/smb/common/smb2pdu.h @@ -477,9 +477,7 @@ struct smb2_neg_context { #define MIN_PREAUTH_CTXT_DATA_LEN 6 =20 struct smb2_preauth_neg_context { - __le16 ContextType; /* 1 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; __le16 HashAlgorithmCount; /* 1 */ __le16 SaltLength; __le16 HashAlgorithms; /* HashAlgorithms[0] since only one defined */ @@ -495,9 +493,7 @@ struct smb2_preauth_neg_context { /* Min encrypt context data is one cipher so 2 bytes + 2 byte count field = */ #define MIN_ENCRYPT_CTXT_DATA_LEN 4 struct smb2_encryption_neg_context { - __le16 ContextType; /* 2 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; /* CipherCount usually 2, but can be 3 when AES256-GCM enabled */ __le16 CipherCount; /* AES128-GCM and AES128-CCM by default */ __le16 Ciphers[]; @@ -519,9 +515,7 @@ struct smb2_encryption_neg_context { #define SMB2_COMPRESSION_CAPABILITIES_FLAG_CHAINED cpu_to_le32(0x00000001) =20 struct smb2_compression_capabilities_context { - __le16 ContextType; /* 3 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; __le16 CompressionAlgorithmCount; __le16 Padding; __le32 Flags; @@ -535,9 +529,7 @@ struct smb2_compression_capabilities_context { * Its struct simply contains NetName, an array of Unicode characters */ struct smb2_netname_neg_context { - __le16 ContextType; /* 5 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; __le16 NetName[]; /* hostname of target converted to UCS-2 */ } __packed; =20 @@ -591,9 +583,7 @@ struct smb2_rdma_transform_capabilities_context { #define SIGNING_ALG_AES_GMAC_LE cpu_to_le16(2) =20 struct smb2_signing_capabilities { - __le16 ContextType; /* 8 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; __le16 SigningAlgorithmCount; __le16 SigningAlgorithms[]; /* Followed by padding to 8 byte boundary (required by some servers) */ @@ -601,9 +591,7 @@ struct smb2_signing_capabilities { =20 #define POSIX_CTXT_DATA_LEN 16 struct smb2_posix_neg_context { - __le16 ContextType; /* 0x100 */ - __le16 DataLength; - __le32 Reserved; + struct smb2_neg_context neg; __u8 Name[16]; /* POSIX ctxt GUID 93AD25509CB411E7B42383DE968BCD7C */ } __packed; =20 diff --git a/fs/smb/server/smb2pdu.c b/fs/smb/server/smb2pdu.c index 62d4399a993d..ec60629355f7 100644 --- a/fs/smb/server/smb2pdu.c +++ b/fs/smb/server/smb2pdu.c @@ -784,10 +784,10 @@ static int smb2_get_dos_mode(struct kstat *stat, int = attribute) static void build_preauth_ctxt(struct smb2_preauth_neg_context *pneg_ctxt, __le16 hash_id) { - pneg_ctxt->ContextType =3D SMB2_PREAUTH_INTEGRITY_CAPABILITIES; - pneg_ctxt->DataLength =3D cpu_to_le16(38); + pneg_ctxt->neg.ContextType =3D SMB2_PREAUTH_INTEGRITY_CAPABILITIES; + pneg_ctxt->neg.DataLength =3D cpu_to_le16(38); + pneg_ctxt->neg.Reserved =3D cpu_to_le32(0); pneg_ctxt->HashAlgorithmCount =3D cpu_to_le16(1); - pneg_ctxt->Reserved =3D cpu_to_le32(0); pneg_ctxt->SaltLength =3D cpu_to_le16(SMB311_SALT_SIZE); get_random_bytes(pneg_ctxt->Salt, SMB311_SALT_SIZE); pneg_ctxt->HashAlgorithms =3D hash_id; @@ -796,9 +796,9 @@ static void build_preauth_ctxt(struct smb2_preauth_neg_= context *pneg_ctxt, static void build_encrypt_ctxt(struct smb2_encryption_neg_context *pneg_ct= xt, __le16 cipher_type) { - pneg_ctxt->ContextType =3D SMB2_ENCRYPTION_CAPABILITIES; - pneg_ctxt->DataLength =3D cpu_to_le16(4); - pneg_ctxt->Reserved =3D cpu_to_le32(0); + pneg_ctxt->neg.ContextType =3D SMB2_ENCRYPTION_CAPABILITIES; + pneg_ctxt->neg.DataLength =3D cpu_to_le16(4); + pneg_ctxt->neg.Reserved =3D cpu_to_le32(0); pneg_ctxt->CipherCount =3D cpu_to_le16(1); pneg_ctxt->Ciphers[0] =3D cipher_type; } @@ -806,19 +806,19 @@ static void build_encrypt_ctxt(struct smb2_encryption= _neg_context *pneg_ctxt, static void build_sign_cap_ctxt(struct smb2_signing_capabilities *pneg_ctx= t, __le16 sign_algo) { - pneg_ctxt->ContextType =3D SMB2_SIGNING_CAPABILITIES; - pneg_ctxt->DataLength =3D + pneg_ctxt->neg.ContextType =3D SMB2_SIGNING_CAPABILITIES; + pneg_ctxt->neg.DataLength =3D cpu_to_le16((sizeof(struct smb2_signing_capabilities) + 2) - sizeof(struct smb2_neg_context)); - pneg_ctxt->Reserved =3D cpu_to_le32(0); + pneg_ctxt->neg.Reserved =3D cpu_to_le32(0); pneg_ctxt->SigningAlgorithmCount =3D cpu_to_le16(1); pneg_ctxt->SigningAlgorithms[0] =3D sign_algo; } =20 static void build_posix_ctxt(struct smb2_posix_neg_context *pneg_ctxt) { - pneg_ctxt->ContextType =3D SMB2_POSIX_EXTENSIONS_AVAILABLE; - pneg_ctxt->DataLength =3D cpu_to_le16(POSIX_CTXT_DATA_LEN); + pneg_ctxt->neg.ContextType =3D SMB2_POSIX_EXTENSIONS_AVAILABLE; + pneg_ctxt->neg.DataLength =3D cpu_to_le16(POSIX_CTXT_DATA_LEN); /* SMB2_CREATE_TAG_POSIX is "0x93AD25509CB411E7B42383DE968BCD7C" */ pneg_ctxt->Name[0] =3D 0x93; pneg_ctxt->Name[1] =3D 0xAD; From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 65C944D9910 for ; Tue, 19 May 2026 10:24:25 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186267; cv=none; b=QtNNp5GrJhQGkv0HwZ7wD7jyPEgpjtuxjuHcN+XzboM3N1s/VqDtC4mKEfSPBaNwNTHkhL1y7L1154n7bH5/Er2P9hsMbftAIJq+i4N/T0XnFD9X9LiD+DKEE9NJTb3pGyAqnRAYlIAUY84+X6v5DOnPUdy4dJYlr7WP9SbPhYs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186267; c=relaxed/simple; bh=VwqNZus43PxkJpHxsmbt5XIg6qZta5+v2+NDD7iXLiI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UvyJovmDUQij0yuPOD3YAnitjLqmUP11Ju5LQ59ju8r7ooXsXwppMRuY5Nz7nNKnTzqnwy/CjL/7f087jsal0dbPB7n7ES58eFpNZBOKGgWtl4F0S31Gm5Ww1SR5jHqqqVW/650LiUXnqRLkhlhWiLdd1vjJDwp1sx7SYbmGjrE= 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=Qb6ee9HW; arc=none smtp.client-ip=170.10.133.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="Qb6ee9HW" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186264; 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=4AzvZS2qj9TZCZ5ahd69qz2826PQzAycMMi1PIdmiLc=; b=Qb6ee9HWit4Z3RWp4XUpcx1a4ujSi6X4jV8PXuY6nAFMVBznmGLNzZ4AUKh3phz0lHwB0X YMGsUVkMXXKm+91vTleNHbmB4S0GWI5RSa731YNMafVhTotpIm52sLuz6OuNN5k16Ba07z vZ8ePbtTZzuVOpcxHxYTnkgKmN1fXm0= 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-404-L2YHATE2Ncu6_0qnN3zD-A-1; Tue, 19 May 2026 06:24:21 -0400 X-MC-Unique: L2YHATE2Ncu6_0qnN3zD-A-1 X-Mimecast-MFC-AGG-ID: L2YHATE2Ncu6_0qnN3zD-A_1779186259 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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 9015B1800372; Tue, 19 May 2026 10:24:19 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 2A26C30001A2; Tue, 19 May 2026 10:24:15 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 27/36] cifs: Convert SMB2 Session Setup request Date: Tue, 19 May 2026 11:21:45 +0100 Message-ID: <20260519102158.592165-28-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 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/ntlmssp.h | 8 +- fs/smb/client/sess.c | 306 ++++++++++++++++++++---------------- fs/smb/client/smb1session.c | 4 +- fs/smb/client/smb2pdu.c | 180 +++++++++------------ 4 files changed, 253 insertions(+), 245 deletions(-) diff --git a/fs/smb/client/ntlmssp.h b/fs/smb/client/ntlmssp.h index be0365f08396..58fcaa868fab 100644 --- a/fs/smb/client/ntlmssp.h +++ b/fs/smb/client/ntlmssp.h @@ -123,7 +123,7 @@ typedef struct _CHALLENGE_MESSAGE { do not set the version is present flag */ } __packed CHALLENGE_MESSAGE, *PCHALLENGE_MESSAGE; =20 -typedef struct _AUTHENTICATE_MESSAGE { +struct ntlmssp_authenticate_message { __u8 Signature[sizeof(NTLMSSP_SIGNATURE)]; __le32 MessageType; /* NtLmsAuthenticate =3D 3 */ SECURITY_BUFFER LmChallengeResponse; @@ -136,7 +136,7 @@ typedef struct _AUTHENTICATE_MESSAGE { struct ntlmssp_version Version; /* SECURITY_BUFFER */ char UserString[]; -} __packed AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE; +} __packed; =20 /* * Size of the session key (crypto key encrypted with the password @@ -148,11 +148,11 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuf= fer, u16 *buflen, struct cifs_ses *ses, struct TCP_Server_Info *server, const struct nls_table *nls_cp); -int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, u16 *buflen, +int build_ntlmssp_smb3_negotiate_blob(struct smb_message *smb, struct cifs_ses *ses, struct TCP_Server_Info *server, const struct nls_table *nls_cp); -int build_ntlmssp_auth_blob(unsigned char **pbuffer, u16 *buflen, +int build_ntlmssp_auth_blob(struct smb_message *smb, struct cifs_ses *ses, struct TCP_Server_Info *server, const struct nls_table *nls_cp); diff --git a/fs/smb/client/sess.c b/fs/smb/client/sess.c index de2012cc9cf3..0abb618019b1 100644 --- a/fs/smb/client/sess.c +++ b/fs/smb/client/sess.c @@ -707,32 +707,67 @@ int decode_ntlmssp_challenge(char *bcc_ptr, int blob_= len, return 0; } =20 -static int size_of_ntlmssp_blob(struct cifs_ses *ses, int base_size) +static int size_of_ntlmssp_neg_blob(struct cifs_ses *ses, int base_size, + const struct nls_table *nls_cp) { int sz =3D base_size + ses->auth_key.len - CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE + 2; + sz +=3D sizeof(__le16) * 2; /* Two empty strings. */ + return sz; +} =20 - if (ses->domainName) - sz +=3D sizeof(__le16) * strnlen(ses->domainName, CIFS_MAX_DOMAINNAME_LE= N); - else - sz +=3D sizeof(__le16); - - if (ses->user_name) - sz +=3D sizeof(__le16) * strnlen(ses->user_name, CIFS_MAX_USERNAME_LEN); - else - sz +=3D sizeof(__le16); +static void cifs_append_security_string(struct smb_message *smb, + SECURITY_BUFFER *pbuf, + const char *str_value, + int str_length, + unsigned char **pcur, + const struct nls_table *nls_cp) +{ + int len; =20 - if (ses->workstation_name[0]) - sz +=3D sizeof(__le16) * strnlen(ses->workstation_name, - ntlmssp_workstation_name_size(ses)); - else - sz +=3D sizeof(__le16); + if (!str_value) { + pbuf->BufferOffset =3D cpu_to_le32(smb->offset); + pbuf->Length =3D 0; + pbuf->MaximumLength =3D 0; + *(__le16 *)*pcur =3D 0; + smb->offset +=3D 2; + *pcur +=3D 2; + } else { + len =3D cifs_strtoUTF16((__le16 *)*pcur, + str_value, + str_length, + nls_cp); + len *=3D sizeof(__le16); + pbuf->BufferOffset =3D cpu_to_le32(smb->offset); + pbuf->Length =3D cpu_to_le16(len); + pbuf->MaximumLength =3D cpu_to_le16(len); + smb->offset +=3D len; + *pcur +=3D len; + } +} =20 - return sz; +static void cifs_append_security_blob(struct smb_message *smb, + SECURITY_BUFFER *pbuf, + const void *content, + int len, + unsigned char **pcur) +{ + if (!content) { + pbuf->BufferOffset =3D cpu_to_le32(smb->offset); + pbuf->Length =3D 0; + pbuf->MaximumLength =3D 0; + } else { + memcpy(*pcur, content, len); + pbuf->BufferOffset =3D cpu_to_le32(smb->offset); + pbuf->Length =3D cpu_to_le16(len); + pbuf->MaximumLength =3D cpu_to_le16(len); + smb->offset +=3D len; + *pcur +=3D len; + } } =20 static inline void cifs_security_buffer_from_str(SECURITY_BUFFER *pbuf, - char *str_value, + const char *str_value, int str_length, unsigned char *pstart, unsigned char **pcur, @@ -779,7 +814,7 @@ int build_ntlmssp_negotiate_blob(unsigned char **pbuffe= r, unsigned char *tmp; int len; =20 - len =3D size_of_ntlmssp_blob(ses, sizeof(NEGOTIATE_MESSAGE)); + len =3D size_of_ntlmssp_neg_blob(ses, sizeof(NEGOTIATE_MESSAGE), nls_cp); *pbuffer =3D kmalloc(len, GFP_KERNEL); if (!*pbuffer) { rc =3D -ENOMEM; @@ -829,173 +864,178 @@ int build_ntlmssp_negotiate_blob(unsigned char **pb= uffer, * supported by modern servers. For safety limit to SMB3 or later * See notes in MS-NLMP Section 2.2.2.1 e.g. */ -int build_ntlmssp_smb3_negotiate_blob(unsigned char **pbuffer, - u16 *buflen, - struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) +int build_ntlmssp_smb3_negotiate_blob(struct smb_message *smb, + struct cifs_ses *ses, + struct TCP_Server_Info *server, + const struct nls_table *nls_cp) { - int rc =3D 0; - struct negotiate_message *sec_blob; - __u32 flags; + struct negotiate_message *neg_msg; unsigned char *tmp; + __u32 flags; + void *blob; int len; + int rc =3D 0; =20 - len =3D size_of_ntlmssp_blob(ses, sizeof(struct negotiate_message)); - *pbuffer =3D kmalloc(len, GFP_KERNEL); - if (!*pbuffer) { + len =3D sizeof(*neg_msg); + len +=3D 2 * sizeof(__le16); /* Two empty strings */ + + blob =3D cifs_allocate_tx_buf(server, len); + if (!blob) { rc =3D -ENOMEM; cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc); - *buflen =3D 0; goto setup_ntlm_smb3_neg_ret; } - sec_blob =3D (struct negotiate_message *)*pbuffer; =20 - memset(*pbuffer, 0, sizeof(struct negotiate_message)); - memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); - sec_blob->MessageType =3D NtLmNegotiate; + smb_add_segment_to_tx_buf(smb, blob, len); + smb->offset =3D sizeof(*neg_msg); =20 /* BB is NTLMV2 session security format easier to use here? */ - flags =3D NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | - NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | - NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC | - NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL | - NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_VERSION; + flags =3D NTLMSSP_NEGOTIATE_56 | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_UNICODE | + NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SEC | + NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL | + NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_VERSION; if (!server->session_estab || ses->ntlmssp->sesskey_per_smbsess) flags |=3D NTLMSSP_NEGOTIATE_KEY_XCH; =20 - sec_blob->Version.ProductMajorVersion =3D LINUX_VERSION_MAJOR; - sec_blob->Version.ProductMinorVersion =3D LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild =3D cpu_to_le16(SMB3_PRODUCT_BUILD); - sec_blob->Version.NTLMRevisionCurrent =3D NTLMSSP_REVISION_W2K3; + neg_msg =3D (struct negotiate_message *)blob; + *neg_msg =3D (struct negotiate_message){ + .Signature =3D NTLMSSP_SIGNATURE, + .MessageType =3D NtLmNegotiate, + .NegotiateFlags =3D cpu_to_le32(flags), + .Version.ProductMajorVersion =3D LINUX_VERSION_MAJOR, + .Version.ProductMinorVersion =3D LINUX_VERSION_PATCHLEVEL, + .Version.ProductBuild =3D cpu_to_le16(SMB3_PRODUCT_BUILD), + .Version.NTLMRevisionCurrent =3D NTLMSSP_REVISION_W2K3, + }; =20 - tmp =3D *pbuffer + sizeof(struct negotiate_message); ses->ntlmssp->client_flags =3D flags; - sec_blob->NegotiateFlags =3D cpu_to_le32(flags); + tmp =3D blob + sizeof(struct negotiate_message); =20 /* these fields should be null in negotiate phase MS-NLMP 3.1.5.1.1 */ - cifs_security_buffer_from_str(&sec_blob->DomainName, - NULL, - CIFS_MAX_DOMAINNAME_LEN, - *pbuffer, &tmp, - nls_cp); - - cifs_security_buffer_from_str(&sec_blob->WorkstationName, - NULL, - CIFS_MAX_WORKSTATION_LEN, - *pbuffer, &tmp, - nls_cp); + cifs_append_security_string(smb, &neg_msg->DomainName, + NULL, CIFS_MAX_DOMAINNAME_LEN, + &tmp, nls_cp); =20 - *buflen =3D tmp - *pbuffer; + cifs_append_security_string(smb, &neg_msg->WorkstationName, + NULL, CIFS_MAX_WORKSTATION_LEN, + &tmp, nls_cp); setup_ntlm_smb3_neg_ret: return rc; } =20 =20 +static int size_of_ntlmssp_auth_blob(struct cifs_ses *ses, int base_size, + const struct nls_table *nls_cp) +{ + int sz =3D base_size + ses->auth_key.len + - CIFS_SESS_KEY_SIZE + CIFS_CPHTXT_SIZE; +=09 + if (ses->domainName) + sz +=3D cifs_size_strtoUTF16(ses->domainName, CIFS_MAX_DOMAINNAME_LEN, + nls_cp); + else + sz +=3D sizeof(__le16); + + if (ses->user_name) + sz +=3D cifs_size_strtoUTF16(ses->user_name, CIFS_MAX_USERNAME_LEN, + nls_cp); + else + sz +=3D sizeof(__le16); + + if (ses->workstation_name[0]) + sz +=3D cifs_size_strtoUTF16(ses->workstation_name, + ntlmssp_workstation_name_size(ses), + nls_cp); + else + sz +=3D sizeof(__le16); + + return sz; +} + /* See MS-NLMP 2.2.1.3 */ -int build_ntlmssp_auth_blob(unsigned char **pbuffer, - u16 *buflen, - struct cifs_ses *ses, - struct TCP_Server_Info *server, - const struct nls_table *nls_cp) +int build_ntlmssp_auth_blob(struct smb_message *smb, + struct cifs_ses *ses, + struct TCP_Server_Info *server, + const struct nls_table *nls_cp) { - int rc; - AUTHENTICATE_MESSAGE *sec_blob; - __u32 flags; + struct ntlmssp_authenticate_message *auth_msg; unsigned char *tmp; + __u32 flags; + void *blob; int len; + int rc; =20 rc =3D setup_ntlmv2_rsp(ses, nls_cp); if (rc) { cifs_dbg(VFS, "Error %d during NTLMSSP authentication\n", rc); - *buflen =3D 0; goto setup_ntlmv2_ret; } =20 - len =3D size_of_ntlmssp_blob(ses, sizeof(AUTHENTICATE_MESSAGE)); - *pbuffer =3D kmalloc(len, GFP_KERNEL); - if (!*pbuffer) { + len =3D size_of_ntlmssp_auth_blob(ses, sizeof(*auth_msg), nls_cp); + blob =3D cifs_allocate_tx_buf(server, len); + if (!blob) { rc =3D -ENOMEM; cifs_dbg(VFS, "Error %d during NTLMSSP allocation\n", rc); - *buflen =3D 0; goto setup_ntlmv2_ret; } - sec_blob =3D (AUTHENTICATE_MESSAGE *)*pbuffer; =20 - memcpy(sec_blob->Signature, NTLMSSP_SIGNATURE, 8); - sec_blob->MessageType =3D NtLmAuthenticate; + smb_add_segment_to_tx_buf(smb, blob, len); + smb->offset =3D sizeof(*auth_msg); =20 /* send version information in ntlmssp authenticate also */ - flags =3D ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET | - NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_VERSION | + flags =3D ses->ntlmssp->server_flags | NTLMSSP_REQUEST_TARGET | + NTLMSSP_NEGOTIATE_TARGET_INFO | NTLMSSP_NEGOTIATE_VERSION | NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED; =20 - sec_blob->Version.ProductMajorVersion =3D LINUX_VERSION_MAJOR; - sec_blob->Version.ProductMinorVersion =3D LINUX_VERSION_PATCHLEVEL; - sec_blob->Version.ProductBuild =3D cpu_to_le16(SMB3_PRODUCT_BUILD); - sec_blob->Version.NTLMRevisionCurrent =3D NTLMSSP_REVISION_W2K3; + auth_msg =3D blob; + *auth_msg =3D (struct ntlmssp_authenticate_message){ + .Signature =3D NTLMSSP_SIGNATURE, + .MessageType =3D NtLmAuthenticate, + .NegotiateFlags =3D cpu_to_le32(flags), + .Version.ProductMajorVersion =3D LINUX_VERSION_MAJOR, + .Version.ProductMinorVersion =3D LINUX_VERSION_PATCHLEVEL, + .Version.ProductBuild =3D cpu_to_le16(SMB3_PRODUCT_BUILD), + .Version.NTLMRevisionCurrent =3D NTLMSSP_REVISION_W2K3, + }; =20 - tmp =3D *pbuffer + sizeof(AUTHENTICATE_MESSAGE); - sec_blob->NegotiateFlags =3D cpu_to_le32(flags); + tmp =3D blob + sizeof(*auth_msg); =20 - sec_blob->LmChallengeResponse.BufferOffset =3D - cpu_to_le32(sizeof(AUTHENTICATE_MESSAGE)); - sec_blob->LmChallengeResponse.Length =3D 0; - sec_blob->LmChallengeResponse.MaximumLength =3D 0; - - sec_blob->NtChallengeResponse.BufferOffset =3D - cpu_to_le32(tmp - *pbuffer); - if (ses->user_name !=3D NULL) { - memcpy(tmp, ses->auth_key.response + CIFS_SESS_KEY_SIZE, - ses->auth_key.len - CIFS_SESS_KEY_SIZE); - tmp +=3D ses->auth_key.len - CIFS_SESS_KEY_SIZE; - - sec_blob->NtChallengeResponse.Length =3D - cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); - sec_blob->NtChallengeResponse.MaximumLength =3D - cpu_to_le16(ses->auth_key.len - CIFS_SESS_KEY_SIZE); - } else { - /* - * don't send an NT Response for anonymous access - */ - sec_blob->NtChallengeResponse.Length =3D 0; - sec_blob->NtChallengeResponse.MaximumLength =3D 0; - } + cifs_append_security_blob(smb, &auth_msg->LmChallengeResponse, + NULL, 0, &tmp); =20 - cifs_security_buffer_from_str(&sec_blob->DomainName, - ses->domainName, - CIFS_MAX_DOMAINNAME_LEN, - *pbuffer, &tmp, - nls_cp); + /* Only send an NT Response for anonymous access */ + if (ses->user_name) + cifs_append_security_blob(smb, &auth_msg->NtChallengeResponse, + ses->auth_key.response + CIFS_SESS_KEY_SIZE, + ses->auth_key.len - CIFS_SESS_KEY_SIZE, + &tmp); + else + cifs_append_security_blob(smb, &auth_msg->NtChallengeResponse, + NULL, 0, &tmp); =20 - cifs_security_buffer_from_str(&sec_blob->UserName, - ses->user_name, - CIFS_MAX_USERNAME_LEN, - *pbuffer, &tmp, - nls_cp); + cifs_append_security_string(smb, &auth_msg->DomainName, + ses->domainName, CIFS_MAX_DOMAINNAME_LEN, + &tmp, nls_cp); =20 - cifs_security_buffer_from_str(&sec_blob->WorkstationName, - ses->workstation_name, - ntlmssp_workstation_name_size(ses), - *pbuffer, &tmp, - nls_cp); + cifs_append_security_string(smb, &auth_msg->UserName, + ses->user_name, CIFS_MAX_USERNAME_LEN, + &tmp, nls_cp); + + cifs_append_security_string(smb, &auth_msg->WorkstationName, + ses->workstation_name, + ntlmssp_workstation_name_size(ses), + &tmp, nls_cp); =20 if ((ses->ntlmssp->server_flags & NTLMSSP_NEGOTIATE_KEY_XCH) && (!ses->server->session_estab || ses->ntlmssp->sesskey_per_smbsess) && - !calc_seckey(ses)) { - memcpy(tmp, ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.BufferOffset =3D cpu_to_le32(tmp - *pbuffer); - sec_blob->SessionKey.Length =3D cpu_to_le16(CIFS_CPHTXT_SIZE); - sec_blob->SessionKey.MaximumLength =3D - cpu_to_le16(CIFS_CPHTXT_SIZE); - tmp +=3D CIFS_CPHTXT_SIZE; - } else { - sec_blob->SessionKey.BufferOffset =3D cpu_to_le32(tmp - *pbuffer); - sec_blob->SessionKey.Length =3D 0; - sec_blob->SessionKey.MaximumLength =3D 0; - } - - *buflen =3D tmp - *pbuffer; + !calc_seckey(ses)) + cifs_append_security_blob(smb, &auth_msg->SessionKey, + ses->ntlmssp->ciphertext, CIFS_CPHTXT_SIZE, + &tmp); + else + cifs_append_security_blob(smb, &auth_msg->SessionKey, + NULL, 0, &tmp); setup_ntlmv2_ret: return rc; } diff --git a/fs/smb/client/smb1session.c b/fs/smb/client/smb1session.c index 83bfbf0c068e..06c3eb2fcae9 100644 --- a/fs/smb/client/smb1session.c +++ b/fs/smb/client/smb1session.c @@ -835,9 +835,7 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *ses= s_data) /* Build security blob before we assemble the request */ pSMB =3D (SESSION_SETUP_ANDX *)sess_data->iov[0].iov_base; smb_buf =3D (struct smb_hdr *)pSMB; - rc =3D build_ntlmssp_auth_blob(&ntlmsspblob, - &blob_len, ses, server, - sess_data->nls_cp); + rc =3D build_ntlmssp_auth_blob(smb, ses, server, sess_data->nls_cp); if (rc) goto out_free_ntlmsspblob; sess_data->iov[1].iov_len =3D blob_len; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 193dca577fa1..4dd4f2de39f4 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1807,33 +1807,30 @@ struct SMB2_sess_data { void (*func)(struct SMB2_sess_data *); int result; u64 previous_session; - - /* we will send the SMB in three pieces: - * a fixed length beginning part, an optional - * SPNEGO blob (which can be zero length), and a - * last part which will include the strings - * and rest of bcc area. This allows us to avoid - * a large buffer 17K allocation - */ - int buf0_type; - struct kvec iov[2]; }; =20 -static int -SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_data) +static struct smb_message * +SMB2_create_session_request(struct SMB2_sess_data *sess_data) { - int rc; + struct smb_message *smb; struct cifs_ses *ses =3D sess_data->ses; struct TCP_Server_Info *server =3D sess_data->server; struct smb2_sess_setup_req *req; - unsigned int total_len; bool is_binding =3D false; =20 - rc =3D smb2_plain_req_init(SMB2_SESSION_SETUP, NULL, server, - (void **) &req, - &total_len); - if (rc) - return rc; + /* We will send the SMB in three pieces: + * - a fixed length beginning part, + * - an optional SPNEGO blob (which can be zero length), and + * - a last part which will include the strings and rest of bcc area. + * This allows us to avoid a large buffer 17K allocation + */ + smb =3D smb2_create_request(SMB2_SESSION_SETUP, server, NULL, + sizeof(*req), sizeof(*req), 0, + SMB2_REQ_DYNAMIC | + SMB2_REQ_SENSITIVE); + if (!smb) + return NULL; + req =3D smb->request; =20 spin_lock(&ses->ses_lock); is_binding =3D (ses->ses_status =3D=3D SES_GOOD); @@ -1882,55 +1879,29 @@ SMB2_sess_alloc_buffer(struct SMB2_sess_data *sess_= data) =20 req->Channel =3D 0; /* MBZ */ =20 - sess_data->iov[0].iov_base =3D (char *)req; - /* 1 for pad */ - sess_data->iov[0].iov_len =3D total_len; - /* - * This variable will be used to clear the buffer - * allocated above in case of any error in the calling function. - */ - sess_data->buf0_type =3D CIFS_SMALL_BUFFER; - - return 0; -} - -static void -SMB2_sess_free_buffer(struct SMB2_sess_data *sess_data) -{ - struct kvec *iov =3D sess_data->iov; - - /* iov[1] is already freed by caller */ - if (sess_data->buf0_type !=3D CIFS_NO_BUFFER && iov[0].iov_base) - memzero_explicit(iov[0].iov_base, iov[0].iov_len); - - free_rsp_buf(sess_data->buf0_type, iov[0].iov_base); - sess_data->buf0_type =3D CIFS_NO_BUFFER; + /* Testing shows that buffer offset must be at location of Buffer[0] */ + req->SecurityBufferOffset =3D cpu_to_le16(sizeof(*req)); + req->SecurityBufferLength =3D 0; + return smb; } =20 static int -SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data) +SMB2_sess_sendreceive(struct SMB2_sess_data *sess_data, + struct smb_message *smb) { int rc; - struct smb_rqst rqst; - struct smb2_sess_setup_req *req =3D sess_data->iov[0].iov_base; - struct kvec rsp_iov =3D { NULL, 0 }; + struct smb2_sess_setup_req *req =3D smb->request; =20 - /* Testing shows that buffer offset must be at location of Buffer[0] */ - req->SecurityBufferOffset =3D - cpu_to_le16(sizeof(struct smb2_sess_setup_req)); - req->SecurityBufferLength =3D cpu_to_le16(sess_data->iov[1].iov_len); + req->SecurityBufferLength =3D cpu_to_le16(smb->total_len - sizeof(*req)); + smb->sr_flags =3D CIFS_LOG_ERROR | CIFS_SESS_OP; =20 - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D sess_data->iov; - rqst.rq_nvec =3D 2; + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->total_len); =20 /* BB add code to build os and lm fields */ - rc =3D cifs_send_recv(sess_data->xid, sess_data->ses, - sess_data->server, - &rqst, - &sess_data->buf0_type, - CIFS_LOG_ERROR | CIFS_SESS_OP, &rsp_iov); - cifs_small_buf_release(sess_data->iov[0].iov_base); + rc =3D smb_send_recv_messages(sess_data->xid, sess_data->ses, sess_data->= server, + smb, CIFS_LOG_ERROR | CIFS_SESS_OP); + smb_clear_request(smb); if (rc =3D=3D 0) sess_data->ses->expired_pwd =3D false; else if ((rc =3D=3D -EACCES) || (rc =3D=3D -EKEYEXPIRED) || (rc =3D=3D -E= KEYREVOKED)) { @@ -1942,8 +1913,6 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_dat= a) sess_data->ses->expired_pwd =3D true; } =20 - memcpy(&sess_data->iov[0], &rsp_iov, sizeof(struct kvec)); - return rc; } =20 @@ -1978,16 +1947,18 @@ SMB2_sess_establish_session(struct SMB2_sess_data *= sess_data) static void SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) { - int rc; - struct cifs_ses *ses =3D sess_data->ses; + struct smb2_sess_setup_rsp *rsp =3D NULL; struct TCP_Server_Info *server =3D sess_data->server; struct cifs_spnego_msg *msg; + struct smb_message *smb =3D NULL; + struct cifs_ses *ses =3D sess_data->ses; struct key *spnego_key =3D NULL; - struct smb2_sess_setup_rsp *rsp =3D NULL; + void *key_buf =3D NULL; bool is_binding =3D false; + int rc =3D -ENOMEM; =20 - rc =3D SMB2_sess_alloc_buffer(sess_data); - if (rc) + smb =3D SMB2_create_session_request(sess_data); + if (!smb) goto out; =20 spnego_key =3D cifs_get_spnego_key(ses, server); @@ -2038,14 +2009,21 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) } memcpy(ses->auth_key.response, msg->data, msg->sesskey_len); =20 - sess_data->iov[1].iov_base =3D msg->data + msg->sesskey_len; - sess_data->iov[1].iov_len =3D msg->secblob_len; + /* Copy the key data here so that we can pass it to MSG_SPLICE_PAGES + * and the need to copy the whole message. + */ + key_buf =3D cifs_allocate_tx_buf(server, msg->secblob_len); + if (!key_buf) + goto out; + + memcpy(key_buf, msg->data + msg->sesskey_len, msg->secblob_len); + smb_add_segment_to_tx_buf(smb, key_buf, msg->secblob_len); =20 - rc =3D SMB2_sess_sendreceive(sess_data); + rc =3D SMB2_sess_sendreceive(sess_data, smb); if (rc) goto out_put_spnego_key; =20 - rsp =3D (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; + rsp =3D (struct smb2_sess_setup_rsp *)smb->response; /* keep session id and flags if binding */ if (!is_binding) { ses->Suid =3D le64_to_cpu(rsp->hdr.SessionId); @@ -2061,10 +2039,11 @@ SMB2_auth_kerberos(struct SMB2_sess_data *sess_data) ses->auth_key.response =3D NULL; ses->auth_key.len =3D 0; } + out: + smb_put_messages(smb); sess_data->result =3D rc; sess_data->func =3D NULL; - SMB2_sess_free_buffer(sess_data); } #else static void @@ -2082,14 +2061,13 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_= sess_data *sess_data); static void SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_sess_data *sess_data) { - int rc; - struct cifs_ses *ses =3D sess_data->ses; - struct TCP_Server_Info *server =3D sess_data->server; struct smb2_sess_setup_rsp *rsp =3D NULL; - unsigned char *ntlmssp_blob =3D NULL; + struct TCP_Server_Info *server =3D sess_data->server; + struct smb_message *smb =3D NULL; + struct cifs_ses *ses =3D sess_data->ses; bool use_spnego =3D false; /* else use raw ntlmssp */ - u16 blob_length =3D 0; bool is_binding =3D false; + int rc =3D -ENOMEM; =20 /* * If memory allocation is successful, caller of this function @@ -2102,13 +2080,12 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_ses= s_data *sess_data) } ses->ntlmssp->sesskey_per_smbsess =3D true; =20 - rc =3D SMB2_sess_alloc_buffer(sess_data); - if (rc) + smb =3D SMB2_create_session_request(sess_data); + if (!smb) goto out_err; =20 - rc =3D build_ntlmssp_smb3_negotiate_blob(&ntlmssp_blob, - &blob_length, ses, server, - sess_data->nls_cp); + rc =3D build_ntlmssp_smb3_negotiate_blob(smb, ses, server, + sess_data->nls_cp); if (rc) goto out; =20 @@ -2118,20 +2095,22 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_ses= s_data *sess_data) rc =3D -EOPNOTSUPP; goto out; } - sess_data->iov[1].iov_base =3D ntlmssp_blob; - sess_data->iov[1].iov_len =3D blob_length; =20 - rc =3D SMB2_sess_sendreceive(sess_data); - rsp =3D (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; + rc =3D SMB2_sess_sendreceive(sess_data, smb); + rsp =3D (struct smb2_sess_setup_rsp *)smb->response; =20 /* If true, rc here is expected and not an error */ - if (sess_data->buf0_type !=3D CIFS_NO_BUFFER && - rsp->hdr.Status =3D=3D STATUS_MORE_PROCESSING_REQUIRED) + if (smb->status =3D=3D STATUS_MORE_PROCESSING_REQUIRED) rc =3D 0; =20 if (rc) goto out; =20 + if (WARN_ON(!rsp)) { + rc =3D -EINVAL; + goto out_err; + } + u16 boff =3D le16_to_cpu(rsp->SecurityBufferOffset); =20 if (offsetof(struct smb2_sess_setup_rsp, Buffer) !=3D boff) { @@ -2157,14 +2136,13 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_ses= s_data *sess_data) } =20 out: - kfree_sensitive(ntlmssp_blob); - SMB2_sess_free_buffer(sess_data); if (!rc) { sess_data->result =3D 0; sess_data->func =3D SMB2_sess_auth_rawntlmssp_authenticate; return; } out_err: + smb_put_messages(smb); kfree_sensitive(ses->ntlmssp); ses->ntlmssp =3D NULL; sess_data->result =3D rc; @@ -2174,26 +2152,23 @@ SMB2_sess_auth_rawntlmssp_negotiate(struct SMB2_ses= s_data *sess_data) static void SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_sess_data *sess_data) { - int rc; + struct smb_message *smb; struct cifs_ses *ses =3D sess_data->ses; struct TCP_Server_Info *server =3D sess_data->server; struct smb2_sess_setup_req *req; struct smb2_sess_setup_rsp *rsp =3D NULL; - unsigned char *ntlmssp_blob =3D NULL; bool use_spnego =3D false; /* else use raw ntlmssp */ - u16 blob_length =3D 0; bool is_binding =3D false; + int rc =3D -ENOMEM; =20 - rc =3D SMB2_sess_alloc_buffer(sess_data); - if (rc) + smb =3D SMB2_create_session_request(sess_data); + if (!smb) goto out; =20 - req =3D (struct smb2_sess_setup_req *) sess_data->iov[0].iov_base; + req =3D smb->request; req->hdr.SessionId =3D cpu_to_le64(ses->Suid); =20 - rc =3D build_ntlmssp_auth_blob(&ntlmssp_blob, &blob_length, - ses, server, - sess_data->nls_cp); + rc =3D build_ntlmssp_auth_blob(smb, ses, server, sess_data->nls_cp); if (rc) { cifs_dbg(FYI, "build_ntlmssp_auth_blob failed %d\n", rc); goto out; @@ -2205,14 +2180,12 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_= sess_data *sess_data) rc =3D -EOPNOTSUPP; goto out; } - sess_data->iov[1].iov_base =3D ntlmssp_blob; - sess_data->iov[1].iov_len =3D blob_length; =20 - rc =3D SMB2_sess_sendreceive(sess_data); + rc =3D SMB2_sess_sendreceive(sess_data, smb); if (rc) goto out; =20 - rsp =3D (struct smb2_sess_setup_rsp *)sess_data->iov[0].iov_base; + rsp =3D (struct smb2_sess_setup_rsp *)smb->response; =20 spin_lock(&ses->ses_lock); is_binding =3D (ses->ses_status =3D=3D SES_GOOD); @@ -2241,8 +2214,6 @@ SMB2_sess_auth_rawntlmssp_authenticate(struct SMB2_se= ss_data *sess_data) } #endif out: - kfree_sensitive(ntlmssp_blob); - SMB2_sess_free_buffer(sess_data); kfree_sensitive(ses->ntlmssp); ses->ntlmssp =3D NULL; sess_data->result =3D rc; @@ -2300,7 +2271,6 @@ SMB2_sess_setup(const unsigned int xid, struct cifs_s= es *ses, sess_data->xid =3D xid; sess_data->ses =3D ses; sess_data->server =3D server; - sess_data->buf0_type =3D CIFS_NO_BUFFER; sess_data->nls_cp =3D (struct nls_table *) nls_cp; sess_data->previous_session =3D ses->Suid; From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 A59AA4E3792 for ; Tue, 19 May 2026 10:24:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186273; cv=none; b=HjI8k8p93OlUaMvJP3MxR4ZdXgBIqIhjedIvL47aR0LpR7mU+8FmQgih/LCA+dkwckLU4D9kA1JpSJ3D24cCDL0hrS+2aTB63ide3fOi4oMKWdNAv6RxDwCuD0vIDghvC0STmy8nVTtR95IL6u+d59VbVRPHtCYLiBONFXdigJw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186273; c=relaxed/simple; bh=3FEUUFTwoFMyfy/lg9qZ/s0+P0PCw5O4toikTojGW5o=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Tl3OC/hGwTFKryJwifqV0/HcC5x35cPiqBf+e3+hnXbXnLVIin6X/YqiK6XJo4LKEeESCY9Lwzz+M3AMqAE4TXmpe3C3cSe0jU7rYTK/StdbNDQFH2cazc3lKczCOlX0kCj4z1uWwXCbsN3kxT1PAxsFnnFWLvM4Z17q4UdRPsM= 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=DsXE0L0K; arc=none smtp.client-ip=170.10.133.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="DsXE0L0K" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186270; 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=mCeork960z2+9owO0TXHybI/uw7l2vxljckiO5ink50=; b=DsXE0L0KvnTMx2lLafoCEE6IBLUnmyV9IFx4gbeRrrwElSkeaOVmnFCtljlV9GET/Ai+Gh Rh3v/nmcCSvJYyez91/yeuKXZQsmUi0spGaqqVfib/H9sVGvwf8FRBmqPabeg6MCOmorZb BkQuDQHIgFSOgWOM6rVcyoQATiBQfNE= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-694-05oFebFIPf6Qu26JNQ56_Q-1; Tue, 19 May 2026 06:24:26 -0400 X-MC-Unique: 05oFebFIPf6Qu26JNQ56_Q-1 X-Mimecast-MFC-AGG-ID: 05oFebFIPf6Qu26JNQ56_Q_1779186264 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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6B682195609F; Tue, 19 May 2026 10:24:24 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 410AF1956053; Tue, 19 May 2026 10:24:21 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 28/36] cifs: Convert SMB2 Logoff request Date: Tue, 19 May 2026 11:21:46 +0100 Message-ID: <20260519102158.592165-29-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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/smb2pdu.c | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 4dd4f2de39f4..082838e9c9b5 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2298,15 +2298,10 @@ SMB2_sess_setup(const unsigned int xid, struct cifs= _ses *ses, int SMB2_logoff(const unsigned int xid, struct cifs_ses *ses) { - struct smb_rqst rqst; - struct smb2_logoff_req *req; /* response is also trivial struct */ - int rc =3D 0; struct TCP_Server_Info *server; - int flags =3D 0; - unsigned int total_len; - struct kvec iov[1]; - struct kvec rsp_iov; - int resp_buf_type; + struct smb2_logoff_req *req; /* response is also trivial struct */ + struct smb_message *smb =3D NULL; + int rc =3D 0, flags =3D 0; =20 cifs_dbg(FYI, "disconnect session %p\n", ses); =20 @@ -2322,10 +2317,11 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses= *ses) } spin_unlock(&ses->chan_lock); =20 - rc =3D smb2_plain_req_init(SMB2_LOGOFF, NULL, ses->server, - (void **) &req, &total_len); - if (rc) - return rc; + smb =3D smb2_create_request(SMB2_LOGOFF, server, NULL, + sizeof(*req), sizeof(*req), 0, 0); + if (!smb) + return -ENOMEM; + req =3D smb->request; =20 /* since no tcon, smb2_init can not do this, so do here */ req->hdr.SessionId =3D cpu_to_le64(ses->Suid); @@ -2335,23 +2331,17 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses= *ses) else if (server->sign) req->hdr.Flags |=3D SMB2_FLAGS_SIGNED; =20 - flags |=3D CIFS_NO_RSP_BUF; - - iov[0].iov_base =3D (char *)req; - iov[0].iov_len =3D total_len; - - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 1; + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); =20 - rc =3D cifs_send_recv(xid, ses, ses->server, - &rqst, &resp_buf_type, flags, &rsp_iov); - cifs_small_buf_release(req); + smb->sr_flags =3D flags; + rc =3D smb_send_recv_messages(xid, ses, ses->server, smb, flags); /* * No tcon so can't do * cifs_stats_inc(&tcon->stats.smb2_stats.smb2_com_fail[SMB2...]); */ =20 + smb_put_messages(smb); smb2_session_already_dead: return rc; } From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 2BAF03F0A98 for ; Tue, 19 May 2026 10:24:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186278; cv=none; b=Bsc8cvr0lYP4mdx2Vc66mBwp6Wmhr6/0cO5XBU/hOn8RbANOdN5jNsuX11s5IY3jlnA5okFObVlaljGgqAxnmlZAqu10flfpflDSifEMXbXdaG8JWdpPjbjZlvgd/JKku/vZyA5/QcJ/aBYV4zGHlRiXtBk4inbEo/sAjk8lAmY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186278; c=relaxed/simple; bh=gfaJzP289xQ4kVltCiQEPXCysPdOpM4vpGCDTkaZPTM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=I8KZwwRbnPj6q4fswS+hAUUXp4WT7U1Xp7BSKlImHm607r+RgqQbhKQIvxkL6xsTQlvwnhXr0GduEawLzuyHCv5FvSBRpvRkOCDZFdHU7uUTRhGfdNQ7hJYeGi2PG/4elo1yw6hH7xPygOElr0rOUFS/kcj5aZ0A2xuDaxN/d5E= 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=buzRiDQO; arc=none smtp.client-ip=170.10.133.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="buzRiDQO" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186276; 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=REhYKVbaqGbxNcyNXrV0J0+0n1UmD1ysJbs6hLY9zMU=; b=buzRiDQOdtINcVws+yPnHv+JcOHiARi7/+nier/RT4f51OO6+AmejZdkMV07yCiQODPxos GVqUA8G/vOQA2dV46qelFRb3z66899la9mDMixiWtyGHPYrmK0RNyVJgoMkHQJj8DbEz2l 1GUzsTjCdcgxzNOAShVtadS7tvIv1KA= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-56-jOkhW4KOOyiXzBGFFZBWHg-1; Tue, 19 May 2026 06:24:31 -0400 X-MC-Unique: jOkhW4KOOyiXzBGFFZBWHg-1 X-Mimecast-MFC-AGG-ID: jOkhW4KOOyiXzBGFFZBWHg_1779186269 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 4333019560A2; Tue, 19 May 2026 10:24:29 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1CA9C18001E9; Tue, 19 May 2026 10:24:25 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 29/36] cifs: Convert SMB2 Tree Connect request Date: Tue, 19 May 2026 11:21:47 +0100 Message-ID: <20260519102158.592165-30-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 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/smb2pdu.c | 76 ++++++++++++++++------------------------- 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 082838e9c9b5..ea4108669e6c 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2365,57 +2365,44 @@ int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tree, struct cifs_tcon *tcon, const struct nls_table *cp) { - struct smb_rqst rqst; + struct TCP_Server_Info *server =3D cifs_pick_channel(ses); struct smb2_tree_connect_req *req; struct smb2_tree_connect_rsp *rsp =3D NULL; - struct kvec iov[2]; - struct kvec rsp_iov =3D { NULL, 0 }; - int rc =3D 0; - int resp_buftype; - int unc_path_len; - __le16 *unc_path =3D NULL; + struct smb_message *smb =3D NULL; + int unc_path_size; int flags =3D 0; - unsigned int total_len; - struct TCP_Server_Info *server =3D cifs_pick_channel(ses); + int rc =3D 0; =20 cifs_dbg(FYI, "TCON\n"); =20 if (!server || !tree) return smb_EIO(smb_eio_trace_null_pointers); =20 - unc_path =3D kmalloc(MAX_SHARENAME_LENGTH * 2, GFP_KERNEL); - if (unc_path =3D=3D NULL) - return -ENOMEM; - - unc_path_len =3D cifs_strtoUTF16(unc_path, tree, strlen(tree), cp); - if (unc_path_len <=3D 0) { - kfree(unc_path); - return -EINVAL; - } - unc_path_len *=3D 2; + unc_path_size =3D cifs_size_strtoUTF16(tree, INT_MAX, cp); =20 /* SMB2 TREE_CONNECT request must be called with TreeId =3D=3D 0 */ tcon->tid =3D 0; atomic_set(&tcon->num_remote_opens, 0); - rc =3D smb2_plain_req_init(SMB2_TREE_CONNECT, tcon, server, - (void **) &req, &total_len); - if (rc) { - kfree(unc_path); - return rc; - } + + smb =3D smb2_create_request(SMB2_TREE_CONNECT, server, tcon, + sizeof(*req), sizeof(*req) + unc_path_size, 0, + SMB2_REQ_DYNAMIC); + if (!smb) + return -ENOMEM; + req =3D smb->request; =20 if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - iov[0].iov_base =3D (char *)req; - /* 1 for pad */ - iov[0].iov_len =3D total_len; - /* Testing shows that buffer offset must be at location of Buffer[0] */ - req->PathOffset =3D cpu_to_le16(sizeof(struct smb2_tree_connect_req)); - req->PathLength =3D cpu_to_le16(unc_path_len); - iov[1].iov_base =3D unc_path; - iov[1].iov_len =3D unc_path_len; + req->PathOffset =3D cpu_to_le16(smb->ext_offset); + req->PathLength =3D cpu_to_le16(unc_path_size); + + rc =3D cifs_strtoUTF16(smb->request + smb->ext_offset, tree, strlen(tree)= , cp); + if (rc <=3D 0) { + rc =3D -EINVAL; + goto tcon_exit; + } =20 /* * 3.11 tcon req must be signed if not encrypted. See MS-SMB2 3.2.4.1.1 @@ -2429,22 +2416,21 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *= ses, const char *tree, ((ses->user_name !=3D NULL) || (ses->sectype =3D=3D Kerberos))) req->hdr.Flags |=3D SMB2_FLAGS_SIGNED; =20 - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 2; - /* Need 64 for max size write so ask for more in case not there yet */ if (server->credits >=3D server->max_credits) req->hdr.CreditRequest =3D cpu_to_le16(0); else req->hdr.CreditRequest =3D cpu_to_le16( - min_t(int, server->max_credits - - server->credits, 64)); + min_t(int, server->max_credits - server->credits, 64)); =20 - rc =3D cifs_send_recv(xid, ses, server, - &rqst, &resp_buftype, flags, &rsp_iov); - cifs_small_buf_release(req); - rsp =3D (struct smb2_tree_connect_rsp *)rsp_iov.iov_base; + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); + + smb->sr_flags =3D flags; + rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); + smb_clear_request(smb); + + rsp =3D (struct smb2_tree_connect_rsp *)smb->response; trace_smb3_tcon(xid, tcon->tid, ses->Suid, tree, rc); if ((rc !=3D 0) || (rsp =3D=3D NULL)) { cifs_stats_fail_inc(tcon, SMB2_TREE_CONNECT_HE); @@ -2491,9 +2477,7 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *se= s, const char *tree, if (tcon->share_flags & SMB2_SHAREFLAG_ISOLATED_TRANSPORT) server->nosharesock =3D true; tcon_exit: - - free_rsp_buf(resp_buftype, rsp); - kfree(unc_path); + smb_put_messages(smb); return rc; =20 tcon_error_exit: From nobody Mon May 25 02:42:24 2026 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 C3BD83F7A99 for ; Tue, 19 May 2026 10:24:39 +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=1779186281; cv=none; b=X6QNG9C9/JQqf3EhzPmGj9F4KYdCa79QGlN+15AJxQXlF2TcoEvBj0g+U+fR5CHueQqc6HDmzuKzltt/K+t6K3PZypyBlEyotmT++Mcct0lGrVB7KwFmBK68+wjvGtcIFKZoLMvBXTKoPVnUey3a5gcvFT9J1Tk1kRWMaCHuZZE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186281; c=relaxed/simple; bh=6JHO7zGoYUv42IdTqmkY851r6tP6oZ8F9UnTfS+t70g=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=BtvQu1jpvFsPSbuRxKBZkhuTHtRAN+M/DINAaLO/f5L/f+J1SmEr7/8vH/t/0wWumwX9WbEu9bA8J5Dk1+CanF6jr41d/j6WWx7srnnoODQhaWr6yCOBRPwLi7G0vRPa5YONRkNH/yu/v4UbUPkJObxU4FFaakgaWTQtoeEixSY= 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=dj6Sq+t7; 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="dj6Sq+t7" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186278; 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=j1YgjwJ80TNUQ6YOR+omfLsLBjy7Grl2VNzSblRzWrw=; b=dj6Sq+t7O1KeNVBvAgn2gQq1iGZAlB/J/kGsullAw89sDsE6noqsMjIhDmh3MU7W7Mquz7 ItSV7EswJyF9zug7evplR/TnIIJlijkfZHJHkxodxX3cbtndU3PsHPEpcz6+eTS5T39haZ Hlp5/mlAmXDawpzFk/bcyfmX+cVr7W0= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-217-LocKuVccNHyw2eqB6ifX0Q-1; Tue, 19 May 2026 06:24:35 -0400 X-MC-Unique: LocKuVccNHyw2eqB6ifX0Q-1 X-Mimecast-MFC-AGG-ID: LocKuVccNHyw2eqB6ifX0Q_1779186274 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 1BAB8195609D; Tue, 19 May 2026 10:24:34 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E8CF71800357; Tue, 19 May 2026 10:24:30 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 30/36] cifs: Convert SMB2 Tree Disconnect request Date: Tue, 19 May 2026 11:21:48 +0100 Message-ID: <20260519102158.592165-31-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 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/smb2pdu.c | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index ea4108669e6c..f0b39c77f8ae 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2489,16 +2489,12 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *= ses, const char *tree, int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon) { - struct smb_rqst rqst; struct smb2_tree_disconnect_req *req; /* response is trivial */ - int rc =3D 0; + struct smb_message *smb =3D NULL; struct cifs_ses *ses =3D tcon->ses; struct TCP_Server_Info *server =3D cifs_pick_channel(ses); int flags =3D 0; - unsigned int total_len; - struct kvec iov[1]; - struct kvec rsp_iov; - int resp_buf_type; + int rc =3D 0; =20 cifs_dbg(FYI, "Tree Disconnect\n"); =20 @@ -2516,33 +2512,29 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon = *tcon) =20 invalidate_all_cached_dirs(tcon, true); =20 - rc =3D smb2_plain_req_init(SMB2_TREE_DISCONNECT, tcon, server, - (void **) &req, - &total_len); - if (rc) - return rc; + smb =3D smb2_create_request(SMB2_TREE_DISCONNECT, server, tcon, + sizeof(*req), sizeof(*req), 0, + SMB2_REQ_DYNAMIC); + if (!smb) + return -ENOMEM; + req =3D smb->request; =20 if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - flags |=3D CIFS_NO_RSP_BUF; - - iov[0].iov_base =3D (char *)req; - iov[0].iov_len =3D total_len; - - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 1; + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); =20 - rc =3D cifs_send_recv(xid, ses, server, - &rqst, &resp_buf_type, flags, &rsp_iov); - cifs_small_buf_release(req); + smb->sr_flags =3D flags; + rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); + smb_clear_request(smb); if (rc) { cifs_stats_fail_inc(tcon, SMB2_TREE_DISCONNECT_HE); trace_smb3_tdis_err(xid, tcon->tid, ses->Suid, rc); } trace_smb3_tdis_done(xid, tcon->tid, ses->Suid); =20 + smb_put_messages(smb); return rc; } From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 7CDE44F798B for ; Tue, 19 May 2026 10:24:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186287; cv=none; b=fJvU0Y1qqED/1IrpMEQG8DsRom+tZRASrwaeJN9alfNs0Bv393hG046LatTW5hA0qRcphyDaAnmZrYcAb4VyQClUiwepvqUXZHxlIcukSMt+mtoJu0GXeQd/wsWMrAU0PrYFv/lPkKdnzhCBm+0HFNTw0MSa5VEYqrmgC5jS56k= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186287; c=relaxed/simple; bh=tnB03R0zqjSoco4Zsq6FYVHFFti6o0ay+Oa8IYZGGTk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RhhZ1BuVTiTd8MOaB+3roXweXJunPn6/kqlmy8ypGFc7dcu6j6Goq017VDV80QgGtz4U7tOqnabvcKXsSjVCyNH1Y6ZLxI1Z0xOygK+woyHD/j/bg6f0/Vz+7uznkgrTbH3KFN4HznwkicfBSKVX8p2GaAL9MN8sLhTpUIUFkPk= 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=bzeK9yuC; arc=none smtp.client-ip=170.10.133.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="bzeK9yuC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186284; 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=bfHGEtE5AWzmVMEaBF0Gut3ba6+P3iVY14LGItT4uII=; b=bzeK9yuCjKzxgNOmv8o6HShwEYalQ8I/cKHzolQkotGlB+Z9d6Fa1Z4716y1LaD0OEYm0f zrozhBuKuL0tQZJ3Pg9NJdd6reCudHlX4Vg4WVLszMsX1HOEwjL2nkxTW5LiPUqMc5vIDe TmM0nNqa0V0Mx3JVoWzcaYFdm2FLTc4= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-332-WERaetEpMJq161vot8g0aA-1; Tue, 19 May 2026 06:24:40 -0400 X-MC-Unique: WERaetEpMJq161vot8g0aA-1 X-Mimecast-MFC-AGG-ID: WERaetEpMJq161vot8g0aA_1779186279 Received: from mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.4]) (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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id D88141956095; Tue, 19 May 2026 10:24:38 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id AEA2530001A2; Tue, 19 May 2026 10:24:35 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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/36] cifs: Convert SMB2 Read request Date: Tue, 19 May 2026 11:21:49 +0100 Message-ID: <20260519102158.592165-32-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.4 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/cifsglob.h | 1 - fs/smb/client/smb2pdu.c | 232 +++++++++++++++++++-------------------- 2 files changed, 113 insertions(+), 120 deletions(-) diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index 9aa9eb72ec6b..ed7311637d81 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -1455,7 +1455,6 @@ struct cifs_io_subrequest { bool replay; unsigned int retries; /* number of retries so far */ unsigned int cur_sleep; /* time to sleep before replay */ - struct kvec iov[2]; struct TCP_Server_Info *server; #ifdef CONFIG_CIFS_SMB_DIRECT struct smbdirect_mr_io *mr; diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index f0b39c77f8ae..b2140cb1662e 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -4757,48 +4757,62 @@ static inline bool smb3_use_rdma_offload(struct cif= s_io_parms *io_parms) * To form a chain of read requests, any read requests after the first sho= uld * have the end_of_chain boolean set to true. */ -static int -smb2_new_read_req(void **buf, unsigned int *total_len, - struct cifs_io_parms *io_parms, struct cifs_io_subrequest *rdata, - unsigned int remaining_bytes, int request_type) +static struct smb_message * +smb2_new_read_req(struct cifs_io_parms *io_parms, struct cifs_io_subreques= t *rdata, + unsigned int remaining_bytes, int request_type) { - int rc =3D -EACCES; - struct smb2_read_req *req =3D NULL; - struct smb2_hdr *shdr; struct TCP_Server_Info *server =3D io_parms->server; + struct smb2_read_req *req; + struct smb_message *smb; + struct smb2_hdr *shdr; + size_t proto_len =3D sizeof(*req) + 1; =20 - rc =3D smb2_plain_req_init(SMB2_READ, io_parms->tcon, server, - (void **) &req, total_len); - if (rc) - return rc; + if (!server) + return ERR_PTR(-ECONNABORTED); =20 - if (server =3D=3D NULL) - return -ECONNABORTED; +#ifdef CONFIG_CIFS_SMB_DIRECT + bool rdma_offload =3D rdata && smb3_use_rdma_offload(io_parms); + + if (rdma_offload) + proto_len +=3D sizeof(struct smbdirect_buffer_descriptor_v1); +#endif =20 + smb =3D smb2_create_request(SMB2_READ, server, io_parms->tcon, + sizeof(*req), proto_len, 0, + SMB2_REQ_DYNAMIC); + if (!smb) + return ERR_PTR(-ENOMEM); + req =3D smb->request; shdr =3D &req->hdr; - shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms->pid); =20 - req->PersistentFileId =3D io_parms->persistent_fid; - req->VolatileFileId =3D io_parms->volatile_fid; - req->ReadChannelInfoOffset =3D 0; /* reserved */ - req->ReadChannelInfoLength =3D 0; /* reserved */ - req->Channel =3D 0; /* reserved */ - req->MinimumCount =3D 0; - req->Length =3D cpu_to_le32(io_parms->length); - req->Offset =3D cpu_to_le64(io_parms->offset); + if (rdata) { + smb->subreq =3D rdata; + smb->credits =3D rdata->credits; + } =20 - trace_smb3_read_enter(rdata ? rdata->rreq->debug_id : 0, - rdata ? rdata->subreq.debug_index : 0, + shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms->pid); + req->PersistentFileId =3D io_parms->persistent_fid; + req->VolatileFileId =3D io_parms->volatile_fid; + req->ReadChannelInfoOffset =3D 0; /* reserved */ + req->ReadChannelInfoLength =3D 0; /* reserved */ + req->Channel =3D 0; /* reserved */ + req->MinimumCount =3D 0; + req->Length =3D cpu_to_le32(io_parms->length); + req->Offset =3D cpu_to_le64(io_parms->offset); + + trace_smb3_read_enter(smb->credits.rreq_debug_id, + smb->credits.rreq_debug_index, rdata ? rdata->xid : 0, io_parms->persistent_fid, io_parms->tcon->tid, io_parms->tcon->ses->Suid, io_parms->offset, io_parms->length); + #ifdef CONFIG_CIFS_SMB_DIRECT /* * If we want to do a RDMA write, fill in and append * smbdirect_buffer_descriptor_v1 to the end of read request */ - if (rdata && smb3_use_rdma_offload(io_parms)) { + if (rdma_offload) { struct smbdirect_buffer_descriptor_v1 *v1; struct iov_iter iter; bool need_invalidate =3D server->dialect =3D=3D SMB30_PROT_ID; @@ -4808,8 +4822,10 @@ smb2_new_read_req(void **buf, unsigned int *total_le= n, rdata->subreq.content.offset, rdata->subreq.len); rdata->mr =3D smbd_register_mr(server->smbd_conn, &iter, true, need_invalidate); - if (!rdata->mr) - return -EAGAIN; + if (!rdata->mr) { + smb_put_messages(smb); + return ERR_PTR(-EAGAIN); + } =20 req->Channel =3D SMB2_CHANNEL_RDMA_V1_INVALIDATE; if (need_invalidate) @@ -4820,36 +4836,28 @@ smb2_new_read_req(void **buf, unsigned int *total_l= en, cpu_to_le16(sizeof(struct smbdirect_buffer_descriptor_v1)); v1 =3D (struct smbdirect_buffer_descriptor_v1 *) &req->Buffer[0]; smbd_mr_fill_buffer_descriptor(rdata->mr, v1); - - *total_len +=3D sizeof(*v1); } #endif - if (request_type & CHAINED_REQUEST) { - if (!(request_type & END_OF_CHAIN)) { - /* next 8-byte aligned request */ - *total_len =3D ALIGN8(*total_len); - shdr->NextCommand =3D cpu_to_le32(*total_len); - } else /* END_OF_CHAIN */ - shdr->NextCommand =3D 0; - if (request_type & RELATED_REQUEST) { - shdr->Flags |=3D SMB2_FLAGS_RELATED_OPERATIONS; - /* - * Related requests use info from previous read request - * in chain. - */ - shdr->SessionId =3D cpu_to_le64(0xFFFFFFFFFFFFFFFF); - shdr->Id.SyncId.TreeId =3D cpu_to_le32(0xFFFFFFFF); - req->PersistentFileId =3D (u64)-1; - req->VolatileFileId =3D (u64)-1; - } + + if ((request_type & CHAINED_REQUEST) && + (request_type & RELATED_REQUEST)) { + shdr->Flags |=3D SMB2_FLAGS_RELATED_OPERATIONS; + /* + * Related requests use info from previous read request in + * chain. + */ + shdr->SessionId =3D cpu_to_le64(0xFFFFFFFFFFFFFFFF); + shdr->Id.SyncId.TreeId =3D cpu_to_le32(0xFFFFFFFF); + req->PersistentFileId =3D (u64)-1; + req->VolatileFileId =3D (u64)-1; } + if (remaining_bytes > io_parms->length) req->RemainingBytes =3D cpu_to_le32(remaining_bytes); else req->RemainingBytes =3D 0; =20 - *buf =3D req; - return rc; + return smb; } =20 static void @@ -5004,13 +5012,12 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) { struct netfs_io_subrequest *subreq =3D &rdata->subreq; struct TCP_Server_Info *server; + struct smb2_read_req *req; struct smb_message *smb; - struct smb2_hdr *shdr; struct cifs_tcon *tcon =3D tlink_tcon(rdata->req->cfile->tlink); - unsigned int total_len; - void *buf; + struct smb2_hdr *shdr; int credit_request; - int rc, flags =3D 0; + int rc; =20 cifs_dbg(FYI, "%s: offset=3D%llu bytes=3D%zu\n", __func__, subreq->start, subreq->len); @@ -5029,30 +5036,19 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) .pid =3D rdata->req->pid, }; =20 - smb =3D smb_message_alloc(smb2_command_trace_read, GFP_NOFS); - if (!smb) { - rc =3D -ENOMEM; - goto out; - } - - rc =3D smb2_new_read_req(&buf, &total_len, &io_parms, rdata, 0, 0); - if (rc) { - mempool_free(smb, &smb_message_pool); + smb =3D smb2_new_read_req(&io_parms, rdata, 0, 0); + if (IS_ERR(smb)) { + rc =3D PTR_ERR(smb); goto out; } + req =3D smb->request; + shdr =3D &req->hdr; =20 if (smb3_encryption_required(io_parms.tcon)) - flags |=3D CIFS_TRANSFORM_REQ; + smb->sr_flags |=3D CIFS_TRANSFORM_REQ; =20 - rdata->iov[0].iov_base =3D buf; - rdata->iov[0].iov_len =3D total_len; rdata->result =3D 0; =20 - smb->rqst.rq_iov =3D rdata->iov; - smb->rqst.rq_nvec =3D 1; - smb->command =3D SMB2_READ; - smb->request =3D buf; - smb->total_len =3D total_len; smb->callback =3D smb2_readv_callback; smb->subreq =3D rdata; smb->copy_to_bufs =3D true; @@ -5061,19 +5057,19 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) rdata->subreq.content.bvecq, rdata->subreq.content.slot, rdata->subreq.content.offset, rdata->subreq.len); =20 - shdr =3D (struct smb2_hdr *)smb->request; - if (rdata->replay) { /* Back-off before retry */ if (rdata->cur_sleep) msleep(rdata->cur_sleep); - smb2_set_replay(server, &smb->rqst); + smb2_set_replay_smb(server, smb); } =20 if (rdata->credits.value > 0) { - shdr->CreditCharge =3D cpu_to_le16(DIV_ROUND_UP(io_parms.length, - SMB2_MAX_BUFFER_SIZE)); - credit_request =3D le16_to_cpu(shdr->CreditCharge) + 8; + unsigned int credit_charge =3D + DIV_ROUND_UP(io_parms.length, SMB2_MAX_BUFFER_SIZE); + + shdr->CreditCharge =3D cpu_to_le16(credit_charge); + credit_request =3D credit_charge + 8; if (server->credits >=3D server->max_credits) shdr->CreditRequest =3D cpu_to_le16(0); else @@ -5085,10 +5081,14 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) if (rc) goto async_readv_out; =20 - flags |=3D CIFS_HAS_CREDITS; + smb->credits.value =3D rdata->credits.value; + smb->sr_flags |=3D CIFS_HAS_CREDITS; } =20 - rc =3D cifs_call_async(server, smb, flags, &rdata->credits); + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); + + rc =3D cifs_call_async(server, smb, smb->sr_flags, &rdata->credits); if (rc) { cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); trace_smb3_read_err(rdata->rreq->debug_id, @@ -5101,8 +5101,7 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) } =20 async_readv_out: - cifs_small_buf_release(buf); - + smb_put_messages(smb); out: /* if the send error is retryable, let netfs know about it */ if (is_replayable_error(rc) && @@ -5113,7 +5112,6 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) __set_bit(NETFS_SREQ_NEED_RETRY, &rdata->subreq.flags); } =20 - smb_put_messages(smb); return rc; } =20 @@ -5121,63 +5119,56 @@ int SMB2_read(const unsigned int xid, struct cifs_io_parms *io_parms, unsigned int *nbytes, char **buf, int *buf_type) { - struct smb_rqst rqst; - int resp_buftype, rc; - struct smb2_read_req *req =3D NULL; struct smb2_read_rsp *rsp =3D NULL; - struct kvec iov[1]; - struct kvec rsp_iov; - unsigned int total_len; - int flags =3D CIFS_LOG_ERROR; + struct smb_message *smb; struct cifs_ses *ses =3D io_parms->tcon->ses; + int rc; =20 if (!io_parms->server) io_parms->server =3D cifs_pick_channel(io_parms->tcon->ses); =20 *nbytes =3D 0; - rc =3D smb2_new_read_req((void **)&req, &total_len, io_parms, NULL, 0, 0); - if (rc) - return rc; + smb =3D smb2_new_read_req(io_parms, NULL, 0, 0); + if (IS_ERR(smb)) + return PTR_ERR(smb); =20 + smb->sr_flags =3D CIFS_LOG_ERROR; if (smb3_encryption_required(io_parms->tcon)) - flags |=3D CIFS_TRANSFORM_REQ; + smb->sr_flags |=3D CIFS_TRANSFORM_REQ; =20 - iov[0].iov_base =3D (char *)req; - iov[0].iov_len =3D total_len; + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); =20 - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D 1; + rc =3D smb_send_recv_messages(xid, ses, io_parms->server, smb, smb->sr_fl= ags); + smb_clear_request(smb); =20 - rc =3D cifs_send_recv(xid, ses, io_parms->server, - &rqst, &resp_buftype, flags, &rsp_iov); - rsp =3D (struct smb2_read_rsp *)rsp_iov.iov_base; + rsp =3D (struct smb2_read_rsp *)smb->response; =20 if (rc) { if (rc !=3D -ENODATA) { cifs_stats_fail_inc(io_parms->tcon, SMB2_READ_HE); cifs_dbg(VFS, "Send error in read =3D %d\n", rc); trace_smb3_read_err(0, 0, xid, - req->PersistentFileId, + io_parms->persistent_fid, io_parms->tcon->tid, ses->Suid, io_parms->offset, io_parms->length, rc); - } else + } else { trace_smb3_read_done(0, 0, xid, - req->PersistentFileId, io_parms->tcon->tid, + io_parms->persistent_fid, + io_parms->tcon->tid, ses->Suid, io_parms->offset, 0); - free_rsp_buf(resp_buftype, rsp_iov.iov_base); - cifs_small_buf_release(req); - return rc =3D=3D -ENODATA ? 0 : rc; - } else - trace_smb3_read_done(0, 0, xid, - req->PersistentFileId, - io_parms->tcon->tid, ses->Suid, - io_parms->offset, io_parms->length); + rc =3D 0; + } + goto out; + } =20 - cifs_small_buf_release(req); + trace_smb3_read_done(0, 0, xid, + io_parms->persistent_fid, + io_parms->tcon->tid, ses->Suid, + io_parms->offset, io_parms->length); =20 - *nbytes =3D le32_to_cpu(rsp->DataLength); + *nbytes =3D smb->resp_data_len; if ((*nbytes > CIFS_MAX_MSGSIZE) || (*nbytes > io_parms->length)) { cifs_dbg(FYI, "bad length %d for count %d\n", @@ -5188,15 +5179,18 @@ SMB2_read(const unsigned int xid, struct cifs_io_pa= rms *io_parms, } =20 if (*buf) { - memcpy(*buf, (char *)rsp + rsp->DataOffset, *nbytes); - free_rsp_buf(resp_buftype, rsp_iov.iov_base); - } else if (resp_buftype !=3D CIFS_NO_BUFFER) { - *buf =3D rsp_iov.iov_base; - if (resp_buftype =3D=3D CIFS_SMALL_BUFFER) + memcpy(*buf, (char *)rsp + smb->resp_data_offset, *nbytes); + } else if (smb->response) { + *buf =3D smb->response; + smb->response =3D NULL; + if (!smb->large_buf) *buf_type =3D CIFS_SMALL_BUFFER; - else if (resp_buftype =3D=3D CIFS_LARGE_BUFFER) + else *buf_type =3D CIFS_LARGE_BUFFER; } + +out: + smb_put_messages(smb); return rc; } From nobody Mon May 25 02:42:24 2026 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 5955823392D for ; Tue, 19 May 2026 10:24:49 +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=1779186290; cv=none; b=sf8LG4DceZO/wVAA6Q5U7bkOx7tgEO1W8uatGeQlCYfHlPrOoz+HMGNAW7m2L1xTrqBXOGobQiavwRAERnWcUgFIziSP1txRhhwLZLZOo9+QfuEWdjaHC2JxuaBxNFDBfFfYXaj5kI/+HnDPdSWpn0BwYxR2RgurXs8X9iSE6tQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186290; c=relaxed/simple; bh=Ai+FRz+YxmnewnzFGBNef8/oJSKhDE1wS40kGQ0amQk=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rysOQ7rjXCwYjqh4k9lotL0bOZqwvAaZk5Q8yR9KCxTLGquOIiCzDpnkDZdP5LNNUYArBhQ/1uCemMXZqAtz/GyBXacAjks0/tqKx3Y4mNu6RnvfdnHXwbJdz2kzqhG0TOAJIyP5oCwy+2FcjrCkqjsoaBPdYiw61kZ4mxgFksE= 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=VTFIJFHT; 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="VTFIJFHT" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186288; 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=pjW4/e4KdjsDicDU4d5mNd29WjlSmju5BWwQwG8iuhI=; b=VTFIJFHTVuRtS1qEm6EA7EmOgOHxlbTtJ0Oaw7Y8Cs8xu3UuF7vU/L4XcNgXtcC7EB3d9h U5II1xh+J1QSUkQSFeujArnoxVAfmcrEA2BsovlWcDPyhnyDVwOeS18hR2xSN08GjPGXti w+nOBqPJF7HqTytBb48HggAv7JCUsYs= Received: from mx-prod-mc-05.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-637-__CM1I27PL6m_3Bad0VSNQ-1; Tue, 19 May 2026 06:24:45 -0400 X-MC-Unique: __CM1I27PL6m_3Bad0VSNQ-1 X-Mimecast-MFC-AGG-ID: __CM1I27PL6m_3Bad0VSNQ_1779186283 Received: from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111]) (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-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id B2D56195608D; Tue, 19 May 2026 10:24:43 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 888211800352; Tue, 19 May 2026 10:24:40 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 32/36] cifs: Convert SMB2 Write request Date: Tue, 19 May 2026 11:21:50 +0100 Message-ID: <20260519102158.592165-33-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.111 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/smb2pdu.c | 69 +++++++++++++++++++++-------------------- 1 file changed, 35 insertions(+), 34 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index b2140cb1662e..b434aaf15dba 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -5338,10 +5338,8 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) struct smb2_hdr *shdr; struct cifs_tcon *tcon =3D tlink_tcon(wdata->req->cfile->tlink); struct TCP_Server_Info *server =3D wdata->server; - struct kvec iov[1]; - unsigned int total_len, xid =3D wdata->xid; - int credit_request; - int rc =3D -EACCES, flags =3D 0; + unsigned int xid =3D wdata->xid; + int rc =3D -EACCES; =20 /* * in future we may get cifs_io_parms passed in from the caller, @@ -5357,41 +5355,39 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) .pid =3D wdata->req->pid, }; =20 - smb =3D smb_message_alloc(smb2_command_trace_write, GFP_NOFS); + size_t proto_len =3D sizeof(*req); + +#ifdef CONFIG_CIFS_SMB_DIRECT + bool rdma_offload =3D smb3_use_rdma_offload(&io_parms); + + if (rdma_offload) + proto_len +=3D sizeof(struct smbdirect_buffer_descriptor_v1); +#endif + + smb =3D smb2_create_request(SMB2_WRITE, server, tcon, + sizeof(*req), proto_len, wdata->subreq.len, + SMB2_REQ_DYNAMIC); if (!smb) { rc =3D -ENOMEM; goto out; } + req =3D smb->request; + shdr =3D &req->hdr; =20 - rc =3D smb2_plain_req_init(SMB2_WRITE, tcon, server, - (void **) &req, &total_len); - if (rc) { - mempool_free(smb, &smb_message_pool); - goto out; - } - - iov[0].iov_len =3D total_len; - iov[0].iov_base =3D (char *)req; - total_len +=3D wdata->subreq.len; - - smb->rqst.rq_iov =3D iov; - smb->rqst.rq_nvec =3D 1; - smb->command =3D SMB2_WRITE; + smb->subreq =3D wdata; + smb->credits =3D wdata->credits; smb->request =3D req; - smb->total_len =3D total_len; smb->callback =3D smb2_writev_callback; smb->subreq =3D wdata; =20 - iov_iter_bvec_queue(&smb->rqst.rq_iter, ITER_SOURCE, + iov_iter_bvec_queue(&smb->data_iter, ITER_SOURCE, wdata->subreq.content.bvecq, wdata->subreq.content.slot, wdata->subreq.content.offset, wdata->subreq.len); =20 if (smb3_encryption_required(tcon)) - flags |=3D CIFS_TRANSFORM_REQ; - - shdr =3D (struct smb2_hdr *)req; - shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms.pid); + smb->sr_flags |=3D CIFS_TRANSFORM_REQ; =20 + shdr->Id.SyncId.ProcessId =3D cpu_to_le32(io_parms.pid); req->PersistentFileId =3D io_parms.persistent_fid; req->VolatileFileId =3D io_parms.volatile_fid; req->WriteChannelInfoOffset =3D 0; @@ -5417,7 +5413,7 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) * If we want to do a server RDMA read, fill in and append * smbdirect_buffer_descriptor_v1 to the end of write request */ - if (smb3_use_rdma_offload(&io_parms)) { + if (rdma_offload) { struct smbdirect_buffer_descriptor_v1 *v1; struct iov_iter iter; bool need_invalidate =3D server->dialect =3D=3D SMB30_PROT_ID; @@ -5467,9 +5463,12 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) io_parms.offset, io_parms.length, iov_iter_count(&smb->rqst.rq_iter)); =20 if (wdata->credits.value > 0) { - shdr->CreditCharge =3D cpu_to_le16(DIV_ROUND_UP(wdata->subreq.len, - SMB2_MAX_BUFFER_SIZE)); - credit_request =3D le16_to_cpu(shdr->CreditCharge) + 8; + u32 credit_charge =3D DIV_ROUND_UP(wdata->subreq.len, + SMB2_MAX_BUFFER_SIZE); + int credit_request; + + shdr->CreditCharge =3D cpu_to_le16(credit_charge); + credit_request =3D credit_charge + 8; if (server->credits >=3D server->max_credits) shdr->CreditRequest =3D cpu_to_le16(0); else @@ -5481,15 +5480,18 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) if (rc) goto async_writev_out; =20 - flags |=3D CIFS_HAS_CREDITS; + smb->sr_flags |=3D CIFS_HAS_CREDITS; } =20 /* XXX: compression + encryption is unsupported for now */ - if (((flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && + if (((smb->sr_flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && should_compress(tcon, smb)) - flags |=3D CIFS_COMPRESS_REQ; + smb->sr_flags |=3D CIFS_COMPRESS_REQ; =20 - rc =3D cifs_call_async(server, smb, flags, &wdata->credits); + iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->data_offset); + + rc =3D cifs_call_async(server, smb, smb->sr_flags, &wdata->credits); /* Can't touch wdata if rc =3D=3D 0 */ if (rc) { trace_smb3_write_err(wdata->rreq->debug_id, @@ -5505,7 +5507,6 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) } =20 async_writev_out: - cifs_small_buf_release(req); smb_put_messages(smb); out: /* if the send error is retryable, let netfs know about it */ From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 67CEB405859 for ; Tue, 19 May 2026 10:24:54 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186297; cv=none; b=B09PoPio4rJLZJHcgbg6Q5fAF0q+RQHGG4MFgRv996RU4X5Pmz8WPwfSAte9/8kvpjPvevxFV+2LuL+EwunhzkY1SMDYR2uz9K7/qInkHiVTK4F3S4cYXYb1ESAwTcUQGudZRKewqTz1yzJkVNsZFr8ehjw3bJWTyWpb0NfxnQA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186297; c=relaxed/simple; bh=oO6f4LRCHepH4qNLpLun8eTejWtJLMHsEwcBStKvMT8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Z+pQSjja3++WMSQf4HWITYcqSVQczIHehjh0zUfXxRV/WUOoRo7DUutuVVHAZHiTl4H8MrJAb3eXtctdTMgJKTxPHx9YGVGKPnEKfGuaTjL0mCXxBIaTm6gpgS1c3piJ8HJsalfrmY0Q4ut3ay/ic1XQfhzfU0Wl5yZj4TSHFzg= 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=f5PCz2sE; arc=none smtp.client-ip=170.10.133.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="f5PCz2sE" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186293; 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=qTP+N02umNQMf6H6f6Beoe7O0wphfbf0XB/xACH6ZMs=; b=f5PCz2sEJZuMdhyJChQGZXCmyZroid8HDgxdnFTdmqfJkPKkRuFGpShn03gA2NwEaAVQLr fH9zhx902DatM5n5B9fkvLiCdG0al8a2yK+YtrQlXpL2pmUE0QCYt2GaXTU0waiuIEADua UruO75CPiQa1PTh+ZEN+Uu8OhrSTlIs= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-468-JjvNWDUQN0m2IPFsi6zAYw-1; Tue, 19 May 2026 06:24:50 -0400 X-MC-Unique: JjvNWDUQN0m2IPFsi6zAYw-1 X-Mimecast-MFC-AGG-ID: JjvNWDUQN0m2IPFsi6zAYw_1779186288 Received: from mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.12]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id CCF421956053; Tue, 19 May 2026 10:24:48 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 6749819560A2; Tue, 19 May 2026 10:24:45 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 33/36] cifs: [WIP] Don't copy new-style smb_messages to a set of pages Date: Tue, 19 May 2026 11:21:51 +0100 Message-ID: <20260519102158.592165-34-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.12 Content-Type: text/plain; charset="utf-8" Currently, smb_send_rqst() copies all the data it is given into a clean set of pages and, if needed, a page fragment so that MSG_SPLICE_PAGES can be passed to sendmsg() to make sendmsg() more efficient. With the "new style" of smb_messages, however, the protocol data is placed into its own fragment or fragments plus, optionally, a bundle of page fragments supplied from higher up carrying data (e.g. for Write). These can be passed to MSG_SPLICE_PAGES without the need for copying, so don't do that if we don't have to. Note that we may still need to do this if encrypting or compressing and we can't modify borrowed data in place (e.g. Write), though we *can* encrypt the request in its fragment. 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/cifsencrypt.c | 4 +- fs/smb/client/cifsglob.h | 16 ++- fs/smb/client/cifssmb.c | 12 +- fs/smb/client/compress.c | 21 ++- fs/smb/client/compress.h | 4 +- fs/smb/client/smb1encrypt.c | 4 +- fs/smb/client/smb1transport.c | 8 +- fs/smb/client/smb2misc.c | 4 +- fs/smb/client/smb2ops.c | 2 +- fs/smb/client/smb2pdu.c | 63 +++------ fs/smb/client/smb2transport.c | 69 ++++++---- fs/smb/client/transport.c | 249 ++++++++++++++++++++++------------ 12 files changed, 274 insertions(+), 182 deletions(-) diff --git a/fs/smb/client/cifsencrypt.c b/fs/smb/client/cifsencrypt.c index 34804e9842a8..eb900cecbb37 100644 --- a/fs/smb/client/cifsencrypt.c +++ b/fs/smb/client/cifsencrypt.c @@ -87,7 +87,9 @@ int __cifs_calc_signature(struct smb_rqst *rqst, struct T= CP_Server_Info *server, if (rc < 0) return rc; =20 - rc =3D cifs_sig_iter(&rqst->rq_iter, iov_iter_count(&rqst->rq_iter), ctx); + iov_iter_bvec_queue(&iter, ITER_SOURCE, rqst->rq_data, 0, 0, rqst->rq_dat= a_len); + + rc =3D cifs_sig_iter(&iter, iov_iter_count(&iter), ctx); if (rc < 0) return rc; =20 diff --git a/fs/smb/client/cifsglob.h b/fs/smb/client/cifsglob.h index ed7311637d81..e5972ac80240 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -290,8 +290,8 @@ struct cifs_open_info_data { struct smb_rqst { struct kvec *rq_iov; /* array of kvecs */ unsigned int rq_nvec; /* number of kvecs in array */ - struct iov_iter rq_iter; /* Data iterator */ - struct bvecq *rq_buffer; /* Buffer for encryption */ + unsigned int rq_data_len; /* Amount of data in ->rq_data */ + struct bvecq *rq_data; /* Data content */ }; =20 struct smb_message; @@ -1706,6 +1706,7 @@ struct smb_message { bool decrypted:1; /* decrypted entry */ bool sig_checked:1; /* T if sig already checked */ bool copy_to_bufs:1; /* Copy to prepared buffer in response_iter */ + bool req_data_nomodify:1; /* T if req_data cannot be modified */ =20 /* Request details */ u8 command_trace; /* enum smb_command_trace - Command trace ID */ @@ -1716,8 +1717,8 @@ struct smb_message { u16 offset; /* Running offset during assembly */ u16 data_offset; /* Offset of data in message (maybe in ->body) */ unsigned int total_len; /* Total length of from hdr_offset onwards */ - struct iov_iter data_iter; /* Data iterator */ - struct iov_iter req_iter; /* Request iterator */ + unsigned int req_data_len; /* Amount of data in ->data_bq */ + struct bvecq *req_data; /* Data content */ /* Response */ //u32 response_pdu_len; /* Size of response PDU */ void *response; /* Protocol part of response */ @@ -1726,8 +1727,11 @@ struct smb_message { u32 resp_data_offset; /* Offset of response data (or 0) */ __le32 status; /* Completion status */ short error; /* Linux error */ - struct iov_iter response_iter; /* Data part of response */ - struct bvecq *response_data; /* Storage for response data (or NULL) */ + struct iov_iter resp_extra_iter; + struct bvecq *resp_buffer; /* Storage for response data */ + unsigned int resp_buffer_slot; + unsigned int resp_buffer_offset; + unsigned int resp_buffer_len; /* Capacity of resp->buffer */ /* Compat with old code */ struct smb_rqst rqst; /* Variable-length request fragment list - must be last! */ diff --git a/fs/smb/client/cifssmb.c b/fs/smb/client/cifssmb.c index e36828359f67..80fc4e89f3df 100644 --- a/fs/smb/client/cifssmb.c +++ b/fs/smb/client/cifssmb.c @@ -1595,10 +1595,10 @@ cifs_async_readv(struct cifs_io_subrequest *rdata) smb->total_len =3D in_len; smb->callback =3D cifs_readv_callback; smb->copy_to_bufs =3D true; - - iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); + smb->resp_buffer =3D bvecq_get(rdata->subreq.content.bvecq); + smb->resp_buffer_slot =3D rdata->subreq.content.slot; + smb->resp_buffer_offset =3D rdata->subreq.content.offset; + smb->resp_buffer_len =3D rdata->subreq.len; =20 trace_smb3_read_enter(rdata->rreq->debug_id, rdata->subreq.debug_index, @@ -1968,7 +1968,9 @@ cifs_async_writev(struct cifs_io_subrequest *wdata) =20 smb->rqst.rq_iov =3D iov; smb->rqst.rq_nvec =3D 1; - smb->command =3D SMB2_WRITE; + smb->req_data =3D wdata->subreq.content; + smb->req_data_len =3D wdata->len; + smb->req_data_nomodify =3D true; smb->request =3D req; smb->total_len =3D in_len + 1; smb->total_len +=3D wdata->subreq.len; diff --git a/fs/smb/client/compress.c b/fs/smb/client/compress.c index 36eb8a604603..67305b1e82a6 100644 --- a/fs/smb/client/compress.c +++ b/fs/smb/client/compress.c @@ -329,9 +329,8 @@ static void *vmap_bvecq(struct iov_iter *iter, pgprot_t= prot) } =20 int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, - struct bvecq **bq) + struct bvecq **bq, struct smb2_compression_hdr *z_hdr) { - struct smb2_compression_hdr *z_hdr; struct smb2_write_req *w_hdr; struct smb2_hdr *shdr; struct iov_iter tmp; @@ -363,9 +362,8 @@ int smb_compress(struct TCP_Server_Info *server, struct= iov_iter *iter, * This is just overprovisioning, as the algorithm will error out if @dst= reaches 7/8 * of @slen. */ - dlen =3D lz77_compressed_alloc_size(slen); - dlen =3D sizeof(*z_hdr) + slen; - dbq =3D bvecq_alloc_buffer(dlen, GFP_NOFS); + dlen =3D slen; + dbq =3D bvecq_alloc_buffer2(dlen, 1, GFP_NOFS); if (!dbq) { ret =3D -ENOMEM; goto err_free; @@ -378,16 +376,15 @@ int smb_compress(struct TCP_Server_Info *server, stru= ct iov_iter *iter, dst =3D NULL; goto err_free; } - z_hdr =3D dst; - dst +=3D sizeof(*z_hdr) + hlen; - dlen -=3D sizeof(*z_hdr) + hlen; + dst +=3D hlen; + dlen -=3D hlen; =20 ret =3D lz77_compress(src + hlen, slen - hlen, dst, &dlen); if (ret) goto err_free; =20 - dlen +=3D sizeof(*z_hdr) + hlen; - dst -=3D hlen; + dlen +=3D hlen; + dst -=3D hlen; memcpy(dst, src, hlen); =20 z_hdr->ProtocolId =3D SMB2_COMPRESSION_TRANSFORM_ID; @@ -396,7 +393,7 @@ int smb_compress(struct TCP_Server_Info *server, struct= iov_iter *iter, z_hdr->Flags =3D SMB2_COMPRESSION_FLAG_NONE; z_hdr->Offset =3D cpu_to_le32(hlen); =20 - vunmap(z_hdr); + vunmap(dst); vunmap(src); =20 dbq->bv[0] =3D sbq->bv[0]; @@ -409,7 +406,7 @@ int smb_compress(struct TCP_Server_Info *server, struct= iov_iter *iter, return dlen; =20 err_free: - vunmap(z_hdr); + vunmap(dst); vunmap(src); bvecq_put(dbq); return ret; diff --git a/fs/smb/client/compress.h b/fs/smb/client/compress.h index d03f7342b4bd..ba45f0681ab1 100644 --- a/fs/smb/client/compress.h +++ b/fs/smb/client/compress.h @@ -31,7 +31,7 @@ typedef int (*compress_send_fn)(struct TCP_Server_Info *,= int, struct smb_rqst * =20 =20 int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, - struct bvecq **bq); + struct bvecq **bq, struct smb2_compression_hdr *z_hdr); bool should_compress(const struct cifs_tcon *tcon, const struct smb_messag= e *smb); bool is_compressible(const struct iov_iter *data); =20 @@ -61,7 +61,7 @@ static __always_inline int smb_compress_alg_valid(__le16 = alg, bool valid_none) #else /* !CONFIG_CIFS_COMPRESSION */ static inline int smb_compress(struct TCP_Server_Info *server, struct iov_iter *iter, - struct bvecq **bq) + struct bvecq **bq, struct smb2_compression_hdr *z_hdr) { return -EOPNOTSUPP; } diff --git a/fs/smb/client/smb1encrypt.c b/fs/smb/client/smb1encrypt.c index c61202ae54c6..a9b5884fd790 100644 --- a/fs/smb/client/smb1encrypt.c +++ b/fs/smb/client/smb1encrypt.c @@ -118,7 +118,9 @@ int cifs_verify_signature(struct smb_message *smb, struct smb_rqst rqst =3D { .rq_iov =3D &iov, .rq_nvec =3D 1, - .rq_iter =3D smb->response_iter + .rq_data =3D smb->resp_buffer, + .rq_data_len =3D umin(smb->resp_buffer_len, smb->resp_data_len), + =09 }; char what_we_think_sig_should_be[20]; char server_response_sig[8]; diff --git a/fs/smb/client/smb1transport.c b/fs/smb/client/smb1transport.c index 598579b564ae..df26eb3cf0e0 100644 --- a/fs/smb/client/smb1transport.c +++ b/fs/smb/client/smb1transport.c @@ -799,10 +799,16 @@ static void smb1_copy_to_prepped_buffers(struct TCP_S= erver_Info *server, struct cifs_receive *recv) { const union smb1_response_hdr *h =3D recv->response; - struct iov_iter dest =3D smb->response_iter; + struct iov_iter dest; unsigned int to_copy, skip; int rc; =20 + iov_iter_bvec_queue(&dest, ITER_DEST, + smb->resp_buffer, + smb->resp_buffer_slot, + smb->resp_buffer_offset, + smb->resp_buffer_len); + switch (h->hdr.Command) { case SMB_COM_READ_ANDX: to_copy =3D recv->data_len; diff --git a/fs/smb/client/smb2misc.c b/fs/smb/client/smb2misc.c index 7c9dc3ede8b8..3f0f1e46bb06 100644 --- a/fs/smb/client/smb2misc.c +++ b/fs/smb/client/smb2misc.c @@ -889,7 +889,9 @@ smb311_update_preauth_hash(struct cifs_ses *ses, struct= TCP_Server_Info *server, if (hash_resp) { sha512_update(&sha_ctx, smb->response, smb->resp_len); } else if (smb->new_style) { - struct iov_iter tmp =3D smb->req_iter; + struct iov_iter tmp; + + iov_iter_bvec_queue(&tmp, ITER_SOURCE, &smb->bvecq, 0, 0, smb->total_len= ); =20 iterate_and_advance_kernel(&tmp, smb->total_len, &sha_ctx, NULL, smb_sha512_step); diff --git a/fs/smb/client/smb2ops.c b/fs/smb/client/smb2ops.c index f9cefc47d084..0e212a3e883d 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -2769,7 +2769,7 @@ smb2_set_next_command(struct cifs_tcon *tcon, struct = smb_rqst *rqst) =20 for (int i =3D 0; i < rqst->rq_nvec; i++) len +=3D rqst->rq_iov[i].iov_len; - len +=3D iov_iter_count(&rqst->rq_iter); + len +=3D rqst->rq_data_len; =20 /* SMB headers in a compound are 8 byte aligned. */ if (IS_ALIGNED(len, 8)) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index b434aaf15dba..01d84f9ece82 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1450,9 +1450,6 @@ SMB2_negotiate(const unsigned int xid, smb->total_len =3D smb->offset; smb->bvecq.bv[0].bv_len =3D smb->offset; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); smb_clear_request(smb); =20 @@ -1513,13 +1510,14 @@ SMB2_negotiate(const unsigned int xid, break; } break; + case SPEC: + /* if requested single dialect ensure returned dialect matched */ + if (dialect =3D=3D server->vals->protocol_id) + break; + fallthrough; default: - if (dialect !=3D server->vals->protocol_id) { - /* if requested single dialect ensure returned dialect matched */ - cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", - dialect); - goto neg_exit; - } + cifs_server_dbg(VFS, "Invalid 0x%x dialect returned: not requested\n", + dialect); rc =3D smb_EIO2(smb_eio_trace_neg_unreq_dialect, dialect, server->vals->protocol_id); goto neg_exit; @@ -1895,9 +1893,6 @@ SMB2_sess_sendreceive(struct SMB2_sess_data *sess_dat= a, req->SecurityBufferLength =3D cpu_to_le16(smb->total_len - sizeof(*req)); smb->sr_flags =3D CIFS_LOG_ERROR | CIFS_SESS_OP; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->total_len); - /* BB add code to build os and lm fields */ rc =3D smb_send_recv_messages(sess_data->xid, sess_data->ses, sess_data->= server, smb, CIFS_LOG_ERROR | CIFS_SESS_OP); @@ -2331,9 +2326,6 @@ SMB2_logoff(const unsigned int xid, struct cifs_ses *= ses) else if (server->sign) req->hdr.Flags |=3D SMB2_FLAGS_SIGNED; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - smb->sr_flags =3D flags; rc =3D smb_send_recv_messages(xid, ses, ses->server, smb, flags); /* @@ -2423,9 +2415,6 @@ SMB2_tcon(const unsigned int xid, struct cifs_ses *se= s, const char *tree, req->hdr.CreditRequest =3D cpu_to_le16( min_t(int, server->max_credits - server->credits, 64)); =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - smb->sr_flags =3D flags; rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); smb_clear_request(smb); @@ -2522,9 +2511,6 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *t= con) if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - smb->sr_flags =3D flags; rc =3D smb_send_recv_messages(xid, ses, server, smb, flags); smb_clear_request(smb); @@ -5052,10 +5038,10 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) smb->callback =3D smb2_readv_callback; smb->subreq =3D rdata; smb->copy_to_bufs =3D true; - - iov_iter_bvec_queue(&smb->response_iter, ITER_DEST, - rdata->subreq.content.bvecq, rdata->subreq.content.slot, - rdata->subreq.content.offset, rdata->subreq.len); + smb->resp_buffer =3D bvecq_get(subreq->content.bvecq); + smb->resp_buffer_slot =3D subreq->content.slot; + smb->resp_buffer_offset =3D subreq->content.offset; + smb->resp_buffer_len =3D subreq->len - subreq->transferred; =20 if (rdata->replay) { /* Back-off before retry */ @@ -5085,9 +5071,6 @@ smb2_async_readv(struct cifs_io_subrequest *rdata) smb->sr_flags |=3D CIFS_HAS_CREDITS; } =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - rc =3D cifs_call_async(server, smb, smb->sr_flags, &rdata->credits); if (rc) { cifs_stats_fail_inc(io_parms.tcon, SMB2_READ_HE); @@ -5136,9 +5119,6 @@ SMB2_read(const unsigned int xid, struct cifs_io_parm= s *io_parms, if (smb3_encryption_required(io_parms->tcon)) smb->sr_flags |=3D CIFS_TRANSFORM_REQ; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); - rc =3D smb_send_recv_messages(xid, ses, io_parms->server, smb, smb->sr_fl= ags); smb_clear_request(smb); =20 @@ -5379,6 +5359,10 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) smb->request =3D req; smb->callback =3D smb2_writev_callback; smb->subreq =3D wdata; + smb->bvecq.next =3D wdata->subreq.content.bvecq; + smb->req_data =3D bvecq_get(wdata->subreq.content.bvecq); + smb->req_data_len =3D wdata->subreq.len; + smb->req_data_nomodify =3D true; =20 iov_iter_bvec_queue(&smb->data_iter, ITER_SOURCE, wdata->subreq.content.bvecq, wdata->subreq.content.slot, @@ -5443,12 +5427,6 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) smbd_mr_fill_buffer_descriptor(wdata->mr, v1); =20 smb->rqst.rq_iov[0].iov_len +=3D sizeof(*v1); - - /* - * We keep wdata->subreq.io_iter, - * but we have to truncate rqst.rq_iter - */ - iov_iter_truncate(&smb->rqst.rq_iter, 0); } #endif =20 @@ -5485,11 +5463,14 @@ smb2_async_writev(struct cifs_io_subrequest *wdata) =20 /* XXX: compression + encryption is unsupported for now */ if (((smb->sr_flags & CIFS_TRANSFORM_REQ) !=3D CIFS_TRANSFORM_REQ) && - should_compress(tcon, smb)) - smb->sr_flags |=3D CIFS_COMPRESS_REQ; + should_compress(tcon, smb)) { + struct iov_iter ziter; =20 - iov_iter_bvec_queue(&smb->req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, - smb->data_offset); + iov_iter_bvec_queue(&ziter, ITER_SOURCE, smb->req_data, 0, 0, + smb->req_data_len); + if (is_compressible(&ziter)) + smb->sr_flags |=3D CIFS_COMPRESS_REQ; + } =20 rc =3D cifs_call_async(server, smb, smb->sr_flags, &wdata->credits); /* Can't touch wdata if rc =3D=3D 0 */ diff --git a/fs/smb/client/smb2transport.c b/fs/smb/client/smb2transport.c index f63eaff4935a..72311ec8746b 100644 --- a/fs/smb/client/smb2transport.c +++ b/fs/smb/client/smb2transport.c @@ -241,7 +241,8 @@ smb2_calc_signature(struct smb_message *smb, struct TCP= _Server_Info *server, hmac_sha256_init_usingrawkey(&hmac_ctx, key, sizeof(key)); =20 if (smb->new_style) { - struct iov_iter req_iter =3D smb->req_iter; + struct iov_iter req_iter; + iov_iter_bvec_queue(&req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, smb->tota= l_len); =20 size =3D iov_iter_count(&req_iter); did =3D iterate_and_advance_kernel(&req_iter, size, &hmac_ctx, NULL, @@ -255,7 +256,8 @@ smb2_calc_signature(struct smb_message *smb, struct TCP= _Server_Info *server, smb->rqst.rq_iov[i].iov_len); } =20 - struct iov_iter data_iter =3D smb->data_iter; + struct iov_iter data_iter; + iov_iter_bvec_queue(&data_iter, ITER_SOURCE, smb->req_data, 0, 0, smb->to= tal_len); =20 size =3D iov_iter_count(&data_iter); did =3D iterate_and_advance_kernel(&data_iter, size, &hmac_ctx, NULL, @@ -515,21 +517,28 @@ smb3_calc_signature(struct smb_message *smb, struct T= CP_Server_Info *server, aes_cmac_init(&cmac_ctx, &cmac_key); =20 if (for_recv) { - struct iov_iter resp_iter =3D smb->response_iter; - size =3D smb->resp_len; did =3D 0; =20 aes_cmac_update(&cmac_ctx, smb->response, size); - rc =3D -EIO; - size =3D iov_iter_count(&resp_iter); - did =3D iterate_and_advance_kernel(&resp_iter, size, &cmac_ctx, - NULL, smb3_aes_cmac_step); - if (did !=3D size) - goto eio; + + if (smb->resp_buffer_len) { + struct iov_iter resp_iter; + + size =3D umin(smb->resp_buffer_len, smb->resp_data_len); + iov_iter_bvec_queue(&resp_iter, ITER_SOURCE, + smb->resp_buffer, 0, 0, size); + did =3D iterate_and_advance_kernel(&resp_iter, size, &cmac_ctx, + NULL, smb3_aes_cmac_step); + if (did !=3D size) + goto eio; + } } else { if (smb->new_style) { - struct iov_iter req_iter =3D smb->req_iter; + struct iov_iter req_iter; + + iov_iter_bvec_queue(&req_iter, ITER_SOURCE, &smb->bvecq, 0, 0, + smb->total_len); =20 size =3D iov_iter_count(&req_iter); did =3D iterate_and_advance_kernel(&req_iter, size, @@ -544,15 +553,18 @@ smb3_calc_signature(struct smb_message *smb, struct T= CP_Server_Info *server, smb->rqst.rq_iov[i].iov_base, size); } - } =20 - struct iov_iter data_iter =3D smb->data_iter; + struct iov_iter data_iter; + iov_iter_bvec_queue(&data_iter, ITER_SOURCE, smb->req_data, 0, 0, + smb->req_data_len); =20 - size =3D iov_iter_count(&data_iter); - did =3D iterate_and_advance_kernel(&data_iter, size, &cmac_ctx, - NULL, smb3_aes_cmac_step); - if (did !=3D size) - return smb_EIO2(smb_eio_trace_sig_iter, did, size); + size =3D iov_iter_count(&data_iter); + did =3D iterate_and_advance_kernel(&data_iter, size, + &cmac_ctx, NULL, + smb3_aes_cmac_step); + if (did !=3D size) + return smb_EIO2(smb_eio_trace_sig_iter, did, size); + } } =20 aes_cmac_final(&cmac_ctx, smb3_signature); @@ -562,7 +574,7 @@ smb3_calc_signature(struct smb_message *smb, struct TCP= _Server_Info *server, out: return rc; eio: - smb_EIO2(smb_eio_trace_sig_iter, did, size); + rc =3D smb_EIO2(smb_eio_trace_sig_iter, did, size); goto out; } =20 @@ -1239,10 +1251,16 @@ static void smb2_copy_to_prepped_buffers(struct TCP= _Server_Info *server, struct cifs_receive *recv) { const union smb2_response_hdr *h =3D recv->response; - struct iov_iter dest =3D smb->response_iter; + struct iov_iter dest; unsigned int to_copy, skip; int rc; =20 + iov_iter_bvec_queue(&dest, ITER_DEST, + smb->resp_buffer, + smb->resp_buffer_slot, + smb->resp_buffer_offset, + smb->resp_buffer_len); +=09 switch (smb->command) { case SMB2_READ: to_copy =3D recv->data_len; @@ -1288,7 +1306,7 @@ static void smb2_copy_to_prepped_buffers(struct TCP_S= erver_Info *server, if (!rxq->refillable) { size_t got; =20 - got =3D netfs_rxqueue_read_iter(rxq, &smb->response_iter, 0, to_copy); + got =3D netfs_rxqueue_read_iter(rxq, &dest, 0, to_copy); if (got > 0) netfs_rxqueue_discard(rxq, got); recv->extracted +=3D got; @@ -1468,12 +1486,13 @@ static void smb2_parse_one_message(struct TCP_Serve= r_Info *server, } else if (smb->copy_to_bufs) { smb2_copy_to_prepped_buffers(server, smb, rxq, recv); - } else if (rxq->pdu_remain) { - iov_iter_bvec_queue(&smb->response_iter, ITER_SOURCE, + } else if (rxq->pdu_remain && !smb->resp_buffer) { + smb->resp_buffer =3D rxq->take_from; + smb->resp_buffer_len =3D rxq->pdu_remain; + iov_iter_bvec_queue(&smb->resp_extra_iter, ITER_SOURCE, rxq->take_from, rxq->take_slot, rxq->take_offset, rxq->pdu_remain); - smb->response_data =3D rxq->take_from; - refcount_inc(&smb->response_data->ref); + refcount_inc(&smb->resp_buffer->ref); } } else { netfs_rxqueue_discard(rxq, recv->extracted); diff --git a/fs/smb/client/transport.c b/fs/smb/client/transport.c index 212894c8d2bd..b01502c38d05 100644 --- a/fs/smb/client/transport.c +++ b/fs/smb/client/transport.c @@ -112,6 +112,8 @@ void smb_clear_request(struct smb_message *smb) if (smb->request) { if (smb->sensitive) memzero_explicit(smb->request, smb->data_offset); + bvecq_put(smb->req_data); + smb->req_data =3D NULL; cifs_free_tx_buf(smb->request); smb->request =3D NULL; } @@ -186,8 +188,11 @@ static void smb_clear_mid(struct TCP_Server_Info *serv= er, struct smb_message *sm cifs_buf_release(smb->response); else cifs_small_buf_release(smb->response); - if (smb->response_data) - netfs_put_rx_bvecq(smb->response_data); + if (smb->resp_extra_iter.count) + netfs_put_rx_bvecq(smb->resp_buffer); + else + bvecq_put(smb->resp_buffer); + bvecq_put(smb->req_data); #ifdef CONFIG_CIFS_STATS2 now =3D jiffies; if (now < smb->when_alloc) @@ -532,15 +537,14 @@ static size_t smb3_copy_data_iter(void *iter_from, si= ze_t progress, size_t len, /* * Copy the data into a buffer that we can use for encryption in place and= also * pass to sendmsg() with MSG_SPLICE_PAGES. This avoids a lot of copies i= n TCP - * at the expense of doing it upfront here. A spare slot is left in the b= vec - * queue at the front for the header(s). + * at the expense of doing it upfront here. * * TODO: In future, the buffers should be allocated by the marshalling cod= e. */ static int smb_copy_data_into_buffer(struct TCP_Server_Info *server, struct smb_message *head_smb, - struct iov_iter *iter, struct bvecq **_bq, - unsigned int flags) + struct iov_iter *iter, + struct bvecq *head_bq) { struct smb_message *smb; struct bvecq *bq; @@ -554,11 +558,11 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, =20 if (total_len <=3D PAGE_SIZE / 2) { /* TODO: Choose algo-based alignment. */ - unsigned int align =3D (flags & CIFS_TRANSFORM_REQ) ? 32 : 1; - size_t alen =3D (flags & CIFS_TRANSFORM_REQ) ? + unsigned int align =3D (head_smb->sr_flags & CIFS_TRANSFORM_REQ) ? 32 : = 1; + size_t alen =3D (head_smb->sr_flags & CIFS_TRANSFORM_REQ) ? round_up(total_len, align) : total_len; =20 - bq =3D bvecq_alloc_chain(2, GFP_NOFS); + bq =3D bvecq_alloc_chain(1, GFP_NOFS); if (!bq) return -ENOMEM; mutex_lock(&server->tx_alloc_lock); @@ -569,16 +573,16 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, bvecq_put(bq); return -ENOMEM; } - bvec_set_virt(&bq->bv[1], p, total_len); - bq->nr_slots =3D 2; + bvec_set_virt(&bq->bv[0], p, total_len); + bq->nr_slots =3D 1; bq->mem_type =3D BVECQ_MEM_PAGECACHE; } else { - bq =3D bvecq_alloc_buffer2(total_len, 1, GFP_NOFS); + bq =3D bvecq_alloc_buffer(total_len, GFP_NOFS); if (!bq) return -ENOMEM; } =20 - iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); + iov_iter_bvec_queue(iter, ITER_DEST, bq, 0, 0, total_len); =20 for (smb =3D head_smb; smb; smb =3D smb->next) { size_t size, got; @@ -590,9 +594,26 @@ static int smb_copy_data_into_buffer(struct TCP_Server= _Info *server, } =20 if (smb->new_style) { - struct iov_iter req_iter =3D smb->req_iter; + struct iov_iter req_iter; + + if (smb->req_data_len) + smb->bvecq.next =3D smb->req_data; + + iov_iter_bvec_queue(&req_iter, ITER_SOURCE, + &smb->bvecq, 0, 0, smb->total_len); + got =3D iterate_and_advance_kernel(&req_iter, + smb->total_len, iter, NULL, + smb3_copy_data_iter); + if (got !=3D size) { + rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); + goto error; + } + offset +=3D smb->total_len; =20 +#if 0 + struct iov_iter req_iter =3D smb->req_iter; size =3D iov_iter_count(&req_iter); + got =3D iterate_and_advance_kernel(&req_iter, size, iter, NULL, smb3_copy_data_iter); @@ -612,10 +633,12 @@ static int smb_copy_data_into_buffer(struct TCP_Serve= r_Info *server, rc =3D smb_EIO2(smb_eio_trace_tx_copy_iter_to_buf, got, size); goto error; } + offset +=3D size; +#endif } else { /* Old-style with an rqst. */ - size =3D iov_iter_count(&smb->rqst.rq_iter); + size =3D smb->rqst.rq_data_len; =20 for (int i =3D 0; i < smb->rqst.rq_nvec; i++) { size_t len =3D smb->rqst.rq_iov[i].iov_len; @@ -628,7 +651,12 @@ static int smb_copy_data_into_buffer(struct TCP_Server= _Info *server, offset +=3D len; } =20 - got =3D iterate_and_advance_kernel(&smb->rqst.rq_iter, + struct iov_iter data_iter; + iov_iter_bvec_queue(&data_iter, ITER_SOURCE, + smb->rqst.rq_data, 0, 0, + smb->rqst.rq_data_len); + + got =3D iterate_and_advance_kernel(&data_iter, size, iter, NULL, smb3_copy_data_iter); if (got !=3D size) { @@ -645,101 +673,152 @@ static int smb_copy_data_into_buffer(struct TCP_Ser= ver_Info *server, goto error; } =20 - iov_iter_bvec_queue(iter, ITER_DEST, bq, 1, 0, total_len); - *_bq =3D bq; + head_bq->next =3D bq; return 0; error: bvecq_put(bq); - *_bq =3D NULL; return rc; } =20 static int -smb_send_rqst(struct TCP_Server_Info *server, struct smb_message *head_smb= , int flags) +smb_send_rqst(struct TCP_Server_Info *server, struct smb_message *head_smb) { + struct smb2_compression_hdr *z_hdr; + struct smb2_transform_hdr *tr_hdr; + struct smb_message *smb; struct iov_iter iter; - struct bvecq *bq; - u32 content_len; + struct bvecq *copy_bq =3D NULL; + struct bio_vec head_bv =3D {}; + unsigned int troff =3D 0, zoff =3D 0; + __be32 *rfc1002; + void *hdr_blob =3D NULL; + bool must_copy =3D false; + u32 hdr_len, content_len =3D 0; int rc; =20 - if ((flags & CIFS_TRANSFORM_REQ) && + if ((head_smb->sr_flags & CIFS_TRANSFORM_REQ) && !server->ops->init_transform_rq) { cifs_server_dbg(VFS, "Encryption requested but transform callback is mis= sing\n"); return smb_EIO(smb_eio_trace_tx_need_transform); } =20 - rc =3D smb_copy_data_into_buffer(server, head_smb, &iter, &bq, flags); - if (rc) - return rc; - content_len =3D iov_iter_count(&iter); + /* We start with a buffer segment that just contains the header. This + * then links on to first message in a compound for new-style buffer + * handling. We end up with a sequence: + * + * pduhdr->smb1->data1->smb2->data2->smb3->data3->... + * + * Where dataN only exists for something like Write. + */ + struct bvecq head_bq =3D { + .ref =3D REFCOUNT_INIT(1), + .nr_slots =3D 1, + .max_slots =3D 1, + .bv =3D &head_bv, + }; =20 - { - struct smb2_transform_hdr *tr_hdr; - unsigned int hdr_len =3D 4, troff =3D 0; - __le32 *rfc1002; - void *hdr_blob; + /* Allocate space to store the RFC1002, Transform and Compress headers + * as needed. The latter part of the Transform header needs to be + * accessed by the encryption routine for inclusion in the checksum. + * The Compress header gets encrypted. + */ + hdr_len =3D sizeof(*rfc1002); + if (head_smb->sr_flags & CIFS_TRANSFORM_REQ) { + troff =3D hdr_len; + hdr_len +=3D sizeof(*tr_hdr); + } + if (head_smb->sr_flags & CIFS_COMPRESS_REQ) { + zoff =3D hdr_len; + hdr_len +=3D sizeof(*z_hdr); + } =20 - if (flags & CIFS_TRANSFORM_REQ) { - troff =3D hdr_len; - hdr_len +=3D sizeof(*tr_hdr); - } + rc =3D -ENOMEM; + hdr_blob =3D cifs_allocate_tx_buf(server, hdr_len); + if (!hdr_blob) + goto error; + bvec_set_virt(&head_bv, hdr_blob, hdr_len); =20 - /* TODO: Allocate netmem here */ - rc =3D -ENOMEM; - mutex_lock(&server->tx_alloc_lock); - hdr_blob =3D page_frag_alloc(&server->tx_alloc, hdr_len, GFP_NOFS); - mutex_unlock(&server->tx_alloc_lock); - if (!hdr_blob) - goto error; - bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len); - - if (flags & CIFS_COMPRESS_REQ) { - struct smb2_write_req *whdr =3D bvec_virt(&bq->bv[1]); - size_t doff =3D le16_to_cpu(whdr->DataOffset); - - iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, doff, - content_len - doff); - - if (is_compressible(&iter)) { - iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 1, 0, - content_len); - - rc =3D smb_compress(server, &iter, &bq); - if (rc > 0) { - content_len =3D rc; - } else if (rc =3D=3D -EMSGSIZE) { - /* Fall back to uncompressed. */ - } else { - if (rc =3D=3D 0) - rc =3D smb_EIO(smb_eio_trace_tx_compress_failed); - goto error; - } - } + /* Work out whether we need to copy some or all of the protocol and the + * data. For old-style (smb_rqst) buffering, we copy everything and + * also for compression; for encryption, we only really need to copy + * any data that can't be modified in-place (e.g. for Write ops). + */ + for (smb =3D head_smb; smb; smb =3D smb->next) { + content_len +=3D smb->total_len; + if (smb->sr_flags & CIFS_COMPRESS_REQ) { + must_copy =3D true; + continue; + } + if (!smb->new_style) { + must_copy =3D true; + continue; } + if ((smb->sr_flags & CIFS_TRANSFORM_REQ) && + smb->req_data_nomodify && + smb->req_data_len > 0) { + must_copy =3D true; + continue; + } + } =20 - if (flags & CIFS_TRANSFORM_REQ) { - iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 0, 0, - hdr_len + content_len); - iov_iter_advance(&iter, troff); - tr_hdr =3D hdr_blob + troff; + if (must_copy) { + rc =3D smb_copy_data_into_buffer(server, head_smb, &iter, &head_bq); + if (rc) + return rc; + copy_bq =3D head_bq.next; + } else { + head_bq.next =3D &head_smb->bvecq; + } =20 - rc =3D server->ops->init_transform_rq(server, head_smb, tr_hdr, &iter); - if (rc) - goto error; - content_len +=3D sizeof(*tr_hdr); + /* Attempt to do compression. This may fail at this point if the data + * isn't sufficiently compressible. Note that the signature hash is + * calculated over the decompressed content. + */ + if (head_smb->sr_flags & CIFS_COMPRESS_REQ) { + iov_iter_bvec_queue(&iter, ITER_SOURCE, copy_bq, 0, 0, + content_len); + + z_hdr =3D hdr_blob + zoff; + rc =3D smb_compress(server, &iter, ©_bq, z_hdr); + if (rc > 0) { + content_len =3D rc; + } else if (rc =3D=3D -EMSGSIZE) { + /* Fall back to uncompressed. */ + hdr_len -=3D sizeof(*z_hdr); + head_bv.bv_len =3D hdr_len; } else { - bvec_set_virt(&bq->bv[0], hdr_blob, hdr_len); + if (rc =3D=3D 0) + rc =3D smb_EIO(smb_eio_trace_tx_compress_failed); + goto error; } + } =20 - /* Set the RFC1002 header at the front. */ - rfc1002 =3D hdr_blob; - *rfc1002 =3D cpu_to_be32(RFC1002_SESSION_MESSAGE << 24 | content_len); + /* We can now encrypt the data - which includes the Compress header. + * The buffer will have been fixed up so that we can encrypt in-place. + * TODO: We could use async crypto or offload, but we will have to make + * sure the PDUs get transmitted in the right order. + */ + if (head_smb->sr_flags & CIFS_TRANSFORM_REQ) { + iov_iter_bvec_queue(&iter, ITER_SOURCE, copy_bq, 0, 0, + hdr_len + content_len); + iov_iter_advance(&iter, troff); + tr_hdr =3D hdr_blob + troff; =20 - iov_iter_bvec_queue(&iter, ITER_SOURCE, bq, 0, 0, 4 + content_len); + rc =3D server->ops->init_transform_rq(server, head_smb, tr_hdr, &iter); + if (rc) + goto error; } + + /* Set the RFC1002 header at the front. */ + rfc1002 =3D hdr_blob; + *rfc1002 =3D cpu_to_be32(RFC1002_SESSION_MESSAGE << 24 | + (hdr_len - sizeof(*rfc1002) + content_len)); + + iov_iter_bvec_queue(&iter, ITER_SOURCE, &head_bq, 0, 0, hdr_len + content= _len); rc =3D __smb_send_rqst(server, &iter); error: - bvecq_put(bq); + cifs_free_tx_buf(hdr_blob); + bvecq_put(copy_bq); return rc; } =20 @@ -1039,7 +1118,7 @@ cifs_call_async(struct TCP_Server_Info *server, struc= t smb_message *smb, * I/O response may come back and free the mid entry on another thread. */ cifs_save_when_sent(smb); - rc =3D smb_send_rqst(server, smb, flags); + rc =3D smb_send_rqst(server, smb); =20 if (rc < 0) { revert_current_mid(server, smb->credits_consumed); @@ -1280,7 +1359,7 @@ int smb_send_recv_messages(const unsigned int xid, st= ruct cifs_ses *ses, smb->mid_state =3D MID_REQUEST_SUBMITTED; } =20 - rc =3D smb_send_rqst(server, head_smb, flags); + rc =3D smb_send_rqst(server, head_smb); =20 for (struct smb_message *smb =3D head_smb; smb; smb =3D smb->next) cifs_save_when_sent(smb); @@ -1432,7 +1511,6 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, smb->request =3D request; smb->rqst =3D *rq; smb->sr_flags =3D flags; - smb->data_iter =3D rq->rq_iter; =20 if (is_smb1(server)) { smb->command =3D 0; @@ -1441,7 +1519,6 @@ compound_send_recv(const unsigned int xid, struct cif= s_ses *ses, =20 for (int j =3D 0; j < rq->rq_nvec; j++) smb->total_len +=3D rq->rq_iov[j].iov_len; - smb->total_len +=3D iov_iter_count(&rq->rq_iter); } =20 rc =3D smb_send_recv_messages(xid, ses, server, head_smb, flags); From nobody Mon May 25 02:42:24 2026 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 4F2B435203B for ; Tue, 19 May 2026 10:25:01 +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=1779186304; cv=none; b=nF7OBiiKloArj+w8JJgHPXePqI0/h4kI2l4CvYhL83eIE3MgDaZjFmedMhk9kBVIL+h1m+EsTmfSEPV8SN3v05hHNK4gKAJWI+5B7CO2Nw1yTyYTQMeoMZ13Peirjg6c9wZJWpvlMDu79GGSyhKaTLq1z2F/00ZUtZJyHu69bAY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186304; c=relaxed/simple; bh=X0h+5AVptZC7q+xWofUw4swviG9Q3/4vLX7eXdNe/co=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=SQToe4RmwPI5lnYE1v4KVbZF4FJUFvQ0iy2Q+GmK5GT0kBCXBCi9lrUthXS2SPczHPYK3oR6PKc1O0Ej0yVYcmoArBX8P6553u+tzTrPVxuS/6RpMtRY0woqW2EkKrwFaJNM7g6TX70G/VHe0yFXzkAHnIrh2m98qtVCYRVq9PM= 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=gL0KzgVl; 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="gL0KzgVl" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186300; 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=d1SaZ+L79QQpkjXffUXdCdtrti4DUONWZdg8TYYyE8Y=; b=gL0KzgVla9hxeTt3hHg3NJ/5fnlq+T2CuP0ELfB3+VlgXNmZHc7EcKahZm2p3lxBOZrN0L Q4N5oyLkpqyUIiiDOZytVrCfgePpFWQI4WpHPhIHkuIpb/DrvMisLnf5NJYiy0j4CZ312e 0Hj0t/S/J0h7umhxXk2LedA3Mz51St4= Received: from mx-prod-mc-06.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-577-KEE-ULsUMymotRhuVNfIaQ-1; Tue, 19 May 2026 06:24:55 -0400 X-MC-Unique: KEE-ULsUMymotRhuVNfIaQ-1 X-Mimecast-MFC-AGG-ID: KEE-ULsUMymotRhuVNfIaQ_1779186293 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A4A5E18005B8; Tue, 19 May 2026 10:24:53 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 7DD06180056E; Tue, 19 May 2026 10:24:50 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 34/36] cifs: [WIP] Rearrange Create request subfuncs Date: Tue, 19 May 2026 11:21:52 +0100 Message-ID: <20260519102158.592165-35-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 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/smb2pdu.c | 355 ++++++++++++++++++++-------------------- 1 file changed, 177 insertions(+), 178 deletions(-) diff --git a/fs/smb/client/smb2pdu.c b/fs/smb/client/smb2pdu.c index 01d84f9ece82..6747886024c4 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -1267,60 +1267,6 @@ static int smb311_decode_neg_context(struct smb_mess= age *smb, return rc; } =20 -static struct create_posix * -create_posix_buf(umode_t mode) -{ - struct create_posix *buf; - - buf =3D kzalloc_obj(struct create_posix); - if (!buf) - return NULL; - - 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); - - /* 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); - return buf; -} - -static int -add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) -{ - unsigned int num =3D *num_iovec; - - iov[num].iov_base =3D create_posix_buf(mode); - if (mode =3D=3D ACL_NO_MODE) - cifs_dbg(FYI, "%s: no mode\n", __func__); - if (iov[num].iov_base =3D=3D NULL) - return -ENOMEM; - iov[num].iov_len =3D sizeof(struct create_posix); - *num_iovec =3D num + 1; - return 0; -} - - /* * * SMB2 Worker functions follow: @@ -2524,6 +2470,59 @@ SMB2_tdis(const unsigned int xid, struct cifs_tcon *= tcon) return rc; } =20 +static struct create_posix * +create_posix_buf(umode_t mode) +{ + struct create_posix *buf; + + buf =3D kzalloc_obj(struct create_posix); + if (!buf) + return NULL; + + 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); + + /* 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); + return buf; +} + +static int +add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) +{ + unsigned int num =3D *num_iovec; + + iov[num].iov_base =3D create_posix_buf(mode); + if (mode =3D=3D ACL_NO_MODE) + cifs_dbg(FYI, "%s: no mode\n", __func__); + if (iov[num].iov_base =3D=3D NULL) + return -ENOMEM; + iov[num].iov_len =3D sizeof(struct create_posix); + *num_iovec =3D num + 1; + return 0; +} + static create_durable_req_t * create_durable_buf(void) { @@ -2572,130 +2571,6 @@ create_reconnect_durable_buf(struct cifs_fid *fid) return buf; } =20 -static void -parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *= buf) -{ - struct create_disk_id_rsp *pdisk_id =3D (struct create_disk_id_rsp *)cc; - - cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n", - pdisk_id->DiskFileId, pdisk_id->VolumeId); - buf->IndexNumber =3D pdisk_id->DiskFileId; -} - -static void -parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *inf= o, - struct create_posix_rsp *posix) -{ - int sid_len; - u8 *beg =3D (u8 *)cc + le16_to_cpu(cc->DataOffset); - u8 *end =3D beg + le32_to_cpu(cc->DataLength); - u8 *sid; - - memset(posix, 0, sizeof(*posix)); - - posix->nlink =3D le32_to_cpu(*(__le32 *)(beg + 0)); - posix->reparse_tag =3D le32_to_cpu(*(__le32 *)(beg + 4)); - posix->mode =3D le32_to_cpu(*(__le32 *)(beg + 8)); - - sid =3D beg + 12; - sid_len =3D posix_info_sid_size(sid, end); - if (sid_len < 0) { - cifs_dbg(VFS, "bad owner sid in posix create response\n"); - return; - } - memcpy(&posix->owner, sid, sid_len); - - sid =3D sid + sid_len; - sid_len =3D posix_info_sid_size(sid, end); - if (sid_len < 0) { - cifs_dbg(VFS, "bad group sid in posix create response\n"); - return; - } - memcpy(&posix->group, sid, sid_len); - - cifs_dbg(FYI, "nlink=3D%d mode=3D%o reparse_tag=3D%x\n", - posix->nlink, posix->mode, posix->reparse_tag); -} - -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) -{ - struct smb2_create_rsp *rsp =3D rsp_iov->iov_base; - struct create_context *cc; - size_t rem, off, len; - size_t doff, dlen; - size_t noff, nlen; - char *name; - static const char smb3_create_tag_posix[] =3D { - 0x93, 0xAD, 0x25, 0x50, 0x9C, - 0xB4, 0x11, 0xE7, 0xB4, 0x23, 0x83, - 0xDE, 0x96, 0x8B, 0xCD, 0x7C - }; - - *oplock =3D 0; - - 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) - return -EINVAL; - cc =3D (struct create_context *)((u8 *)rsp + off); - - /* Initialize inode number to 0 in case no valid data in qfid context */ - if (buf) - buf->IndexNumber =3D 0; - - while (rem >=3D sizeof(*cc)) { - doff =3D le16_to_cpu(cc->DataOffset); - dlen =3D le32_to_cpu(cc->DataLength); - if (check_add_overflow(doff, dlen, &len) || len > rem) - return -EINVAL; - - noff =3D le16_to_cpu(cc->NameOffset); - nlen =3D le16_to_cpu(cc->NameLength); - if (noff + nlen > doff) - return -EINVAL; - - name =3D (char *)cc + noff; - switch (nlen) { - case 4: - if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) { - *oplock =3D server->ops->parse_lease_buf(cc, epoch, - lease_key); - } else if (buf && - !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) { - parse_query_id_ctxt(cc, buf); - } - break; - case 16: - if (posix && !memcmp(name, smb3_create_tag_posix, 16)) - parse_posix_ctxt(cc, buf, posix); - break; - default: - cifs_dbg(FYI, "%s: unhandled context (nlen=3D%zu dlen=3D%zu)\n", - __func__, nlen, dlen); - if (IS_ENABLED(CONFIG_CIFS_DEBUG2)) - cifs_dump_mem("context data: ", cc, dlen); - break; - } - - off =3D le32_to_cpu(cc->Next); - if (!off) - break; - if (check_sub_overflow(rem, off, &rem)) - return -EINVAL; - cc =3D (struct create_context *)((u8 *)cc + off); - } - - if (rsp->OplockLevel !=3D SMB2_OPLOCK_LEVEL_LEASE) - *oplock =3D rsp->OplockLevel; - - return 0; -} - static int add_lease_context(struct TCP_Server_Info *server, struct smb2_create_req *req, @@ -3466,6 +3341,130 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_S= erver_Info *server, return 0; } =20 +static void +parse_query_id_ctxt(struct create_context *cc, struct smb2_file_all_info *= buf) +{ + struct create_disk_id_rsp *pdisk_id =3D (struct create_disk_id_rsp *)cc; + + cifs_dbg(FYI, "parse query id context 0x%llx 0x%llx\n", + pdisk_id->DiskFileId, pdisk_id->VolumeId); + buf->IndexNumber =3D pdisk_id->DiskFileId; +} + +static void +parse_posix_ctxt(struct create_context *cc, struct smb2_file_all_info *inf= o, + struct create_posix_rsp *posix) +{ + int sid_len; + u8 *beg =3D (u8 *)cc + le16_to_cpu(cc->DataOffset); + u8 *end =3D beg + le32_to_cpu(cc->DataLength); + u8 *sid; + + memset(posix, 0, sizeof(*posix)); + + posix->nlink =3D le32_to_cpu(*(__le32 *)(beg + 0)); + posix->reparse_tag =3D le32_to_cpu(*(__le32 *)(beg + 4)); + posix->mode =3D le32_to_cpu(*(__le32 *)(beg + 8)); + + sid =3D beg + 12; + sid_len =3D posix_info_sid_size(sid, end); + if (sid_len < 0) { + cifs_dbg(VFS, "bad owner sid in posix create response\n"); + return; + } + memcpy(&posix->owner, sid, sid_len); + + sid =3D sid + sid_len; + sid_len =3D posix_info_sid_size(sid, end); + if (sid_len < 0) { + cifs_dbg(VFS, "bad group sid in posix create response\n"); + return; + } + memcpy(&posix->group, sid, sid_len); + + cifs_dbg(FYI, "nlink=3D%d mode=3D%o reparse_tag=3D%x\n", + posix->nlink, posix->mode, posix->reparse_tag); +} + +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) +{ + struct smb2_create_rsp *rsp =3D rsp_iov->iov_base; + struct create_context *cc; + size_t rem, off, len; + size_t doff, dlen; + size_t noff, nlen; + char *name; + static const char smb3_create_tag_posix[] =3D { + 0x93, 0xAD, 0x25, 0x50, 0x9C, + 0xB4, 0x11, 0xE7, 0xB4, 0x23, 0x83, + 0xDE, 0x96, 0x8B, 0xCD, 0x7C + }; + + *oplock =3D 0; + + 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) + return -EINVAL; + cc =3D (struct create_context *)((u8 *)rsp + off); + + /* Initialize inode number to 0 in case no valid data in qfid context */ + if (buf) + buf->IndexNumber =3D 0; + + while (rem >=3D sizeof(*cc)) { + doff =3D le16_to_cpu(cc->DataOffset); + dlen =3D le32_to_cpu(cc->DataLength); + if (check_add_overflow(doff, dlen, &len) || len > rem) + return -EINVAL; + + noff =3D le16_to_cpu(cc->NameOffset); + nlen =3D le16_to_cpu(cc->NameLength); + if (noff + nlen > doff) + return -EINVAL; + + name =3D (char *)cc + noff; + switch (nlen) { + case 4: + if (!strncmp(name, SMB2_CREATE_REQUEST_LEASE, 4)) { + *oplock =3D server->ops->parse_lease_buf(cc, epoch, + lease_key); + } else if (buf && + !strncmp(name, SMB2_CREATE_QUERY_ON_DISK_ID, 4)) { + parse_query_id_ctxt(cc, buf); + } + break; + case 16: + if (posix && !memcmp(name, smb3_create_tag_posix, 16)) + parse_posix_ctxt(cc, buf, posix); + break; + default: + cifs_dbg(FYI, "%s: unhandled context (nlen=3D%zu dlen=3D%zu)\n", + __func__, nlen, dlen); + if (IS_ENABLED(CONFIG_CIFS_DEBUG2)) + cifs_dump_mem("context data: ", cc, dlen); + break; + } + + off =3D le32_to_cpu(cc->Next); + if (!off) + break; + if (check_sub_overflow(rem, off, &rem)) + return -EINVAL; + cc =3D (struct create_context *)((u8 *)cc + off); + } + + if (rsp->OplockLevel !=3D SMB2_OPLOCK_LEVEL_LEASE) + *oplock =3D rsp->OplockLevel; + + return 0; +} + /* rq_iov[0] is the request and is released by cifs_small_buf_release(). * All other vectors are freed by kfree(). */ From nobody Mon May 25 02:42:24 2026 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.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 990094D9906 for ; Tue, 19 May 2026 10:25:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=170.10.133.124 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186306; cv=none; b=XxO+KY2yMM45C6Y4l4pHo/i+YRj8q+XyQ95082+G2Lgt5kOMQQGPr12qpqmVf/0AZB97sDpvkt38aX1pieTCmDGbLjn6QrO9HkNxQETbH4SW4XMgA5CE5EnEstulns1ZeOGDs9oyGTeURDQCSNzQZ43I6vyOpkrqvW5faaRHRbI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186306; c=relaxed/simple; bh=sVlVfRVLd+wyRHWm6he/XPWksu42m3SlMjc6YynhkW8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DQk7JTn3iBuDt1mqxeasHrDoju/sLXv13oadxKWeSA9EHvB7i4jxz/ixzHzoWHQni2hcDvv0uKVAIqo3zTTNdK9MVqWRRxnUHzDZMXltZiFxTCxUfYZSnbNhJGLfqFc/kE2XgsQPVq7IyuVOEdExzES936dmYJldiYZ6q1dDZ9c= 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=RXX+Q4SS; arc=none smtp.client-ip=170.10.133.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="RXX+Q4SS" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186303; 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=h9AT4ZXzx43KbkFm0U0Dvica8KBzMIOrhGP2OEXKA24=; b=RXX+Q4SSEQVe7stgF8C9PPrQSstpz+CccZ1I7YFVA3Cz3mCB5UMj5t4gKn+yQ+10tzDhtu EgioLstV/+kwxaB+pNAwYsOHmHS1ZiOKPKGoXsu8zZrVQmAMZV5alLINfUTDzajaIaCES+ MglFREsNtXPLZz5iX2v6jP3mxcFPgoM= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-58-AGp3xDXhMEC36rA6wX63Ig-1; Tue, 19 May 2026 06:25:00 -0400 X-MC-Unique: AGp3xDXhMEC36rA6wX63Ig-1 X-Mimecast-MFC-AGG-ID: AGp3xDXhMEC36rA6wX63Ig_1779186298 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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id 6B5951956095; Tue, 19 May 2026 10:24:58 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 4115A1955F22; Tue, 19 May 2026 10:24:55 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 35/36] cifs: [WIP] Convert SMB2 Posix Mkdir request Date: Tue, 19 May 2026 11:21:53 +0100 Message-ID: <20260519102158.592165-36-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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/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; } =20 -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 =3D kzalloc_obj(struct create_posix); - if (!buf) - return NULL; - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof(struct create_posix, Mode)); buf->ccontext.DataLength =3D cpu_to_le32(4); @@ -2505,20 +2498,25 @@ create_posix_buf(umode_t mode) buf->Name[15] =3D 0x7C; buf->Mode =3D cpu_to_le32(mode); cifs_dbg(FYI, "mode on posix create 0%o\n", mode); - return buf; } =20 static int add_posix_context(struct kvec *iov, unsigned int *num_iovec, umode_t mode) { + struct create_posix *buf; unsigned int num =3D *num_iovec; =20 - iov[num].iov_base =3D create_posix_buf(mode); if (mode =3D=3D ACL_NO_MODE) cifs_dbg(FYI, "%s: no mode\n", __func__); - if (iov[num].iov_base =3D=3D NULL) + + buf =3D kzalloc_obj(struct create_posix); + if (!buf) return -ENOMEM; - iov[num].iov_len =3D sizeof(struct create_posix); + + 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; } @@ -2986,73 +2984,141 @@ alloc_path_with_tree_prefix(__le16 **out_path, int= *out_size, int *out_len, return 0; } =20 +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 =3D lay->offset; + size_t tmp; + bool has_contexts =3D 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 =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 ALIGN8(offset); + lay->name_pad =3D offset - tmp; + lay->contexts_offset =3D offset; + + if (tcon->posix_extensions) { + /* resource #3: posix buf */ + offset +=3D sizeof(struct create_posix); + has_contexts =3D true; + } + + if (has_contexts) + lay->contexts_len =3D offset - lay->contexts_offset; + else + lay->contexts_offset =3D 0; + + lay->offset =3D 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 =3D NULL; + struct smb_message *smb =3D NULL; struct cifs_ses *ses =3D tcon->ses; - struct kvec iov[3]; /* make sure at least one for each open context */ - struct kvec rsp_iov =3D {NULL, 0}; - int resp_buftype; - int uni_path_len; - __le16 *copy_path =3D NULL; - int copy_size; - int rc =3D 0; - unsigned int n_iov =3D 2; - __u32 file_attributes =3D 0; - char *pc_buf =3D NULL; - int flags =3D 0; - unsigned int total_len; __le16 *utf16_path =3D NULL; struct TCP_Server_Info *server; - int retries =3D 0, cur_sleep =3D 0; + int retries =3D 0, cur_sleep =3D 0, path_len; + + if (!ses) { + rc =3D smb_EIO(smb_eio_trace_null_pointers); + + /* resource #1: path allocation */ + utf16_path =3D cifs_convert_path_to_utf16(full_path, cifs_sb); + if (!utf16_path) + return -ENOMEM; + path_len =3D UniStrlen(utf16_path); =20 replay_again: /* reinitialize for possible replay */ - pc_buf =3D NULL; flags =3D 0; - n_iov =3D 2; server =3D cifs_pick_channel(ses); =20 cifs_dbg(FYI, "mkdir\n"); =20 - /* resource #1: path allocation */ - utf16_path =3D cifs_convert_path_to_utf16(full_path, cifs_sb); - if (!utf16_path) - return -ENOMEM; - - if (!ses || !server) { - rc =3D smb_EIO(smb_eio_trace_null_pointers); + if (!server) { + rc =3D -EIO; goto err_free_path; } =20 + struct smb2_create_layout layout =3D { + .offset =3D sizeof(struct smb2_create_req), + .path_len =3D path_len, + .cp =3D cifs_sb->local_nls, + }; + rc =3D smb311_posix_mkdir_layout(tcon, &layout); + if (rc < 0) + goto err_free_path; + /* resource #2: request */ - rc =3D smb2_plain_req_init(SMB2_CREATE, tcon, server, - (void **) &req, &total_len); - if (rc) + rc =3D -ENOMEM; + smb =3D smb2_create_request(SMB2_CREATE, server, tcon, + sizeof(*req), layout.offset, 0, + SMB2_REQ_DYNAMIC); + if (!smb) goto err_free_path; =20 =20 if (smb3_encryption_required(tcon)) flags |=3D CIFS_TRANSFORM_REQ; =20 - req->ImpersonationLevel =3D IL_IMPERSONATION; - req->DesiredAccess =3D cpu_to_le32(FILE_WRITE_ATTRIBUTES); + req->ImpersonationLevel =3D IL_IMPERSONATION; + req->DesiredAccess =3D cpu_to_le32(FILE_WRITE_ATTRIBUTES); /* 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(FILE_CREATE); - req->CreateOptions =3D cpu_to_le32(CREATE_NOT_FILE); - - 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; - - 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(FILE_CREATE); + req->CreateOptions =3D cpu_to_le32(CREATE_NOT_FILE); + 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 @@ -3062,61 +3128,32 @@ int smb311_posix_mkdir(const unsigned int xid, stru= ct inode *inode, * 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, utf16_path); - if (rc) - goto err_free_req; =20 - req->NameLength =3D cpu_to_le16(name_len * 2); - uni_path_len =3D copy_size; - /* free before overwriting resource */ - kfree(utf16_path); - utf16_path =3D copy_path; - } else { - uni_path_len =3D (2 * UniStrnlen((wchar_t *)utf16_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); - if (uni_path_len % 8 !=3D 0) { - copy_size =3D roundup(uni_path_len, 8); - copy_path =3D kzalloc(copy_size, GFP_KERNEL); - if (!copy_path) { - rc =3D -ENOMEM; - goto err_free_req; - } - memcpy((char *)copy_path, (const char *)utf16_path, - uni_path_len); - uni_path_len =3D copy_size; - /* free before overwriting resource */ - kfree(utf16_path); - utf16_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, utf16_path, layout.path_len); } + } else { + memcpy(name, utf16_path, layout.path_len); } =20 - iov[1].iov_len =3D uni_path_len; - iov[1].iov_base =3D utf16_path; - req->RequestedOplockLevel =3D SMB2_OPLOCK_LEVEL_NONE; + if (layout.name_pad) + memset(smb->request + layout.name_offset + layout.name_len, + 0, layout.name_pad); =20 - if (tcon->posix_extensions) { + if (tcon->posix_extensions) /* resource #3: posix buf */ - rc =3D add_posix_context(iov, &n_iov, mode); - if (rc) - goto err_free_req; - req->CreateContextsOffset =3D 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 =3D iov[n_iov-1].iov_base; - } - - - memset(&rqst, 0, sizeof(struct smb_rqst)); - rqst.rq_iov =3D iov; - rqst.rq_nvec =3D n_iov; + fill_posix_buf(smb->request + layout.posix_offset, 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, @@ -3126,18 +3163,17 @@ int smb311_posix_mkdir(const unsigned int xid, stru= ct inode *inode, /* Back-off before retry */ if (cur_sleep) msleep(cur_sleep); - smb2_set_replay(server, &rqst); + smb2_set_replay(server, smb); } =20 /* resource #4: response buffer */ - rc =3D cifs_send_recv(xid, ses, server, - &rqst, &resp_buftype, flags, &rsp_iov); + rc =3D 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; } =20 /* @@ -3145,10 +3181,9 @@ int smb311_posix_mkdir(const unsigned int xid, struc= t inode *inode, * adding check below is slightly safer long term (and quiets Coverity * warning) */ - rsp =3D (struct smb2_create_rsp *)rsp_iov.iov_base; + rsp =3D (struct smb2_create_rsp *)smb->response; if (rsp =3D=3D NULL) { rc =3D smb_EIO(smb_eio_trace_mkdir_no_rsp); - kfree(pc_buf); goto err_free_req; } =20 @@ -3160,18 +3195,14 @@ int smb311_posix_mkdir(const unsigned int xid, stru= ct inode *inode, =20 /* Eventually save off posix specific response info and timestamps */ =20 -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; =20 + kfree(utf16_path); return rc; } From nobody Mon May 25 02:42:24 2026 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 A1AF7370AFA for ; Tue, 19 May 2026 10:25:09 +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=1779186312; cv=none; b=E49IU0TNZCG4Ny5jFoBGzlPqPw4YgaZlTEE2N75TSRSmPfzjFGdA33SYfPupcPwchLNLQd3N50jjDDhCH1bqhkoBjyAe9U50nZ3997saK4ewYvbfZzxgmVrgfCyrwseCuXA4TXejUz66HHGRZ6sjhnBNlPBSQA8dGLrUxQMVU+s= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779186312; c=relaxed/simple; bh=7gzRKL2KFrk7ZMB0fd+X4egw+hxhE71soBf2dR6YtrI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=tA1evu3B7VjM5snZGlRtuveSXv1297GJLEnJnbwR+ubxaZi+WsEQv3UHZDt5vEJWUO6D8edZ3s+B41aA3tt/HEJvWDVuEgoIJwGt/a6clAalN0E0WJWbB+HXrHn9J2sg+sfe+RMmekeRV77zs69RAm2kYdXMOTtuuAM5oOJNdfg= 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=fgONBy/d; 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="fgONBy/d" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1779186308; 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=oJPybgKBz/zzKKS0BSKe39kCjwE802bY9qlkLsERYFk=; b=fgONBy/dHqsbkhgjPFvzi9wKSnVmkzy2ygWfB5YD2jfArkFBH3G4g65H8DGWVQhJdiZ/8E r9I0Tyudp+1u5kIPHCZmDyid5mzangq/lDq7NWPOUQro+9oG3mKDEzOhJXYXy8/dSEZQNE P5ZcfRSfmXP9fm5wnVO6Jpau0tCmjWo= Received: from mx-prod-mc-03.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-403-vUQZS36WOdK9mUdwiSGTag-1; Tue, 19 May 2026 06:25:05 -0400 X-MC-Unique: vUQZS36WOdK9mUdwiSGTag-1 X-Mimecast-MFC-AGG-ID: vUQZS36WOdK9mUdwiSGTag_1779186303 Received: from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93]) (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-03.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id C81841956060; Tue, 19 May 2026 10:25:03 +0000 (UTC) Received: from warthog.procyon.org.com (unknown [10.44.48.33]) by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 1EE6C1800357; Tue, 19 May 2026 10:24:59 +0000 (UTC) From: David Howells To: Steve French Cc: David Howells , Paulo Alcantara , Shyam Prasad N , Tom Talpey , 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 36/36] cifs: [WIP] Convert SMB2 Open request Date: Tue, 19 May 2026 11:21:54 +0100 Message-ID: <20260519102158.592165-37-dhowells@redhat.com> In-Reply-To: <20260519102158.592165-1-dhowells@redhat.com> References: <20260519102158.592165-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.4.1 on 10.30.177.93 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 | 880 +++++++++++++++---------------------- fs/smb/client/smb2proto.h | 24 +- 6 files changed, 401 insertions(+), 589 deletions(-) diff --git a/fs/smb/client/cached_dir.c b/fs/smb/client/cached_dir.c index 88d5e9a32f28..4a4063d2c903 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; @@ -261,29 +259,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; =20 @@ -349,10 +338,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 e5972ac80240..616eec52aa7d 100644 --- a/fs/smb/client/cifsglob.h +++ b/fs/smb/client/cifsglob.h @@ -530,8 +530,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 6789049db053..73819629af19 100644 --- a/fs/smb/client/smb2inode.c +++ b/fs/smb/client/smb2inode.c @@ -579,9 +579,9 @@ static int smb2_compound_op(const unsigned int xid, str= uct cifs_tcon *tcon, idata->fi.DeletePending =3D 0; /* successful open =3D not delete pending= */ 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 0e212a3e883d..f6598ea0a2de 100644 --- a/fs/smb/client/smb2ops.c +++ b/fs/smb/client/smb2ops.c @@ -4248,14 +4248,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_obj(struct create_lease); - 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); @@ -4271,17 +4268,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_obj(struct create_lease_v2); - 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); @@ -4300,7 +4294,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 @@ -4628,7 +4622,7 @@ struct smb_version_operations smb20_operations =3D { .new_lease_key =3D smb2_new_lease_key, .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, @@ -4719,7 +4713,7 @@ struct smb_version_operations smb21_operations =3D { .new_lease_key =3D smb2_new_lease_key, .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, @@ -4817,7 +4811,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, @@ -4919,7 +4913,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 3eeaf027115c..1374d9251dc2 100644 --- a/fs/smb/client/smb2pdu.c +++ b/fs/smb/client/smb2pdu.c @@ -2470,296 +2470,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_obj(struct create_posix); - 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 create_durable_req_t * -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) { - create_durable_req_t *buf; - - buf =3D kzalloc_obj(create_durable_req_t); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (create_durable_req_t, Data)); - buf->ccontext.DataLength =3D cpu_to_le32(16); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (create_durable_req_t, 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 create_durable_req_t * -create_reconnect_durable_buf(struct cifs_fid *fid) +static void fill_durable_v1_context(struct smb_message *smb) { - create_durable_req_t *buf; + struct create_durable *buf =3D cifs_begin_ccontext(smb); =20 - buf =3D kzalloc_obj(create_durable_req_t); - if (!buf) - return NULL; - - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (create_durable_req_t, Data)); - buf->ccontext.DataLength =3D cpu_to_le32(16); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (create_durable_req_t, 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_req_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_req_v2 *buf; - - buf =3D kzalloc_obj(struct create_durable_req_v2); - if (!buf) - return NULL; + struct create_durable_v2 *buf =3D cifs_begin_ccontext(smb); + struct cifs_fid *fid =3D oparms->fid; =20 - buf->ccontext.DataOffset =3D cpu_to_le16(offsetof - (struct create_durable_req_v2, dcontext)); - buf->ccontext.DataLength =3D cpu_to_le32(sizeof(struct durable_context_v2= _req)); - buf->ccontext.NameOffset =3D cpu_to_le16(offsetof - (struct create_durable_req_v2, Name)); - buf->ccontext.NameLength =3D cpu_to_le16(4); + *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 - /* - * 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_obj(struct create_durable_handle_reconnect_v2); - 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_req_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(create_durable_req_t); - *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_obj(struct crt_twarp_ctxt); - 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= */ @@ -2787,26 +2670,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) { @@ -2872,33 +2750,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_obj(struct crt_query_id_ctxt); - 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); @@ -2910,78 +2770,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)}; - - /* - * 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); + void *p =3D cifs_begin_extension(smb); =20 - /* 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 { @@ -2993,7 +2794,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 @@ -3001,8 +2801,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 @@ -3031,22 +2829,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; } @@ -3147,13 +2940,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, @@ -3206,81 +2998,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; + 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; @@ -3292,32 +3188,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)) { @@ -3336,40 +3221,13 @@ SMB2_open_init(struct cifs_tcon *tcon, struct TCP_S= erver_Info *server, set_owner =3D sbflags & CIFS_MOUNT_UID_FROM_ACL; 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; - } - } - - 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); + fill_sd_context(smb, oparms->mode, set_owner); } - le32_add_cpu(&req->CreateContextsLength, - iov[n_iov-1].iov_len); } =20 - rqst->rq_nvec =3D n_iov; - return 0; + fill_query_id_context(smb); + fill_ea_context(smb, oparms); + return smb; } =20 static void @@ -3417,14 +3275,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; @@ -3440,7 +3298,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 @@ -3496,39 +3354,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 retries =3D 0, cur_sleep =3D 1; int flags =3D 0; - int retries =3D 0, cur_sleep =3D 0; + int rc =3D 0; =20 replay_again: /* reinitialize for possible replay */ @@ -3543,15 +3380,12 @@ 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); @@ -3560,21 +3394,17 @@ SMB2_open(const unsigned int xid, struct cifs_open_= parms *oparms, __le16 *path, /* Back-off before retry */ if (cur_sleep) msleep(cur_sleep); - smb2_set_replay(server, &rqst); + smb2_set_replay(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_HE); 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); @@ -3584,9 +3414,14 @@ SMB2_open(const unsigned int xid, struct cifs_open_p= arms *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; =20 + trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, + oparms->create_options, oparms->desired_access, + *oplock); + atomic_inc(&tcon->num_remote_opens); oparms->fid->persistent_fid =3D rsp->PersistentFileId; oparms->fid->volatile_fid =3D rsp->VolatileFileId; @@ -3607,17 +3442,10 @@ SMB2_open(const unsigned int xid, struct cifs_open_= parms *oparms, __le16 *path, buf->DeletePending =3D 0; /* successful open =3D not delete pending */ } =20 - - rc =3D smb2_parse_contexts(server, &rsp_iov, &oparms->fid->epoch, - oparms->fid->lease_key, oplock, buf, posix); - - trace_smb3_open_done(xid, rsp->PersistentFileId, tcon->tid, ses->Suid, - oparms->create_options, oparms->desired_access, - *oplock); + 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 6571a6a7b147..8d3f5271bc21 100644 --- a/fs/smb/client/smb2proto.h +++ b/fs/smb/client/smb2proto.h @@ -149,14 +149,12 @@ int SMB2_logoff(const unsigned int xid, struct cifs_s= es *ses); int SMB2_tcon(const unsigned int xid, struct cifs_ses *ses, const char *tr= ee, struct cifs_tcon *tcon, const struct nls_table *cp); int SMB2_tdis(const unsigned int xid, struct cifs_tcon *tcon); -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_init(struct cifs_tcon *tcon, struct TCP_Server_Info *server, - struct smb_rqst *rqst, __u8 *oplock, - struct cifs_open_parms *oparms, __le16 *path); -void SMB2_open_free(struct smb_rqst *rqst); +struct smb_message *SMB2_open_init(struct cifs_tcon *tcon, + struct TCP_Server_Info *server, __u8 *oplock, + struct cifs_open_parms *oparms, __le16 *path); +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); 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 max_out_data_len, char **out_data, @@ -258,10 +256,12 @@ int smb3_validate_negotiate(const unsigned int xid, s= truct cifs_tcon *tcon); =20 enum securityEnum smb2_select_sectype(struct TCP_Server_Info *server, enum securityEnum requested); -int smb2_parse_contexts(struct TCP_Server_Info *server, struct kvec *rsp_i= ov, - __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 int smb3_encryption_required(const struct cifs_tcon *tcon); int smb2_validate_iov(unsigned int offset, unsigned int buffer_length,