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