iommufd: Folio subroutines
authorSteve Sistare <steven.sistare@oracle.com>
Fri, 25 Oct 2024 13:11:55 +0000 (06:11 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Mon, 28 Oct 2024 16:24:24 +0000 (13:24 -0300)
Add subroutines for copying folios to a batch.

Link: https://patch.msgid.link/r/1729861919-234514-6-git-send-email-steven.sistare@oracle.com
Signed-off-by: Steve Sistare <steven.sistare@oracle.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/iommu/iommufd/pages.c

index 9097b25..aa79504 100644 (file)
@@ -346,27 +346,41 @@ static void batch_destroy(struct pfn_batch *batch, void *backup)
                kfree(batch->pfns);
 }
 
-/* true if the pfn was added, false otherwise */
-static bool batch_add_pfn(struct pfn_batch *batch, unsigned long pfn)
+static bool batch_add_pfn_num(struct pfn_batch *batch, unsigned long pfn,
+                             u32 nr)
 {
        const unsigned int MAX_NPFNS = type_max(typeof(*batch->npfns));
-
-       if (batch->end &&
-           pfn == batch->pfns[batch->end - 1] + batch->npfns[batch->end - 1] &&
-           batch->npfns[batch->end - 1] != MAX_NPFNS) {
-               batch->npfns[batch->end - 1]++;
-               batch->total_pfns++;
-               return true;
-       }
-       if (batch->end == batch->array_size)
+       unsigned int end = batch->end;
+
+       if (end && pfn == batch->pfns[end - 1] + batch->npfns[end - 1] &&
+           nr <= MAX_NPFNS - batch->npfns[end - 1]) {
+               batch->npfns[end - 1] += nr;
+       } else if (end < batch->array_size) {
+               batch->pfns[end] = pfn;
+               batch->npfns[end] = nr;
+               batch->end++;
+       } else {
                return false;
-       batch->total_pfns++;
-       batch->pfns[batch->end] = pfn;
-       batch->npfns[batch->end] = 1;
-       batch->end++;
+       }
+
+       batch->total_pfns += nr;
        return true;
 }
 
+static void batch_remove_pfn_num(struct pfn_batch *batch, unsigned long nr)
+{
+       batch->npfns[batch->end - 1] -= nr;
+       if (batch->npfns[batch->end - 1] == 0)
+               batch->end--;
+       batch->total_pfns -= nr;
+}
+
+/* true if the pfn was added, false otherwise */
+static bool batch_add_pfn(struct pfn_batch *batch, unsigned long pfn)
+{
+       return batch_add_pfn_num(batch, pfn, 1);
+}
+
 /*
  * Fill the batch with pfns from the domain. When the batch is full, or it
  * reaches last_index, the function will return. The caller should use
@@ -622,6 +636,41 @@ static void batch_from_pages(struct pfn_batch *batch, struct page **pages,
                        break;
 }
 
+static int batch_from_folios(struct pfn_batch *batch, struct folio ***folios_p,
+                            unsigned long *offset_p, unsigned long npages)
+{
+       int rc = 0;
+       struct folio **folios = *folios_p;
+       unsigned long offset = *offset_p;
+
+       while (npages) {
+               struct folio *folio = *folios;
+               unsigned long nr = folio_nr_pages(folio) - offset;
+               unsigned long pfn = page_to_pfn(folio_page(folio, offset));
+
+               nr = min(nr, npages);
+               npages -= nr;
+
+               if (!batch_add_pfn_num(batch, pfn, nr))
+                       break;
+               if (nr > 1) {
+                       rc = folio_add_pins(folio, nr - 1);
+                       if (rc) {
+                               batch_remove_pfn_num(batch, nr);
+                               goto out;
+                       }
+               }
+
+               folios++;
+               offset = 0;
+       }
+
+out:
+       *folios_p = folios;
+       *offset_p = offset;
+       return rc;
+}
+
 static void batch_unpin(struct pfn_batch *batch, struct iopt_pages *pages,
                        unsigned int first_page_off, size_t npages)
 {