Skip to content

Commit 908a1ad

Browse files
author
Matthew Wilcox (Oracle)
committed
iov_iter: Handle compound highmem pages in copy_page_from_iter_atomic()
copy_page_from_iter_atomic() already handles !highmem compound pages correctly, but if we are passed a highmem compound page, each base page needs to be mapped & unmapped individually. Signed-off-by: Matthew Wilcox (Oracle) <[email protected]> Reviewed-by: Christoph Hellwig <[email protected]> Reviewed-by: Kent Overstreet <[email protected]> Reviewed-by: Darrick J. Wong <[email protected]> Tested-by: Kent Overstreet <[email protected]>
1 parent f7f9a0c commit 908a1ad

File tree

1 file changed

+23
-10
lines changed

1 file changed

+23
-10
lines changed

lib/iov_iter.c

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -566,24 +566,37 @@ size_t iov_iter_zero(size_t bytes, struct iov_iter *i)
566566
}
567567
EXPORT_SYMBOL(iov_iter_zero);
568568

569-
size_t copy_page_from_iter_atomic(struct page *page, unsigned offset, size_t bytes,
570-
struct iov_iter *i)
569+
size_t copy_page_from_iter_atomic(struct page *page, unsigned offset,
570+
size_t bytes, struct iov_iter *i)
571571
{
572-
char *p;
572+
size_t n, copied = 0;
573573

574574
if (!page_copy_sane(page, offset, bytes))
575575
return 0;
576576
if (WARN_ON_ONCE(!i->data_source))
577577
return 0;
578578

579-
p = kmap_atomic(page) + offset;
580-
iterate_and_advance(i, bytes, base, len, off,
581-
copyin(p + off, base, len),
582-
memcpy_from_iter(i, p + off, base, len)
583-
)
584-
kunmap_atomic(p);
579+
do {
580+
char *p;
585581

586-
return bytes;
582+
n = bytes - copied;
583+
if (PageHighMem(page)) {
584+
page += offset / PAGE_SIZE;
585+
offset %= PAGE_SIZE;
586+
n = min_t(size_t, n, PAGE_SIZE - offset);
587+
}
588+
589+
p = kmap_atomic(page) + offset;
590+
iterate_and_advance(i, n, base, len, off,
591+
copyin(p + off, base, len),
592+
memcpy_from_iter(i, p + off, base, len)
593+
)
594+
kunmap_atomic(p);
595+
copied += n;
596+
offset += n;
597+
} while (PageHighMem(page) && copied != bytes && n > 0);
598+
599+
return copied;
587600
}
588601
EXPORT_SYMBOL(copy_page_from_iter_atomic);
589602

0 commit comments

Comments
 (0)