summaryrefslogtreecommitdiffstats
path: root/mm/iov_iter.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2014-11-24 01:08:00 -0500
committerAl Viro <viro@zeniv.linux.org.uk>2014-12-08 20:25:22 -0500
commita604ec7e9ffea22fed84db8306585090e7a6e85d (patch)
tree568dc02b8ed5b0ea52f37b2e459e535be7564638 /mm/iov_iter.c
parenta280455fa87053eed59de8464200d03ae4caa8c3 (diff)
csum_and_copy_..._iter()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'mm/iov_iter.c')
-rw-r--r--mm/iov_iter.c89
1 files changed, 89 insertions, 0 deletions
diff --git a/mm/iov_iter.c b/mm/iov_iter.c
index 1618e378277e..1d2cdeb57c58 100644
--- a/mm/iov_iter.c
+++ b/mm/iov_iter.c
@@ -3,6 +3,7 @@
3#include <linux/pagemap.h> 3#include <linux/pagemap.h>
4#include <linux/slab.h> 4#include <linux/slab.h>
5#include <linux/vmalloc.h> 5#include <linux/vmalloc.h>
6#include <net/checksum.h>
6 7
7#define iterate_iovec(i, n, __v, __p, skip, STEP) { \ 8#define iterate_iovec(i, n, __v, __p, skip, STEP) { \
8 size_t left; \ 9 size_t left; \
@@ -586,6 +587,94 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i,
586} 587}
587EXPORT_SYMBOL(iov_iter_get_pages_alloc); 588EXPORT_SYMBOL(iov_iter_get_pages_alloc);
588 589
590size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum,
591 struct iov_iter *i)
592{
593 char *to = addr;
594 __wsum sum, next;
595 size_t off = 0;
596 if (unlikely(bytes > i->count))
597 bytes = i->count;
598
599 if (unlikely(!bytes))
600 return 0;
601
602 sum = *csum;
603 iterate_and_advance(i, bytes, v, ({
604 int err = 0;
605 next = csum_and_copy_from_user(v.iov_base,
606 (to += v.iov_len) - v.iov_len,
607 v.iov_len, 0, &err);
608 if (!err) {
609 sum = csum_block_add(sum, next, off);
610 off += v.iov_len;
611 }
612 err ? v.iov_len : 0;
613 }), ({
614 char *p = kmap_atomic(v.bv_page);
615 next = csum_partial_copy_nocheck(p + v.bv_offset,
616 (to += v.bv_len) - v.bv_len,
617 v.bv_len, 0);
618 kunmap_atomic(p);
619 sum = csum_block_add(sum, next, off);
620 off += v.bv_len;
621 }),({
622 next = csum_partial_copy_nocheck(v.iov_base,
623 (to += v.iov_len) - v.iov_len,
624 v.iov_len, 0);
625 sum = csum_block_add(sum, next, off);
626 off += v.iov_len;
627 })
628 )
629 *csum = sum;
630 return bytes;
631}
632EXPORT_SYMBOL(csum_and_copy_from_iter);
633
634size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum,
635 struct iov_iter *i)
636{
637 char *from = addr;
638 __wsum sum, next;
639 size_t off = 0;
640 if (unlikely(bytes > i->count))
641 bytes = i->count;
642
643 if (unlikely(!bytes))
644 return 0;
645
646 sum = *csum;
647 iterate_and_advance(i, bytes, v, ({
648 int err = 0;
649 next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len,
650 v.iov_base,
651 v.iov_len, 0, &err);
652 if (!err) {
653 sum = csum_block_add(sum, next, off);
654 off += v.iov_len;
655 }
656 err ? v.iov_len : 0;
657 }), ({
658 char *p = kmap_atomic(v.bv_page);
659 next = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len,
660 p + v.bv_offset,
661 v.bv_len, 0);
662 kunmap_atomic(p);
663 sum = csum_block_add(sum, next, off);
664 off += v.bv_len;
665 }),({
666 next = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len,
667 v.iov_base,
668 v.iov_len, 0);
669 sum = csum_block_add(sum, next, off);
670 off += v.iov_len;
671 })
672 )
673 *csum = sum;
674 return bytes;
675}
676EXPORT_SYMBOL(csum_and_copy_to_iter);
677
589int iov_iter_npages(const struct iov_iter *i, int maxpages) 678int iov_iter_npages(const struct iov_iter *i, int maxpages)
590{ 679{
591 size_t size = i->count; 680 size_t size = i->count;