mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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