[PATCH 17/26] cifs: Support ITER_BVECQ in smb_extract_iter_to_rdma()

David Howells
2026-03-26T10:48:40Z

Add support for ITER_BVECQ to smb_extract_iter_to_rdma().

Signed-off-by: David Howells <dhowells@redhat.com>
cc: Paulo Alcantara <pc@manguebit.org>
cc: Matthew Wilcox <willy@infradead.org>
cc: Christoph Hellwig <hch@infradead.org>
cc: Steve French <sfrench@samba.org>
cc: Shyam Prasad N <sprasad@microsoft.com>
cc: Tom Talpey <tom@talpey.com>
cc: linux-cifs@vger.kernel.org
cc: netfs@lists.linux.dev
cc: linux-fsdevel@vger.kernel.org
---
fs/smb/client/smbdirect.c | 60 +++++++++++++++++++++++++++++++++++++++
1 file changed, 60 insertions(+)

diff --git a/fs/smb/client/smbdirect.c b/fs/smb/client/smbdirect.c
index c79304012b08..f8a6be83db98 100644
--- a/fs/smb/client/smbdirect.c
+++ b/fs/smb/client/smbdirect.c
@@ -3298,6 +3298,63 @@ static ssize_t smb_extract_folioq_to_rdma(struct iov_iter *iter,
return ret;
}

+/*
+ * Extract memory fragments from a BVECQ-class iterator and add them to an RDMA
+ * list. The folios are not pinned.
+ */
+static ssize_t smb_extract_bvecq_to_rdma(struct iov_iter *iter,
+ struct smb_extract_to_rdma *rdma,
+ ssize_t maxsize)
+{
+ const struct bvecq *bq = iter->bvecq;
+ unsigned int slot = iter->bvecq_slot;
+ ssize_t ret = 0;
+ size_t offset = iter->iov_offset;
+
+ if (slot >= bq->nr_slots) {
+ bq = bq->next;
+ if (WARN_ON_ONCE(!bq))
+ return -EIO;
+ slot = 0;
+ }
+
+ do {
+ struct bio_vec *bv = &bq->bv[slot];
+ struct page *page = bv->bv_page;
+ size_t bsize = bv->bv_len;
+
+ if (offset < bsize) {
+ size_t part = umin(maxsize, bsize - offset);
+
+ if (!smb_set_sge(rdma, page, bv->bv_offset + offset, part))
+ return -EIO;
+
+ offset += part;
+ ret += part;
+ maxsize -= part;
+ }
+
+ if (offset >= bsize) {
+ offset = 0;
+ slot++;
+ if (slot >= bq->nr_slots) {
+ if (!bq->next) {
+ WARN_ON_ONCE(ret < iter->count);
+ break;
+ }
+ bq = bq->next;
+ slot = 0;
+ }
+ }
+ } while (rdma->nr_sge < rdma->max_sge && maxsize > 0);
+
+ iter->bvecq = bq;
+ iter->bvecq_slot = slot;
+ iter->iov_offset = offset;
+ iter->count -= ret;
+ return ret;
+}
+
/*
* Extract page fragments from up to the given amount of the source iterator
* and build up an RDMA list that refers to all of those bits. The RDMA list
@@ -3325,6 +3382,9 @@ static ssize_t smb_extract_iter_to_rdma(struct iov_iter *iter, size_t len,
case ITER_FOLIOQ:
ret = smb_extract_folioq_to_rdma(iter, rdma, len);
break;
+ case ITER_BVECQ:
+ ret = smb_extract_bvecq_to_rdma(iter, rdma, len);
+ break;
default:
WARN_ON_ONCE(1);
return -EIO;