On Mon, Nov 24, 2014 at 01:09:54AM +0000, Al Viro wrote: > Specifically, it allows to add a new kind of iovecs (ITER_KVEC using > straight memcpy instead of going through copy_..._user) at the cost of > mere 74 extra lines (see the next patch) and allows to add the things > like csum_and_copy_{from,to}_iter() without arseloads of extra code (also > written, but I'd prefer to clean it up a bit more first). FWIW, the current variant of csum_and_copy_..._iter (completely untested, without any code in net/* that would use it, etc.) is this: diff --git a/include/linux/uio.h b/include/linux/uio.h index 6e16945..28ed2d9 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -124,6 +124,8 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) { i->count = count; } +size_t csum_and_copy_to_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); +size_t csum_and_copy_from_iter(void *addr, size_t bytes, __wsum *csum, struct iov_iter *i); int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); diff --git a/mm/iov_iter.c b/mm/iov_iter.c index 89ed7cd..fa03b8d 100644 --- a/mm/iov_iter.c +++ b/mm/iov_iter.c @@ -3,6 +3,7 @@ #include <linux/pagemap.h> #include <linux/slab.h> #include <linux/vmalloc.h> +#include <net/checksum.h> #define iterate_iovec(i, n, __v, __p, skip, STEP) { \ size_t left; \ @@ -577,6 +578,76 @@ ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, } EXPORT_SYMBOL(iov_iter_get_pages_alloc); +size_t copy_and_csum_from_iter(void *addr, size_t bytes, __wsum *csum, + struct iov_iter *i) +{ + char *to = addr; + __wsum sum; + if (unlikely(bytes > i->count)) + bytes = i->count; + + if (unlikely(!bytes)) + return 0; + + sum = *csum; + iterate_all_kinds_shift(i, bytes, v, ({ + int err = 0; + __wsum next; + next = csum_and_copy_from_user(v.iov_base, + (to += v.iov_len) - v.iov_len, + v.iov_len, sum, &err); + err ? v.iov_len : (sum = next, 0); + }), ({ + char *p = kmap_atomic(v.bv_page); + sum = csum_partial_copy_nocheck(p + v.bv_offset, + (to += v.bv_len) - v.bv_len, + v.bv_len, sum); + kunmap_atomic(p); + }), + sum = csum_partial_copy_nocheck(v.iov_base, + (to += v.iov_len) - v.iov_len, + v.iov_len, sum) + ) + *csum = sum; + return bytes; +} +EXPORT_SYMBOL(csum_and_copy_from_iter); + +size_t copy_and_csum_to_iter(void *addr, size_t bytes, __wsum *csum, + struct iov_iter *i) +{ + char *from = addr; + __wsum sum; + if (unlikely(bytes > i->count)) + bytes = i->count; + + if (unlikely(!bytes)) + return 0; + + sum = *csum; + iterate_all_kinds_shift(i, bytes, v, ({ + int err = 0; + __wsum next; + next = csum_and_copy_to_user((from += v.iov_len) - v.iov_len, + v.iov_base, + v.iov_len, sum, &err); + err ? v.iov_len : (sum = next, 0); + }), ({ + char *p = kmap_atomic(v.bv_page); + sum = csum_partial_copy_nocheck((from += v.bv_len) - v.bv_len, + p + v.bv_offset, + v.bv_len, sum); + kunmap_atomic(p); + }), + sum = csum_partial_copy_nocheck((from += v.iov_len) - v.iov_len, + v.iov_base, + v.iov_len, sum) + ) + *csum = sum; + return bytes; +} +EXPORT_SYMBOL(csum_and_copy_to_iter); + int iov_iter_npages(const struct iov_iter *i, int maxpages) { size_t size = i->count; -- To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html