You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
112 lines
2.2 KiB
112 lines
2.2 KiB
#include <linux/uaccess.h> |
|
#include <linux/export.h> |
|
#include <linux/uio.h> |
|
|
|
/* |
|
* Copy iovec to kernel. Returns -EFAULT on error. |
|
* |
|
* Note: this modifies the original iovec. |
|
*/ |
|
|
|
int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len) |
|
{ |
|
while (len > 0) { |
|
if (iov->iov_len) { |
|
int copy = min_t(unsigned int, len, iov->iov_len); |
|
if (copy_from_user(kdata, iov->iov_base, copy)) |
|
return -EFAULT; |
|
len -= copy; |
|
kdata += copy; |
|
iov->iov_base += copy; |
|
iov->iov_len -= copy; |
|
} |
|
iov++; |
|
} |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(memcpy_fromiovec); |
|
|
|
/* |
|
* Copy kernel to iovec. Returns -EFAULT on error. |
|
* |
|
* Note: this modifies the original iovec. |
|
*/ |
|
|
|
int memcpy_toiovec(struct iovec *iov, unsigned char *kdata, int len) |
|
{ |
|
while (len > 0) { |
|
if (iov->iov_len) { |
|
int copy = min_t(unsigned int, iov->iov_len, len); |
|
if (copy_to_user(iov->iov_base, kdata, copy)) |
|
return -EFAULT; |
|
kdata += copy; |
|
len -= copy; |
|
iov->iov_len -= copy; |
|
iov->iov_base += copy; |
|
} |
|
iov++; |
|
} |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(memcpy_toiovec); |
|
|
|
/* |
|
* Copy kernel to iovec. Returns -EFAULT on error. |
|
*/ |
|
|
|
int memcpy_toiovecend(const struct iovec *iov, unsigned char *kdata, |
|
int offset, int len) |
|
{ |
|
int copy; |
|
for (; len > 0; ++iov) { |
|
/* Skip over the finished iovecs */ |
|
if (unlikely(offset >= iov->iov_len)) { |
|
offset -= iov->iov_len; |
|
continue; |
|
} |
|
copy = min_t(unsigned int, iov->iov_len - offset, len); |
|
if (copy_to_user(iov->iov_base + offset, kdata, copy)) |
|
return -EFAULT; |
|
offset = 0; |
|
kdata += copy; |
|
len -= copy; |
|
} |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(memcpy_toiovecend); |
|
|
|
/* |
|
* Copy iovec to kernel. Returns -EFAULT on error. |
|
*/ |
|
|
|
int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, |
|
int offset, int len) |
|
{ |
|
/* No data? Done! */ |
|
if (len == 0) |
|
return 0; |
|
|
|
/* Skip over the finished iovecs */ |
|
while (offset >= iov->iov_len) { |
|
offset -= iov->iov_len; |
|
iov++; |
|
} |
|
|
|
while (len > 0) { |
|
u8 __user *base = iov->iov_base + offset; |
|
int copy = min_t(unsigned int, len, iov->iov_len - offset); |
|
|
|
offset = 0; |
|
if (copy_from_user(kdata, base, copy)) |
|
return -EFAULT; |
|
len -= copy; |
|
kdata += copy; |
|
iov++; |
|
} |
|
|
|
return 0; |
|
} |
|
EXPORT_SYMBOL(memcpy_fromiovecend);
|
|
|