Add support for ITER_BVECQ to smbdirect_map_sges_from_iter().

Signed-off-by: David Howells <[email protected]>
Acked-by: Stefan Metzmacher <[email protected]>
cc: Paulo Alcantara <[email protected]>
cc: Matthew Wilcox <[email protected]>
cc: Christoph Hellwig <[email protected]>
cc: Steve French <[email protected]>
cc: Shyam Prasad N <[email protected]>
cc: Tom Talpey <[email protected]>
cc: [email protected]
cc: [email protected]
cc: [email protected]
---
 fs/smb/smbdirect/connection.c | 66 +++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/fs/smb/smbdirect/connection.c b/fs/smb/smbdirect/connection.c
index 8adf58097534..4d2a1700104e 100644
--- a/fs/smb/smbdirect/connection.c
+++ b/fs/smb/smbdirect/connection.c
@@ -5,6 +5,7 @@
  */
 
 #include "internal.h"
+#include <linux/bvecq.h>
 #include <linux/folio_queue.h>
 
 struct smbdirect_map_sges {
@@ -2006,6 +2007,68 @@ static ssize_t smbdirect_map_sges_from_bvec(struct 
iov_iter *iter,
        return ret;
 }
 
+/*
+ * Extract memory fragments from a BVECQ-class iterator and add them to an RDMA
+ * list.  The fragments are not pinned.
+ */
+static ssize_t smbdirect_map_sges_from_bvecq(struct iov_iter *iter,
+                                            struct smbdirect_map_sges *state,
+                                            ssize_t maxsize)
+{
+       const struct bvecq *bq = iter->bvecq;
+       unsigned int slot = iter->bvecq_slot;
+       ssize_t extracted = 0;
+       size_t offset = iter->iov_offset;
+
+       maxsize = umin(maxsize, iov_iter_count(iter));
+
+       do {
+               struct bio_vec *bv;
+               size_t bsize;
+
+               while (slot >= bq->nr_slots) {
+                       if (!bq->next) {
+                               if (WARN_ON_ONCE(maxsize > 0))
+                                       return -EIO;
+                               goto out;
+                       }
+                       bq = bq->next;
+                       slot = 0;
+               }
+
+               bv = &bq->bv[slot];
+               bsize = bv->bv_len;
+
+               if (offset < bsize) {
+                       size_t part = umin(maxsize, bsize - offset);
+                       bool ok;
+
+                       ok = smbdirect_map_sges_single_page(state,
+                                                           bv->bv_page,
+                                                           bv->bv_offset + 
offset,
+                                                           part);
+                       if (!ok)
+                               return -EIO;
+
+                       offset += part;
+                       extracted += part;
+                       maxsize -= part;
+               }
+
+               if (offset >= bsize) {
+                       offset = 0;
+                       slot++;
+               }
+       } while (state->num_sge < state->max_sge && maxsize > 0);
+
+out:
+       iter->bvecq = bq;
+       iter->bvecq_slot = slot;
+       iter->iov_offset = offset;
+       iter->count -= extracted;
+       return extracted;
+}
+
 /*
  * Extract fragments from a KVEC-class iterator and add them to an ib_sge list.
  * This can deal with vmalloc'd buffers as well as kmalloc'd or static buffers.
@@ -2155,6 +2218,9 @@ static ssize_t smbdirect_map_sges_from_iter(struct 
iov_iter *iter, size_t len,
        case ITER_BVEC:
                ret = smbdirect_map_sges_from_bvec(iter, state, len);
                break;
+       case ITER_BVECQ:
+               ret = smbdirect_map_sges_from_bvecq(iter, state, len);
+               break;
        case ITER_KVEC:
                ret = smbdirect_map_sges_from_kvec(iter, state, len);
                break;


Reply via email to