[PATCH 08/10] ntfs3: Use a folio to read UpCase

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Add a memcpy_from_folio_le16() which does the byteswapping.
This is now large folio safe and avoids kmap().

Signed-off-by: Matthew Wilcox (Oracle) <willy@xxxxxxxxxxxxx>
---
 fs/ntfs3/super.c        | 25 +++++++++++--------------
 include/linux/highmem.h | 31 +++++++++++++++++++++++++++++++
 2 files changed, 42 insertions(+), 14 deletions(-)

diff --git a/fs/ntfs3/super.c b/fs/ntfs3/super.c
index f6a9ab0f5cad..00700598a717 100644
--- a/fs/ntfs3/super.c
+++ b/fs/ntfs3/super.c
@@ -1493,26 +1493,23 @@ static int ntfs_fill_super(struct super_block *sb, struct fs_context *fc)
 		goto put_inode_out;
 	}
 
-	for (idx = 0; idx < (0x10000 * sizeof(short) >> PAGE_SHIFT); idx++) {
-		const __le16 *src;
+	idx = 0;
+	while (idx < (0x10000 * sizeof(u16) >> PAGE_SHIFT)) {
 		u16 *dst = Add2Ptr(sbi->upcase, idx << PAGE_SHIFT);
-		struct page *page = ntfs_map_page(inode->i_mapping, idx);
+		struct folio *folio = read_mapping_folio(inode->i_mapping,
+				idx, NULL);
+		size_t limit = 0x10000 * sizeof(u16) - idx * PAGE_SIZE;
 
-		if (IS_ERR(page)) {
-			err = PTR_ERR(page);
+		if (IS_ERR(folio)) {
+			err = PTR_ERR(folio);
 			ntfs_err(sb, "Failed to read $UpCase (%d).", err);
 			goto put_inode_out;
 		}
 
-		src = page_address(page);
-
-#ifdef __BIG_ENDIAN
-		for (i = 0; i < PAGE_SIZE / sizeof(u16); i++)
-			*dst++ = le16_to_cpu(*src++);
-#else
-		memcpy(dst, src, PAGE_SIZE);
-#endif
-		ntfs_unmap_page(page);
+		memcpy_from_folio_le16(dst, folio, 0,
+				min(limit, folio_size(folio)));
+		idx += folio_nr_pages(folio);
+		folio_put(folio);
 	}
 
 	shared = ntfs_set_shared(sbi->upcase, 0x10000 * sizeof(short));
diff --git a/include/linux/highmem.h b/include/linux/highmem.h
index 00341b56d291..20b5d5a5feaf 100644
--- a/include/linux/highmem.h
+++ b/include/linux/highmem.h
@@ -467,6 +467,37 @@ static inline void memcpy_from_folio(char *to, struct folio *folio,
 	} while (len > 0);
 }
 
+#ifdef __BIG_ENDIAN
+static inline void memcpy_from_folio_le16(u16 *to, struct folio *folio,
+		size_t offset, size_t len)
+{
+	VM_BUG_ON(offset + len > folio_size(folio));
+
+	do {
+		const __le16 *from = kmap_local_folio(folio, offset);
+		size_t chunk = len;
+
+		if (folio_test_highmem(folio) &&
+		    chunk > PAGE_SIZE - offset_in_page(offset))
+			chunk = PAGE_SIZE - offset_in_page(offset);
+
+		for (i = 0; i < chunk / sizeof(*to); i++)
+			*to++ = le16_to_cpu(*from++);
+		kunmap_local(from);
+
+		to += chunk / sizeof(*to);
+		offset += chunk;
+		len -= chunk;
+	} while (len > 0);
+}
+#else
+static inline void memcpy_from_folio_le16(u16 *to, struct folio *folio,
+		size_t offset, size_t len)
+{
+	memcpy_from_folio((char *)to, folio, offset, len);
+}
+#endif
+
 /**
  * memcpy_to_folio - Copy a range of bytes to a folio.
  * @folio: The folio to write to.
-- 
2.43.0





[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux