forked from mirrors/linux
		
	datagram: consolidate datagram copy to iter helpers
skb_copy_datagram_iter and skb_copy_and_csum_datagram are essentialy the same but with a couple of differences: The first is the copy operation used which either a simple copy or a csum_and_copy, and the second are the behavior on the "short copy" path where simply copy needs to return the number of bytes successfully copied while csum_and_copy needs to fault immediately as the checksum is partial. Introduce __skb_datagram_iter that additionally accepts: 1. copy operation function pointer 2. private data that goes with the copy operation 3. fault_short flag to indicate the action on short copy Suggested-by: David S. Miller <davem@davemloft.net> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sagi Grimberg <sagi@lightbitslabs.com> Signed-off-by: Christoph Hellwig <hch@lst.de>
This commit is contained in:
		
							parent
							
								
									cb002d074d
								
							
						
					
					
						commit
						950fcaecd5
					
				
					 1 changed files with 42 additions and 94 deletions
				
			
		|  | @ -408,27 +408,20 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) | |||
| } | ||||
| EXPORT_SYMBOL(skb_kill_datagram); | ||||
| 
 | ||||
| /**
 | ||||
|  *	skb_copy_datagram_iter - Copy a datagram to an iovec iterator. | ||||
|  *	@skb: buffer to copy | ||||
|  *	@offset: offset in the buffer to start copying from | ||||
|  *	@to: iovec iterator to copy to | ||||
|  *	@len: amount of data to copy from buffer to iovec | ||||
|  */ | ||||
| int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | ||||
| 			   struct iov_iter *to, int len) | ||||
| int __skb_datagram_iter(const struct sk_buff *skb, int offset, | ||||
| 			struct iov_iter *to, int len, bool fault_short, | ||||
| 			size_t (*cb)(const void *, size_t, void *, struct iov_iter *), | ||||
| 			void *data) | ||||
| { | ||||
| 	int start = skb_headlen(skb); | ||||
| 	int i, copy = start - offset, start_off = offset, n; | ||||
| 	struct sk_buff *frag_iter; | ||||
| 
 | ||||
| 	trace_skb_copy_datagram_iovec(skb, len); | ||||
| 
 | ||||
| 	/* Copy header. */ | ||||
| 	if (copy > 0) { | ||||
| 		if (copy > len) | ||||
| 			copy = len; | ||||
| 		n = copy_to_iter(skb->data + offset, copy, to); | ||||
| 		n = cb(skb->data + offset, copy, data, to); | ||||
| 		offset += n; | ||||
| 		if (n != copy) | ||||
| 			goto short_copy; | ||||
|  | @ -450,8 +443,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | |||
| 
 | ||||
| 			if (copy > len) | ||||
| 				copy = len; | ||||
| 			n = copy_to_iter(vaddr + frag->page_offset + | ||||
| 					 offset - start, copy, to); | ||||
| 			n = cb(vaddr + frag->page_offset + | ||||
| 				offset - start, copy, data, to); | ||||
| 			kunmap(page); | ||||
| 			offset += n; | ||||
| 			if (n != copy) | ||||
|  | @ -471,8 +464,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | |||
| 		if ((copy = end - offset) > 0) { | ||||
| 			if (copy > len) | ||||
| 				copy = len; | ||||
| 			if (skb_copy_datagram_iter(frag_iter, offset - start, | ||||
| 						   to, copy)) | ||||
| 			if (__skb_datagram_iter(frag_iter, offset - start, | ||||
| 						to, copy, short_copy, cb, data)) | ||||
| 				goto fault; | ||||
| 			if ((len -= copy) == 0) | ||||
| 				return 0; | ||||
|  | @ -493,11 +486,32 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | |||
| 	return -EFAULT; | ||||
| 
 | ||||
| short_copy: | ||||
| 	if (iov_iter_count(to)) | ||||
| 	if (fault_short || iov_iter_count(to)) | ||||
| 		goto fault; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static size_t simple_copy_to_iter(const void *addr, size_t bytes, | ||||
| 		void *data __always_unused, struct iov_iter *i) | ||||
| { | ||||
| 	return copy_to_iter(addr, bytes, i); | ||||
| } | ||||
| 
 | ||||
| /**
 | ||||
|  *	skb_copy_datagram_iter - Copy a datagram to an iovec iterator. | ||||
|  *	@skb: buffer to copy | ||||
|  *	@offset: offset in the buffer to start copying from | ||||
|  *	@to: iovec iterator to copy to | ||||
|  *	@len: amount of data to copy from buffer to iovec | ||||
|  */ | ||||
| int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | ||||
| 			   struct iov_iter *to, int len) | ||||
| { | ||||
| 	trace_skb_copy_datagram_iovec(skb, len); | ||||
| 	return __skb_datagram_iter(skb, offset, to, len, false, | ||||
| 			simple_copy_to_iter, NULL); | ||||
| } | ||||
| EXPORT_SYMBOL(skb_copy_datagram_iter); | ||||
| 
 | ||||
| /**
 | ||||
|  | @ -648,87 +662,21 @@ int zerocopy_sg_from_iter(struct sk_buff *skb, struct iov_iter *from) | |||
| } | ||||
| EXPORT_SYMBOL(zerocopy_sg_from_iter); | ||||
| 
 | ||||
| /**
 | ||||
|  *	skb_copy_and_csum_datagram_iter - Copy datagram to an iovec iterator | ||||
|  *          and update a checksum. | ||||
|  *	@skb: buffer to copy | ||||
|  *	@offset: offset in the buffer to start copying from | ||||
|  *	@to: iovec iterator to copy to | ||||
|  *	@len: amount of data to copy from buffer to iovec | ||||
|  *      @csump: checksum pointer | ||||
|  */ | ||||
| static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | ||||
| 				      struct iov_iter *to, int len, | ||||
| 				      __wsum *csump) | ||||
| { | ||||
| 	int start = skb_headlen(skb); | ||||
| 	int i, copy = start - offset, start_off = offset; | ||||
| 	struct sk_buff *frag_iter; | ||||
| 	int pos = 0; | ||||
| 	int n; | ||||
| 
 | ||||
| 	/* Copy header. */ | ||||
| 	if (copy > 0) { | ||||
| 		if (copy > len) | ||||
| 			copy = len; | ||||
| 		n = csum_and_copy_to_iter(skb->data + offset, copy, csump, to); | ||||
| 		offset += n; | ||||
| 		if (n != copy) | ||||
| 			goto fault; | ||||
| 		if ((len -= copy) == 0) | ||||
| 			return 0; | ||||
| 		pos = copy; | ||||
| 	} | ||||
| 
 | ||||
| 	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) { | ||||
| 		int end; | ||||
| 		const skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; | ||||
| 
 | ||||
| 		WARN_ON(start > offset + len); | ||||
| 
 | ||||
| 		end = start + skb_frag_size(frag); | ||||
| 		if ((copy = end - offset) > 0) { | ||||
| 			__wsum csum2 = 0; | ||||
| 			struct page *page = skb_frag_page(frag); | ||||
| 			u8  *vaddr = kmap(page); | ||||
| 
 | ||||
| 			if (copy > len) | ||||
| 				copy = len; | ||||
| 			n = csum_and_copy_to_iter(vaddr + frag->page_offset + | ||||
| 						  offset - start, copy, | ||||
| 						  &csum2, to); | ||||
| 			kunmap(page); | ||||
| 			offset += n; | ||||
| 			if (n != copy) | ||||
| 				goto fault; | ||||
| 			*csump = csum_block_add(*csump, csum2, pos); | ||||
| 			if (!(len -= copy)) | ||||
| 				return 0; | ||||
| 			pos += copy; | ||||
| 		} | ||||
| 		start = end; | ||||
| 	} | ||||
| 
 | ||||
| 	skb_walk_frags(skb, frag_iter) { | ||||
| 		int end; | ||||
| 
 | ||||
| 		WARN_ON(start > offset + len); | ||||
| 
 | ||||
| 		end = start + frag_iter->len; | ||||
| 		if ((copy = end - offset) > 0) { | ||||
| 			__wsum csum2 = 0; | ||||
| 			if (copy > len) | ||||
| 				copy = len; | ||||
| 			if (skb_copy_and_csum_datagram(frag_iter, | ||||
| 						       offset - start, | ||||
| 						       to, copy, | ||||
| 						       &csum2)) | ||||
| 				goto fault; | ||||
| 			*csump = csum_block_add(*csump, csum2, pos); | ||||
| 			if ((len -= copy) == 0) | ||||
| 				return 0; | ||||
| 			offset += copy; | ||||
| 			pos += copy; | ||||
| 		} | ||||
| 		start = end; | ||||
| 	} | ||||
| 	if (!len) | ||||
| 		return 0; | ||||
| 
 | ||||
| fault: | ||||
| 	iov_iter_revert(to, offset - start_off); | ||||
| 	return -EFAULT; | ||||
| 	return __skb_datagram_iter(skb, offset, to, len, true, | ||||
| 			csum_and_copy_to_iter, csump); | ||||
| } | ||||
| 
 | ||||
| __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue
	
	 Sagi Grimberg
						Sagi Grimberg