diff options
| -rw-r--r-- | include/linux/socket.h | 4 | ||||
| -rw-r--r-- | include/linux/uio.h | 5 | ||||
| -rw-r--r-- | lib/iovec.c | 55 | ||||
| -rw-r--r-- | net/core/iovec.c | 55 |
4 files changed, 59 insertions, 60 deletions
diff --git a/include/linux/socket.h b/include/linux/socket.h index 8e98297f1388..ec538fc287a6 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
| @@ -305,8 +305,6 @@ struct ucred { | |||
| 305 | /* IPX options */ | 305 | /* IPX options */ |
| 306 | #define IPX_TYPE 1 | 306 | #define IPX_TYPE 1 |
| 307 | 307 | ||
| 308 | extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, | ||
| 309 | int offset, int len); | ||
| 310 | extern int csum_partial_copy_fromiovecend(unsigned char *kdata, | 308 | extern int csum_partial_copy_fromiovecend(unsigned char *kdata, |
| 311 | struct iovec *iov, | 309 | struct iovec *iov, |
| 312 | int offset, | 310 | int offset, |
| @@ -315,8 +313,6 @@ extern unsigned long iov_pages(const struct iovec *iov, int offset, | |||
| 315 | unsigned long nr_segs); | 313 | unsigned long nr_segs); |
| 316 | 314 | ||
| 317 | extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); | 315 | extern int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode); |
| 318 | extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, | ||
| 319 | int offset, int len); | ||
| 320 | extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); | 316 | extern int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr); |
| 321 | extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); | 317 | extern int put_cmsg(struct msghdr*, int level, int type, int len, void *data); |
| 322 | 318 | ||
diff --git a/include/linux/uio.h b/include/linux/uio.h index e2231e47cec1..04c8c4bb4927 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h | |||
| @@ -111,6 +111,9 @@ static inline void iov_iter_reexpand(struct iov_iter *i, size_t count) | |||
| 111 | 111 | ||
| 112 | int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); | 112 | int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len); |
| 113 | int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); | 113 | int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len); |
| 114 | 114 | int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, | |
| 115 | int offset, int len); | ||
| 116 | int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata, | ||
| 117 | int offset, int len); | ||
| 115 | 118 | ||
| 116 | #endif | 119 | #endif |
diff --git a/lib/iovec.c b/lib/iovec.c index 454baa88bf27..7a7c2da4cddf 100644 --- a/lib/iovec.c +++ b/lib/iovec.c | |||
| @@ -51,3 +51,58 @@ int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) | |||
| 51 | return 0; | 51 | return 0; |
| 52 | } | 52 | } |
| 53 | EXPORT_SYMBOL(memcpy_toiovec); | 53 | EXPORT_SYMBOL(memcpy_toiovec); |
| 54 | |||
| 55 | /* | ||
| 56 | * Copy kernel to iovec. Returns -EFAULT on error. | ||
| 57 | */ | ||
| 58 | |||
| 59 | int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, | ||
| 60 | int offset, int len) | ||
| 61 | { | ||
| 62 | int copy; | ||
| 63 | for (; len > 0; ++iov) { | ||
| 64 | /* Skip over the finished iovecs */ | ||
| 65 | if (unlikely(offset >= iov->iov_len)) { | ||
| 66 | offset -= iov->iov_len; | ||
| 67 | continue; | ||
| 68 | } | ||
| 69 | copy = min_t(unsigned int, iov->iov_len - offset, len); | ||
| 70 | if (copy_to_user(iov->iov_base + offset, kdata, copy)) | ||
| 71 | return -EFAULT; | ||
| 72 | offset = 0; | ||
| 73 | kdata += copy; | ||
| 74 | len -= copy; | ||
| 75 | } | ||
| 76 | |||
| 77 | return 0; | ||
| 78 | } | ||
| 79 | EXPORT_SYMBOL(memcpy_toiovecend); | ||
| 80 | |||
| 81 | /* | ||
| 82 | * Copy iovec to kernel. Returns -EFAULT on error. | ||
| 83 | */ | ||
| 84 | |||
| 85 | int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, | ||
| 86 | int offset, int len) | ||
| 87 | { | ||
| 88 | /* Skip over the finished iovecs */ | ||
| 89 | while (offset >= iov->iov_len) { | ||
| 90 | offset -= iov->iov_len; | ||
| 91 | iov++; | ||
| 92 | } | ||
| 93 | |||
| 94 | while (len > 0) { | ||
| 95 | u8 __user *base = iov->iov_base + offset; | ||
| 96 | int copy = min_t(unsigned int, len, iov->iov_len - offset); | ||
| 97 | |||
| 98 | offset = 0; | ||
| 99 | if (copy_from_user(kdata, base, copy)) | ||
| 100 | return -EFAULT; | ||
| 101 | len -= copy; | ||
| 102 | kdata += copy; | ||
| 103 | iov++; | ||
| 104 | } | ||
| 105 | |||
| 106 | return 0; | ||
| 107 | } | ||
| 108 | EXPORT_SYMBOL(memcpy_fromiovecend); | ||
diff --git a/net/core/iovec.c b/net/core/iovec.c index b61869429f4c..827dd6beb49c 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c | |||
| @@ -75,61 +75,6 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *a | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | /* | 77 | /* |
| 78 | * Copy kernel to iovec. Returns -EFAULT on error. | ||
| 79 | */ | ||
| 80 | |||
| 81 | int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, | ||
| 82 | int offset, int len) | ||
| 83 | { | ||
| 84 | int copy; | ||
| 85 | for (; len > 0; ++iov) { | ||
| 86 | /* Skip over the finished iovecs */ | ||
| 87 | if (unlikely(offset >= iov->iov_len)) { | ||
| 88 | offset -= iov->iov_len; | ||
| 89 | continue; | ||
| 90 | } | ||
| 91 | copy = min_t(unsigned int, iov->iov_len - offset, len); | ||
| 92 | if (copy_to_user(iov->iov_base + offset, kdata, copy)) | ||
| 93 | return -EFAULT; | ||
| 94 | offset = 0; | ||
| 95 | kdata += copy; | ||
| 96 | len -= copy; | ||
| 97 | } | ||
| 98 | |||
| 99 | return 0; | ||
| 100 | } | ||
| 101 | EXPORT_SYMBOL(memcpy_toiovecend); | ||
| 102 | |||
| 103 | /* | ||
| 104 | * Copy iovec to kernel. Returns -EFAULT on error. | ||
| 105 | */ | ||
| 106 | |||
| 107 | int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, | ||
| 108 | int offset, int len) | ||
| 109 | { | ||
| 110 | /* Skip over the finished iovecs */ | ||
| 111 | while (offset >= iov->iov_len) { | ||
| 112 | offset -= iov->iov_len; | ||
| 113 | iov++; | ||
| 114 | } | ||
| 115 | |||
| 116 | while (len > 0) { | ||
| 117 | u8 __user *base = iov->iov_base + offset; | ||
| 118 | int copy = min_t(unsigned int, len, iov->iov_len - offset); | ||
| 119 | |||
| 120 | offset = 0; | ||
| 121 | if (copy_from_user(kdata, base, copy)) | ||
| 122 | return -EFAULT; | ||
| 123 | len -= copy; | ||
| 124 | kdata += copy; | ||
| 125 | iov++; | ||
| 126 | } | ||
| 127 | |||
| 128 | return 0; | ||
| 129 | } | ||
| 130 | EXPORT_SYMBOL(memcpy_fromiovecend); | ||
| 131 | |||
| 132 | /* | ||
| 133 | * And now for the all-in-one: copy and checksum from a user iovec | 78 | * And now for the all-in-one: copy and checksum from a user iovec |
| 134 | * directly to a datagram | 79 | * directly to a datagram |
| 135 | * Calls to csum_partial but the last must be in 32 bit chunks | 80 | * Calls to csum_partial but the last must be in 32 bit chunks |
