diff options
| author | Matthew Wilcox (Oracle) <willy@infradead.org> | 2025-03-31 23:11:11 +0300 |
|---|---|---|
| committer | Jaegeuk Kim <jaegeuk@kernel.org> | 2025-04-28 18:26:33 +0300 |
| commit | 1313057c369bb4da11bb1f8dffb570ac7b44a4d4 (patch) | |
| tree | 2b48bf30478fd2a122d6a599e6f655142f25d4a2 /include/linux | |
| parent | 48b68943053af00d0c3247eaab8f83bc17d26632 (diff) | |
| download | linux-1313057c369bb4da11bb1f8dffb570ac7b44a4d4.tar.xz | |
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>
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/highmem.h | 27 |
1 files changed, 27 insertions, 0 deletions
diff --git a/include/linux/highmem.h b/include/linux/highmem.h index 5c6bea81a90e..fd72f66b872a 100644 --- a/include/linux/highmem.h +++ b/include/linux/highmem.h @@ -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) { |
