highmem: Add memcpy_folio()

The folio equivalent of memcpy_page().  It should correctly and
efficiently manage large folios:

 - If one, neither or both is highmem
 - If (either or both) offset+len crosses a page boundary
 - If the two offsets are congruent or not

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Reviewed-by: Chao Yu <chao@kernel.org>
Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org>
This commit is contained in:
Matthew Wilcox (Oracle) 2025-03-31 21:11:11 +01:00 committed by Jaegeuk Kim
parent 48b6894305
commit 1313057c36

View File

@ -404,6 +404,33 @@ static inline void memcpy_page(struct page *dst_page, size_t dst_off,
kunmap_local(dst);
}
static inline void memcpy_folio(struct folio *dst_folio, size_t dst_off,
struct folio *src_folio, size_t src_off, size_t len)
{
VM_BUG_ON(dst_off + len > folio_size(dst_folio));
VM_BUG_ON(src_off + len > folio_size(src_folio));
do {
char *dst = kmap_local_folio(dst_folio, dst_off);
const char *src = kmap_local_folio(src_folio, src_off);
size_t chunk = len;
if (folio_test_highmem(dst_folio) &&
chunk > PAGE_SIZE - offset_in_page(dst_off))
chunk = PAGE_SIZE - offset_in_page(dst_off);
if (folio_test_highmem(src_folio) &&
chunk > PAGE_SIZE - offset_in_page(src_off))
chunk = PAGE_SIZE - offset_in_page(src_off);
memcpy(dst, src, chunk);
kunmap_local(src);
kunmap_local(dst);
dst_off += chunk;
src_off += chunk;
len -= chunk;
} while (len > 0);
}
static inline void memset_page(struct page *page, size_t offset, int val,
size_t len)
{