[PATCH] Fix folio conversion in __dma_page_dev_to_cpu()

Matthew Wilcox (Oracle) willy at infradead.org
Wed Aug 23 12:18:52 PDT 2023


Russell and Marek pointed out some assumptions I was making about how sg
lists work; eg that they are limited to 2GB and that the initial offset
lies within the first page (or at least within the first folio that a
page belongs to).  While I think those assumptions are true, it's not
too hard to write a version which does not have those assumptions and
also calculates folio_size() only once per loop iteration.

---
 arch/arm/mm/dma-mapping.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mm/dma-mapping.c b/arch/arm/mm/dma-mapping.c
index 0474840224d9..5409225b4abc 100644
--- a/arch/arm/mm/dma-mapping.c
+++ b/arch/arm/mm/dma-mapping.c
@@ -695,7 +695,6 @@ static void __dma_page_cpu_to_dev(struct page *page, unsigned long off,
 static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
 	size_t size, enum dma_data_direction dir)
 {
-	struct folio *folio = page_folio(page);
 	phys_addr_t paddr = page_to_phys(page) + off;
 
 	/* FIXME: non-speculating: not required */
@@ -710,18 +709,19 @@ static void __dma_page_dev_to_cpu(struct page *page, unsigned long off,
 	 * Mark the D-cache clean for these pages to avoid extra flushing.
 	 */
 	if (dir != DMA_TO_DEVICE && size >= PAGE_SIZE) {
-		ssize_t left = size;
+		struct folio *folio = pfn_folio(paddr / PAGE_SIZE);
 		size_t offset = offset_in_folio(folio, paddr);
 
-		if (offset) {
-			left -= folio_size(folio) - offset;
-			folio = folio_next(folio);
-		}
+		for (;;) {
+			size_t sz = folio_size(folio) - offset;
 
-		while (left >= (ssize_t)folio_size(folio)) {
-			left -= folio_size(folio);
-			set_bit(PG_dcache_clean, &folio->flags);
-			if (!left)
+			if (size < sz)
+				break;
+			if (!offset)
+				set_bit(PG_dcache_clean, &folio->flags);
+			offset = 0;
+			size -= sz;
+			if (!size)
 				break;
 			folio = folio_next(folio);
 		}
-- 
2.40.1




More information about the linux-arm-kernel mailing list