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); | EXPORT_SYMBOL(skb_kill_datagram); | ||||||
| 
 | 
 | ||||||
| /**
 | int __skb_datagram_iter(const struct sk_buff *skb, int offset, | ||||||
|  *	skb_copy_datagram_iter - Copy a datagram to an iovec iterator. | 			struct iov_iter *to, int len, bool fault_short, | ||||||
|  *	@skb: buffer to copy | 			size_t (*cb)(const void *, size_t, void *, struct iov_iter *), | ||||||
|  *	@offset: offset in the buffer to start copying from | 			void *data) | ||||||
|  *	@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 start = skb_headlen(skb); | 	int start = skb_headlen(skb); | ||||||
| 	int i, copy = start - offset, start_off = offset, n; | 	int i, copy = start - offset, start_off = offset, n; | ||||||
| 	struct sk_buff *frag_iter; | 	struct sk_buff *frag_iter; | ||||||
| 
 | 
 | ||||||
| 	trace_skb_copy_datagram_iovec(skb, len); |  | ||||||
| 
 |  | ||||||
| 	/* Copy header. */ | 	/* Copy header. */ | ||||||
| 	if (copy > 0) { | 	if (copy > 0) { | ||||||
| 		if (copy > len) | 		if (copy > len) | ||||||
| 			copy = len; | 			copy = len; | ||||||
| 		n = copy_to_iter(skb->data + offset, copy, to); | 		n = cb(skb->data + offset, copy, data, to); | ||||||
| 		offset += n; | 		offset += n; | ||||||
| 		if (n != copy) | 		if (n != copy) | ||||||
| 			goto short_copy; | 			goto short_copy; | ||||||
|  | @ -450,8 +443,8 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | ||||||
| 
 | 
 | ||||||
| 			if (copy > len) | 			if (copy > len) | ||||||
| 				copy = len; | 				copy = len; | ||||||
| 			n = copy_to_iter(vaddr + frag->page_offset + | 			n = cb(vaddr + frag->page_offset + | ||||||
| 					 offset - start, copy, to); | 				offset - start, copy, data, to); | ||||||
| 			kunmap(page); | 			kunmap(page); | ||||||
| 			offset += n; | 			offset += n; | ||||||
| 			if (n != copy) | 			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 = end - offset) > 0) { | ||||||
| 			if (copy > len) | 			if (copy > len) | ||||||
| 				copy = len; | 				copy = len; | ||||||
| 			if (skb_copy_datagram_iter(frag_iter, offset - start, | 			if (__skb_datagram_iter(frag_iter, offset - start, | ||||||
| 						   to, copy)) | 						to, copy, short_copy, cb, data)) | ||||||
| 				goto fault; | 				goto fault; | ||||||
| 			if ((len -= copy) == 0) | 			if ((len -= copy) == 0) | ||||||
| 				return 0; | 				return 0; | ||||||
|  | @ -493,11 +486,32 @@ int skb_copy_datagram_iter(const struct sk_buff *skb, int offset, | ||||||
| 	return -EFAULT; | 	return -EFAULT; | ||||||
| 
 | 
 | ||||||
| short_copy: | short_copy: | ||||||
| 	if (iov_iter_count(to)) | 	if (fault_short || iov_iter_count(to)) | ||||||
| 		goto fault; | 		goto fault; | ||||||
| 
 | 
 | ||||||
| 	return 0; | 	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); | 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); | 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, | static int skb_copy_and_csum_datagram(const struct sk_buff *skb, int offset, | ||||||
| 				      struct iov_iter *to, int len, | 				      struct iov_iter *to, int len, | ||||||
| 				      __wsum *csump) | 				      __wsum *csump) | ||||||
| { | { | ||||||
| 	int start = skb_headlen(skb); | 	return __skb_datagram_iter(skb, offset, to, len, true, | ||||||
| 	int i, copy = start - offset, start_off = offset; | 			csum_and_copy_to_iter, csump); | ||||||
| 	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; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) | __sum16 __skb_checksum_complete_head(struct sk_buff *skb, int len) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue
	
	 Sagi Grimberg
						Sagi Grimberg