at v3.17 2.2 kB view raw
1#include <linux/uaccess.h> 2#include <linux/export.h> 3#include <linux/uio.h> 4 5/* 6 * Copy iovec to kernel. Returns -EFAULT on error. 7 * 8 * Note: this modifies the original iovec. 9 */ 10 11int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) 12{ 13 while (len > 0) { 14 if (iov->iov_len) { 15 int copy = min_t(unsigned int, len, iov->iov_len); 16 if (copy_from_user(kdata, iov->iov_base, copy)) 17 return -EFAULT; 18 len -= copy; 19 kdata += copy; 20 iov->iov_base += copy; 21 iov->iov_len -= copy; 22 } 23 iov++; 24 } 25 26 return 0; 27} 28EXPORT_SYMBOL(memcpy_fromiovec); 29 30/* 31 * Copy kernel to iovec. Returns -EFAULT on error. 32 * 33 * Note: this modifies the original iovec. 34 */ 35 36int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) 37{ 38 while (len > 0) { 39 if (iov->iov_len) { 40 int copy = min_t(unsigned int, iov->iov_len, len); 41 if (copy_to_user(iov->iov_base, kdata, copy)) 42 return -EFAULT; 43 kdata += copy; 44 len -= copy; 45 iov->iov_len -= copy; 46 iov->iov_base += copy; 47 } 48 iov++; 49 } 50 51 return 0; 52} 53EXPORT_SYMBOL(memcpy_toiovec); 54 55/* 56 * Copy kernel to iovec. Returns -EFAULT on error. 57 */ 58 59int 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} 79EXPORT_SYMBOL(memcpy_toiovecend); 80 81/* 82 * Copy iovec to kernel. Returns -EFAULT on error. 83 */ 84 85int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, 86 int offset, int len) 87{ 88 /* No data? Done! */ 89 if (len == 0) 90 return 0; 91 92 /* Skip over the finished iovecs */ 93 while (offset >= iov->iov_len) { 94 offset -= iov->iov_len; 95 iov++; 96 } 97 98 while (len > 0) { 99 u8 __user *base = iov->iov_base + offset; 100 int copy = min_t(unsigned int, len, iov->iov_len - offset); 101 102 offset = 0; 103 if (copy_from_user(kdata, base, copy)) 104 return -EFAULT; 105 len -= copy; 106 kdata += copy; 107 iov++; 108 } 109 110 return 0; 111} 112EXPORT_SYMBOL(memcpy_fromiovecend);