diff options
Diffstat (limited to 'net/core/skbuff.c')
| -rw-r--r-- | net/core/skbuff.c | 261 | 
1 files changed, 145 insertions, 116 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 9e0597d189b..19d6c21220f 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -93,7 +93,7 @@ static int sock_pipe_buf_steal(struct pipe_inode_info *pipe,  /* Pipe buffer operations for a socket. */ -static struct pipe_buf_operations sock_pipe_buf_ops = { +static const struct pipe_buf_operations sock_pipe_buf_ops = {  	.can_merge = 0,  	.map = generic_pipe_buf_map,  	.unmap = generic_pipe_buf_unmap, @@ -117,7 +117,7 @@ static struct pipe_buf_operations sock_pipe_buf_ops = {   *   *	Out of line support code for skb_put(). Not user callable.   */ -void skb_over_panic(struct sk_buff *skb, int sz, void *here) +static void skb_over_panic(struct sk_buff *skb, int sz, void *here)  {  	printk(KERN_EMERG "skb_over_panic: text:%p len:%d put:%d head:%p "  			  "data:%p tail:%#lx end:%#lx dev:%s\n", @@ -126,7 +126,6 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)  	       skb->dev ? skb->dev->name : "<NULL>");  	BUG();  } -EXPORT_SYMBOL(skb_over_panic);  /**   *	skb_under_panic	- 	private function @@ -137,7 +136,7 @@ EXPORT_SYMBOL(skb_over_panic);   *	Out of line support code for skb_push(). Not user callable.   */ -void skb_under_panic(struct sk_buff *skb, int sz, void *here) +static void skb_under_panic(struct sk_buff *skb, int sz, void *here)  {  	printk(KERN_EMERG "skb_under_panic: text:%p len:%d put:%d head:%p "  			  "data:%p tail:%#lx end:%#lx dev:%s\n", @@ -146,7 +145,6 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)  	       skb->dev ? skb->dev->name : "<NULL>");  	BUG();  } -EXPORT_SYMBOL(skb_under_panic);  /* 	Allocate a new skbuff. We do this ourselves so we can fill in a few   *	'private' fields and also do memory statistics to find all the @@ -183,12 +181,14 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  	skb = kmem_cache_alloc_node(cache, gfp_mask & ~__GFP_DMA, node);  	if (!skb)  		goto out; +	prefetchw(skb);  	size = SKB_DATA_ALIGN(size);  	data = kmalloc_node_track_caller(size + sizeof(struct skb_shared_info),  			gfp_mask, node);  	if (!data)  		goto nodata; +	prefetchw(data + size);  	/*  	 * Only clear those fields we need to clear, not those that we will @@ -202,23 +202,14 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,  	skb->data = data;  	skb_reset_tail_pointer(skb);  	skb->end = skb->tail + size; -	kmemcheck_annotate_bitfield(skb, flags1); -	kmemcheck_annotate_bitfield(skb, flags2);  #ifdef NET_SKBUFF_DATA_USES_OFFSET  	skb->mac_header = ~0U;  #endif  	/* make sure we initialize shinfo sequentially */  	shinfo = skb_shinfo(skb); +	memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));  	atomic_set(&shinfo->dataref, 1); -	shinfo->nr_frags  = 0; -	shinfo->gso_size = 0; -	shinfo->gso_segs = 0; -	shinfo->gso_type = 0; -	shinfo->ip6_frag_id = 0; -	shinfo->tx_flags.flags = 0; -	skb_frag_list_init(skb); -	memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));  	if (fclone) {  		struct sk_buff *child = skb + 1; @@ -256,10 +247,9 @@ EXPORT_SYMBOL(__alloc_skb);  struct sk_buff *__netdev_alloc_skb(struct net_device *dev,  		unsigned int length, gfp_t gfp_mask)  { -	int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1;  	struct sk_buff *skb; -	skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, node); +	skb = __alloc_skb(length + NET_SKB_PAD, gfp_mask, 0, NUMA_NO_NODE);  	if (likely(skb)) {  		skb_reserve(skb, NET_SKB_PAD);  		skb->dev = dev; @@ -268,16 +258,6 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,  }  EXPORT_SYMBOL(__netdev_alloc_skb); -struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask) -{ -	int node = dev->dev.parent ? dev_to_node(dev->dev.parent) : -1; -	struct page *page; - -	page = alloc_pages_node(node, gfp_mask, 0); -	return page; -} -EXPORT_SYMBOL(__netdev_alloc_page); -  void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,  		int size)  { @@ -347,7 +327,7 @@ static void skb_release_data(struct sk_buff *skb)  				put_page(skb_shinfo(skb)->frags[i].page);  		} -		if (skb_has_frags(skb)) +		if (skb_has_frag_list(skb))  			skb_drop_fraglist(skb);  		kfree(skb->head); @@ -473,6 +453,7 @@ void consume_skb(struct sk_buff *skb)  		smp_rmb();  	else if (likely(!atomic_dec_and_test(&skb->users)))  		return; +	trace_consume_skb(skb);  	__kfree_skb(skb);  }  EXPORT_SYMBOL(consume_skb); @@ -489,37 +470,34 @@ EXPORT_SYMBOL(consume_skb);   *	reference count dropping and cleans up the skbuff as if it   *	just came from __alloc_skb().   */ -int skb_recycle_check(struct sk_buff *skb, int skb_size) +bool skb_recycle_check(struct sk_buff *skb, int skb_size)  {  	struct skb_shared_info *shinfo; +	if (irqs_disabled()) +		return false; +  	if (skb_is_nonlinear(skb) || skb->fclone != SKB_FCLONE_UNAVAILABLE) -		return 0; +		return false;  	skb_size = SKB_DATA_ALIGN(skb_size + NET_SKB_PAD);  	if (skb_end_pointer(skb) - skb->head < skb_size) -		return 0; +		return false;  	if (skb_shared(skb) || skb_cloned(skb)) -		return 0; +		return false;  	skb_release_head_state(skb); +  	shinfo = skb_shinfo(skb); +	memset(shinfo, 0, offsetof(struct skb_shared_info, dataref));  	atomic_set(&shinfo->dataref, 1); -	shinfo->nr_frags = 0; -	shinfo->gso_size = 0; -	shinfo->gso_segs = 0; -	shinfo->gso_type = 0; -	shinfo->ip6_frag_id = 0; -	shinfo->tx_flags.flags = 0; -	skb_frag_list_init(skb); -	memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));  	memset(skb, 0, offsetof(struct sk_buff, tail));  	skb->data = skb->head + NET_SKB_PAD;  	skb_reset_tail_pointer(skb); -	return 1; +	return true;  }  EXPORT_SYMBOL(skb_recycle_check); @@ -530,7 +508,8 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	new->transport_header	= old->transport_header;  	new->network_header	= old->network_header;  	new->mac_header		= old->mac_header; -	skb_dst_set(new, dst_clone(skb_dst(old))); +	skb_dst_copy(new, old); +	new->rxhash		= old->rxhash;  #ifdef CONFIG_XFRM  	new->sp			= secpath_get(old->sp);  #endif @@ -541,12 +520,13 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  	new->ip_summed		= old->ip_summed;  	skb_copy_queue_mapping(new, old);  	new->priority		= old->priority; +	new->deliver_no_wcard	= old->deliver_no_wcard;  #if defined(CONFIG_IP_VS) || defined(CONFIG_IP_VS_MODULE)  	new->ipvs_property	= old->ipvs_property;  #endif  	new->protocol		= old->protocol;  	new->mark		= old->mark; -	new->iif		= old->iif; +	new->skb_iif		= old->skb_iif;  	__nf_copy(new, old);  #if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) || \      defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE) @@ -559,9 +539,6 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  #endif  #endif  	new->vlan_tci		= old->vlan_tci; -#if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) -	new->do_not_encrypt	= old->do_not_encrypt; -#endif  	skb_copy_secmark(new, old);  } @@ -696,16 +673,10 @@ static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)  struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)  { -	int headerlen = skb->data - skb->head; -	/* -	 *	Allocate the copy buffer -	 */ -	struct sk_buff *n; -#ifdef NET_SKBUFF_DATA_USES_OFFSET -	n = alloc_skb(skb->end + skb->data_len, gfp_mask); -#else -	n = alloc_skb(skb->end - skb->head + skb->data_len, gfp_mask); -#endif +	int headerlen = skb_headroom(skb); +	unsigned int size = (skb_end_pointer(skb) - skb->head) + skb->data_len; +	struct sk_buff *n = alloc_skb(size, gfp_mask); +  	if (!n)  		return NULL; @@ -737,20 +708,14 @@ EXPORT_SYMBOL(skb_copy);  struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)  { -	/* -	 *	Allocate the copy buffer -	 */ -	struct sk_buff *n; -#ifdef NET_SKBUFF_DATA_USES_OFFSET -	n = alloc_skb(skb->end, gfp_mask); -#else -	n = alloc_skb(skb->end - skb->head, gfp_mask); -#endif +	unsigned int size = skb_end_pointer(skb) - skb->head; +	struct sk_buff *n = alloc_skb(size, gfp_mask); +  	if (!n)  		goto out;  	/* Set the data pointer */ -	skb_reserve(n, skb->data - skb->head); +	skb_reserve(n, skb_headroom(skb));  	/* Set the tail pointer and length */  	skb_put(n, skb_headlen(skb));  	/* Copy the bytes */ @@ -770,7 +735,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)  		skb_shinfo(n)->nr_frags = i;  	} -	if (skb_has_frags(skb)) { +	if (skb_has_frag_list(skb)) {  		skb_shinfo(n)->frag_list = skb_shinfo(skb)->frag_list;  		skb_clone_fraglist(n);  	} @@ -802,12 +767,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  {  	int i;  	u8 *data; -#ifdef NET_SKBUFF_DATA_USES_OFFSET -	int size = nhead + skb->end + ntail; -#else -	int size = nhead + (skb->end - skb->head) + ntail; -#endif +	int size = nhead + (skb_end_pointer(skb) - skb->head) + ntail;  	long off; +	bool fastpath;  	BUG_ON(nhead < 0); @@ -816,31 +778,56 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  	size = SKB_DATA_ALIGN(size); +	/* Check if we can avoid taking references on fragments if we own +	 * the last reference on skb->head. (see skb_release_data()) +	 */ +	if (!skb->cloned) +		fastpath = true; +	else { +		int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1; + +		fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta; +	} + +	if (fastpath && +	    size + sizeof(struct skb_shared_info) <= ksize(skb->head)) { +		memmove(skb->head + size, skb_shinfo(skb), +			offsetof(struct skb_shared_info, +				 frags[skb_shinfo(skb)->nr_frags])); +		memmove(skb->head + nhead, skb->head, +			skb_tail_pointer(skb) - skb->head); +		off = nhead; +		goto adjust_others; +	} +  	data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);  	if (!data)  		goto nodata;  	/* Copy only real data... and, alas, header. This should be -	 * optimized for the cases when header is void. */ -#ifdef NET_SKBUFF_DATA_USES_OFFSET -	memcpy(data + nhead, skb->head, skb->tail); -#else -	memcpy(data + nhead, skb->head, skb->tail - skb->head); -#endif -	memcpy(data + size, skb_end_pointer(skb), -	       sizeof(struct skb_shared_info)); +	 * optimized for the cases when header is void. +	 */ +	memcpy(data + nhead, skb->head, skb_tail_pointer(skb) - skb->head); -	for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) -		get_page(skb_shinfo(skb)->frags[i].page); +	memcpy((struct skb_shared_info *)(data + size), +	       skb_shinfo(skb), +	       offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags])); -	if (skb_has_frags(skb)) -		skb_clone_fraglist(skb); +	if (fastpath) { +		kfree(skb->head); +	} else { +		for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) +			get_page(skb_shinfo(skb)->frags[i].page); -	skb_release_data(skb); +		if (skb_has_frag_list(skb)) +			skb_clone_fraglist(skb); +		skb_release_data(skb); +	}  	off = (data + nhead) - skb->head;  	skb->head     = data; +adjust_others:  	skb->data    += off;  #ifdef NET_SKBUFF_DATA_USES_OFFSET  	skb->end      = size; @@ -854,7 +841,9 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,  	skb->network_header   += off;  	if (skb_mac_header_was_set(skb))  		skb->mac_header += off; -	skb->csum_start       += nhead; +	/* Only adjust this if it actually is csum_start rather than csum */ +	if (skb->ip_summed == CHECKSUM_PARTIAL) +		skb->csum_start += nhead;  	skb->cloned   = 0;  	skb->hdr_len  = 0;  	skb->nohdr    = 0; @@ -941,7 +930,8 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,  	copy_skb_header(n, skb);  	off                  = newheadroom - oldheadroom; -	n->csum_start       += off; +	if (n->ip_summed == CHECKSUM_PARTIAL) +		n->csum_start += off;  #ifdef NET_SKBUFF_DATA_USES_OFFSET  	n->transport_header += off;  	n->network_header   += off; @@ -1051,7 +1041,7 @@ EXPORT_SYMBOL(skb_push);   */  unsigned char *skb_pull(struct sk_buff *skb, unsigned int len)  { -	return unlikely(len > skb->len) ? NULL : __skb_pull(skb, len); +	return skb_pull_inline(skb, len);  }  EXPORT_SYMBOL(skb_pull); @@ -1107,7 +1097,7 @@ drop_pages:  		for (; i < nfrags; i++)  			put_page(skb_shinfo(skb)->frags[i].page); -		if (skb_has_frags(skb)) +		if (skb_has_frag_list(skb))  			skb_drop_fraglist(skb);  		goto done;  	} @@ -1202,7 +1192,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)  	/* Optimization: no fragments, no reasons to preestimate  	 * size of pulled pages. Superb.  	 */ -	if (!skb_has_frags(skb)) +	if (!skb_has_frag_list(skb))  		goto pull_pages;  	/* Estimate size of pulled pages. */ @@ -1417,12 +1407,13 @@ new_page:  /*   * Fill page/offset/length into spd, if it can hold more pages.   */ -static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page, +static inline int spd_fill_page(struct splice_pipe_desc *spd, +				struct pipe_inode_info *pipe, struct page *page,  				unsigned int *len, unsigned int offset,  				struct sk_buff *skb, int linear,  				struct sock *sk)  { -	if (unlikely(spd->nr_pages == PIPE_BUFFERS)) +	if (unlikely(spd->nr_pages == pipe->buffers))  		return 1;  	if (linear) { @@ -1458,7 +1449,8 @@ static inline int __splice_segment(struct page *page, unsigned int poff,  				   unsigned int plen, unsigned int *off,  				   unsigned int *len, struct sk_buff *skb,  				   struct splice_pipe_desc *spd, int linear, -				   struct sock *sk) +				   struct sock *sk, +				   struct pipe_inode_info *pipe)  {  	if (!*len)  		return 1; @@ -1481,7 +1473,7 @@ static inline int __splice_segment(struct page *page, unsigned int poff,  		/* the linear region may spread across several pages  */  		flen = min_t(unsigned int, flen, PAGE_SIZE - poff); -		if (spd_fill_page(spd, page, &flen, poff, skb, linear, sk)) +		if (spd_fill_page(spd, pipe, page, &flen, poff, skb, linear, sk))  			return 1;  		__segment_seek(&page, &poff, &plen, flen); @@ -1496,9 +1488,9 @@ static inline int __splice_segment(struct page *page, unsigned int poff,   * Map linear and fragment data from the skb to spd. It reports failure if the   * pipe is full or if we already spliced the requested length.   */ -static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset, -			     unsigned int *len, struct splice_pipe_desc *spd, -			     struct sock *sk) +static int __skb_splice_bits(struct sk_buff *skb, struct pipe_inode_info *pipe, +			     unsigned int *offset, unsigned int *len, +			     struct splice_pipe_desc *spd, struct sock *sk)  {  	int seg; @@ -1508,7 +1500,7 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,  	if (__splice_segment(virt_to_page(skb->data),  			     (unsigned long) skb->data & (PAGE_SIZE - 1),  			     skb_headlen(skb), -			     offset, len, skb, spd, 1, sk)) +			     offset, len, skb, spd, 1, sk, pipe))  		return 1;  	/* @@ -1518,7 +1510,7 @@ static int __skb_splice_bits(struct sk_buff *skb, unsigned int *offset,  		const skb_frag_t *f = &skb_shinfo(skb)->frags[seg];  		if (__splice_segment(f->page, f->page_offset, f->size, -				     offset, len, skb, spd, 0, sk)) +				     offset, len, skb, spd, 0, sk, pipe))  			return 1;  	} @@ -1535,8 +1527,8 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,  		    struct pipe_inode_info *pipe, unsigned int tlen,  		    unsigned int flags)  { -	struct partial_page partial[PIPE_BUFFERS]; -	struct page *pages[PIPE_BUFFERS]; +	struct partial_page partial[PIPE_DEF_BUFFERS]; +	struct page *pages[PIPE_DEF_BUFFERS];  	struct splice_pipe_desc spd = {  		.pages = pages,  		.partial = partial, @@ -1546,12 +1538,16 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,  	};  	struct sk_buff *frag_iter;  	struct sock *sk = skb->sk; +	int ret = 0; + +	if (splice_grow_spd(pipe, &spd)) +		return -ENOMEM;  	/*  	 * __skb_splice_bits() only fails if the output has no room left,  	 * so no point in going over the frag_list for the error case.  	 */ -	if (__skb_splice_bits(skb, &offset, &tlen, &spd, sk)) +	if (__skb_splice_bits(skb, pipe, &offset, &tlen, &spd, sk))  		goto done;  	else if (!tlen)  		goto done; @@ -1562,14 +1558,12 @@ int skb_splice_bits(struct sk_buff *skb, unsigned int offset,  	skb_walk_frags(skb, frag_iter) {  		if (!tlen)  			break; -		if (__skb_splice_bits(frag_iter, &offset, &tlen, &spd, sk)) +		if (__skb_splice_bits(frag_iter, pipe, &offset, &tlen, &spd, sk))  			break;  	}  done:  	if (spd.nr_pages) { -		int ret; -  		/*  		 * Drop the socket lock, otherwise we have reverse  		 * locking dependencies between sk_lock and i_mutex @@ -1582,10 +1576,10 @@ done:  		release_sock(sk);  		ret = splice_to_pipe(pipe, &spd);  		lock_sock(sk); -		return ret;  	} -	return 0; +	splice_shrink_spd(pipe, &spd); +	return ret;  }  /** @@ -1830,7 +1824,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)  	long csstart;  	if (skb->ip_summed == CHECKSUM_PARTIAL) -		csstart = skb->csum_start - skb_headroom(skb); +		csstart = skb_checksum_start_offset(skb);  	else  		csstart = skb_headlen(skb); @@ -2327,7 +2321,7 @@ next_skb:  		st->frag_data = NULL;  	} -	if (st->root_skb == st->cur_skb && skb_has_frags(st->root_skb)) { +	if (st->root_skb == st->cur_skb && skb_has_frag_list(st->root_skb)) {  		st->cur_skb = skb_shinfo(st->root_skb)->frag_list;  		st->frag_idx = 0;  		goto next_skb; @@ -2490,7 +2484,6 @@ unsigned char *skb_pull_rcsum(struct sk_buff *skb, unsigned int len)  	skb_postpull_rcsum(skb, skb->data, len);  	return skb->data += len;  } -  EXPORT_SYMBOL_GPL(skb_pull_rcsum);  /** @@ -2578,6 +2571,10 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features)  		__copy_skb_header(nskb, skb);  		nskb->mac_len = skb->mac_len; +		/* nskb and skb might have different headroom */ +		if (nskb->ip_summed == CHECKSUM_PARTIAL) +			nskb->csum_start += skb_headroom(nskb) - headroom; +  		skb_reset_mac_header(nskb);  		skb_set_network_header(nskb, skb->mac_len);  		nskb->transport_header = (nskb->network_header + @@ -2704,10 +2701,11 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  		NAPI_GRO_CB(skb)->free = 1;  		goto done; -	} +	} else if (skb_gro_len(p) != pinfo->gso_size) +		return -E2BIG;  	headroom = skb_headroom(p); -	nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p)); +	nskb = alloc_skb(headroom + skb_gro_offset(p), GFP_ATOMIC);  	if (unlikely(!nskb))  		return -ENOMEM; @@ -2728,6 +2726,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)  	*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);  	skb_shinfo(nskb)->frag_list = p;  	skb_shinfo(nskb)->gso_size = pinfo->gso_size; +	pinfo->gso_size = 0;  	skb_header_release(p);  	nskb->prev = p; @@ -2892,7 +2891,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)  		return -ENOMEM;  	/* Easy case. Most of packets will go this way. */ -	if (!skb_has_frags(skb)) { +	if (!skb_has_frag_list(skb)) {  		/* A little of trouble, not enough of space for trailer.  		 * This should not happen, when stack is tuned to generate  		 * good frames. OK, on miss we reallocate and reserve even more @@ -2927,7 +2926,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)  		if (skb1->next == NULL && tailbits) {  			if (skb_shinfo(skb1)->nr_frags || -			    skb_has_frags(skb1) || +			    skb_has_frag_list(skb1) ||  			    skb_tailroom(skb1) < tailbits)  				ntail = tailbits + 128;  		} @@ -2936,7 +2935,7 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)  		    skb_cloned(skb1) ||  		    ntail ||  		    skb_shinfo(skb1)->nr_frags || -		    skb_has_frags(skb1)) { +		    skb_has_frag_list(skb1)) {  			struct sk_buff *skb2;  			/* Fuck, we are miserable poor guys... */ @@ -2970,6 +2969,34 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)  }  EXPORT_SYMBOL_GPL(skb_cow_data); +static void sock_rmem_free(struct sk_buff *skb) +{ +	struct sock *sk = skb->sk; + +	atomic_sub(skb->truesize, &sk->sk_rmem_alloc); +} + +/* + * Note: We dont mem charge error packets (no sk_forward_alloc changes) + */ +int sock_queue_err_skb(struct sock *sk, struct sk_buff *skb) +{ +	if (atomic_read(&sk->sk_rmem_alloc) + skb->truesize >= +	    (unsigned)sk->sk_rcvbuf) +		return -ENOMEM; + +	skb_orphan(skb); +	skb->sk = sk; +	skb->destructor = sock_rmem_free; +	atomic_add(skb->truesize, &sk->sk_rmem_alloc); + +	skb_queue_tail(&sk->sk_error_queue, skb); +	if (!sock_flag(sk, SOCK_DEAD)) +		sk->sk_data_ready(sk, skb->len); +	return 0; +} +EXPORT_SYMBOL(sock_queue_err_skb); +  void skb_tstamp_tx(struct sk_buff *orig_skb,  		struct skb_shared_hwtstamps *hwtstamps)  { @@ -2991,7 +3018,7 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,  	} else {  		/*  		 * no hardware time stamps available, -		 * so keep the skb_shared_tx and only +		 * so keep the shared tx_flags and only  		 * store software time stamp  		 */  		skb->tstamp = ktime_get_real(); @@ -3001,7 +3028,9 @@ void skb_tstamp_tx(struct sk_buff *orig_skb,  	memset(serr, 0, sizeof(*serr));  	serr->ee.ee_errno = ENOMSG;  	serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING; +  	err = sock_queue_err_skb(sk, skb); +  	if (err)  		kfree_skb(skb);  }  | 
