| 
									
										
										
										
											2013-05-17 09:05:21 +09:30
										 |  |  | #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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-19 21:22:56 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *	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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2014-07-31 23:00:35 -04:00
										 |  |  | 	/* No data? Done! */ | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-06-19 21:22:56 +03:00
										 |  |  | 	/* 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); |