diff options
author | Dan Williams <dan.j.williams@intel.com> | 2018-05-03 20:06:31 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2018-05-15 02:32:42 -0400 |
commit | 8780356ef630aa577fd4daa49e49b79674711fae (patch) | |
tree | 104e73665ca067e220a59a70daee5539e50e0c99 /lib/iov_iter.c | |
parent | 12c89130a56ae8e8d85db753d70333c4ee0ea835 (diff) |
x86/asm/memcpy_mcsafe: Define copy_to_iter_mcsafe()
Use the updated memcpy_mcsafe() implementation to define
copy_user_mcsafe() and copy_to_iter_mcsafe(). The most significant
difference from typical copy_to_iter() is that the ITER_KVEC and
ITER_BVEC iterator types can fail to complete a full transfer.
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: Andrew Morton <akpm@linux-foundation.org>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Tony Luck <tony.luck@intel.com>
Cc: hch@lst.de
Cc: linux-fsdevel@vger.kernel.org
Cc: linux-nvdimm@lists.01.org
Link: http://lkml.kernel.org/r/152539239150.31796.9189779163576449784.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'lib/iov_iter.c')
-rw-r--r-- | lib/iov_iter.c | 61 |
1 files changed, 61 insertions, 0 deletions
diff --git a/lib/iov_iter.c b/lib/iov_iter.c index 970212670b6a..70ebc8ede143 100644 --- a/lib/iov_iter.c +++ b/lib/iov_iter.c | |||
@@ -573,6 +573,67 @@ size_t _copy_to_iter(const void *addr, size_t bytes, struct iov_iter *i) | |||
573 | } | 573 | } |
574 | EXPORT_SYMBOL(_copy_to_iter); | 574 | EXPORT_SYMBOL(_copy_to_iter); |
575 | 575 | ||
576 | #ifdef CONFIG_ARCH_HAS_UACCESS_MCSAFE | ||
577 | static int copyout_mcsafe(void __user *to, const void *from, size_t n) | ||
578 | { | ||
579 | if (access_ok(VERIFY_WRITE, to, n)) { | ||
580 | kasan_check_read(from, n); | ||
581 | n = copy_to_user_mcsafe((__force void *) to, from, n); | ||
582 | } | ||
583 | return n; | ||
584 | } | ||
585 | |||
586 | static unsigned long memcpy_mcsafe_to_page(struct page *page, size_t offset, | ||
587 | const char *from, size_t len) | ||
588 | { | ||
589 | unsigned long ret; | ||
590 | char *to; | ||
591 | |||
592 | to = kmap_atomic(page); | ||
593 | ret = memcpy_mcsafe(to + offset, from, len); | ||
594 | kunmap_atomic(to); | ||
595 | |||
596 | return ret; | ||
597 | } | ||
598 | |||
599 | size_t _copy_to_iter_mcsafe(const void *addr, size_t bytes, struct iov_iter *i) | ||
600 | { | ||
601 | const char *from = addr; | ||
602 | unsigned long rem, curr_addr, s_addr = (unsigned long) addr; | ||
603 | |||
604 | if (unlikely(i->type & ITER_PIPE)) { | ||
605 | WARN_ON(1); | ||
606 | return 0; | ||
607 | } | ||
608 | if (iter_is_iovec(i)) | ||
609 | might_fault(); | ||
610 | iterate_and_advance(i, bytes, v, | ||
611 | copyout_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len, v.iov_len), | ||
612 | ({ | ||
613 | rem = memcpy_mcsafe_to_page(v.bv_page, v.bv_offset, | ||
614 | (from += v.bv_len) - v.bv_len, v.bv_len); | ||
615 | if (rem) { | ||
616 | curr_addr = (unsigned long) from; | ||
617 | bytes = curr_addr - s_addr - rem; | ||
618 | return bytes; | ||
619 | } | ||
620 | }), | ||
621 | ({ | ||
622 | rem = memcpy_mcsafe(v.iov_base, (from += v.iov_len) - v.iov_len, | ||
623 | v.iov_len); | ||
624 | if (rem) { | ||
625 | curr_addr = (unsigned long) from; | ||
626 | bytes = curr_addr - s_addr - rem; | ||
627 | return bytes; | ||
628 | } | ||
629 | }) | ||
630 | ) | ||
631 | |||
632 | return bytes; | ||
633 | } | ||
634 | EXPORT_SYMBOL_GPL(_copy_to_iter_mcsafe); | ||
635 | #endif /* CONFIG_ARCH_HAS_UACCESS_MCSAFE */ | ||
636 | |||
576 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) | 637 | size_t _copy_from_iter(void *addr, size_t bytes, struct iov_iter *i) |
577 | { | 638 | { |
578 | char *to = addr; | 639 | char *to = addr; |