diff options
Diffstat (limited to 'net/core/iovec.c')
| -rw-r--r-- | net/core/iovec.c | 134 | 
1 files changed, 27 insertions, 107 deletions
diff --git a/net/core/iovec.c b/net/core/iovec.c index c40f27e7d20..e1ec45ab1e6 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -35,11 +35,11 @@   *	in any case.   */ -int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address, int mode) +int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr_storage *address, int mode)  {  	int size, ct, err; -	if (m->msg_namelen) { +	if (m->msg_name && m->msg_namelen) {  		if (mode == VERIFY_READ) {  			void __user *namep;  			namep = (void __user __force *) m->msg_name; @@ -51,6 +51,7 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,  		m->msg_name = address;  	} else {  		m->msg_name = NULL; +		m->msg_namelen = 0;  	}  	size = m->msg_iovlen * sizeof(struct iovec); @@ -74,111 +75,6 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, struct sockaddr *address,  }  /* - *	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. - * - *	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 iovec from kernel. Returns -EFAULT on error. - */ - -int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov, -			int offset, int len) -{ -	/* 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); - -/*   *	And now for the all-in-one: copy and checksum from a user iovec   *	directly to a datagram   *	Calls to csum_partial but the last must be in 32 bit chunks @@ -262,3 +158,27 @@ out_fault:  	goto out;  }  EXPORT_SYMBOL(csum_partial_copy_fromiovecend); + +unsigned long iov_pages(const struct iovec *iov, int offset, +			unsigned long nr_segs) +{ +	unsigned long seg, base; +	int pages = 0, len, size; + +	while (nr_segs && (offset >= iov->iov_len)) { +		offset -= iov->iov_len; +		++iov; +		--nr_segs; +	} + +	for (seg = 0; seg < nr_segs; seg++) { +		base = (unsigned long)iov[seg].iov_base + offset; +		len = iov[seg].iov_len - offset; +		size = ((base & ~PAGE_MASK) + len + ~PAGE_MASK) >> PAGE_SHIFT; +		pages += size; +		offset = 0; +	} + +	return pages; +} +EXPORT_SYMBOL(iov_pages);  | 
