diff options
Diffstat (limited to 'net/core/sock.c')
| -rw-r--r-- | net/core/sock.c | 50 | 
1 files changed, 35 insertions, 15 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index d57b0cc995a0..545fac19a711 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1992,6 +1992,19 @@ void skb_set_owner_w(struct sk_buff *skb, struct sock *sk)  }  EXPORT_SYMBOL(skb_set_owner_w); +static bool can_skb_orphan_partial(const struct sk_buff *skb) +{ +#ifdef CONFIG_TLS_DEVICE +	/* Drivers depend on in-order delivery for crypto offload, +	 * partial orphan breaks out-of-order-OK logic. +	 */ +	if (skb->decrypted) +		return false; +#endif +	return (skb->destructor == sock_wfree || +		(IS_ENABLED(CONFIG_INET) && skb->destructor == tcp_wfree)); +} +  /* This helper is used by netem, as it can hold packets in its   * delay queue. We want to allow the owner socket to send more   * packets, as if they were already TX completed by a typical driver. @@ -2003,11 +2016,7 @@ void skb_orphan_partial(struct sk_buff *skb)  	if (skb_is_tcp_pure_ack(skb))  		return; -	if (skb->destructor == sock_wfree -#ifdef CONFIG_INET -	    || skb->destructor == tcp_wfree -#endif -		) { +	if (can_skb_orphan_partial(skb)) {  		struct sock *sk = skb->sk;  		if (refcount_inc_not_zero(&sk->sk_refcnt)) { @@ -3278,16 +3287,17 @@ static __init int net_inuse_init(void)  core_initcall(net_inuse_init); -static void assign_proto_idx(struct proto *prot) +static int assign_proto_idx(struct proto *prot)  {  	prot->inuse_idx = find_first_zero_bit(proto_inuse_idx, PROTO_INUSE_NR);  	if (unlikely(prot->inuse_idx == PROTO_INUSE_NR - 1)) {  		pr_err("PROTO_INUSE_NR exhausted\n"); -		return; +		return -ENOSPC;  	}  	set_bit(prot->inuse_idx, proto_inuse_idx); +	return 0;  }  static void release_proto_idx(struct proto *prot) @@ -3296,8 +3306,9 @@ static void release_proto_idx(struct proto *prot)  		clear_bit(prot->inuse_idx, proto_inuse_idx);  }  #else -static inline void assign_proto_idx(struct proto *prot) +static inline int assign_proto_idx(struct proto *prot)  { +	return 0;  }  static inline void release_proto_idx(struct proto *prot) @@ -3346,6 +3357,8 @@ static int req_prot_init(const struct proto *prot)  int proto_register(struct proto *prot, int alloc_slab)  { +	int ret = -ENOBUFS; +  	if (alloc_slab) {  		prot->slab = kmem_cache_create_usercopy(prot->name,  					prot->obj_size, 0, @@ -3382,20 +3395,27 @@ int proto_register(struct proto *prot, int alloc_slab)  	}  	mutex_lock(&proto_list_mutex); +	ret = assign_proto_idx(prot); +	if (ret) { +		mutex_unlock(&proto_list_mutex); +		goto out_free_timewait_sock_slab_name; +	}  	list_add(&prot->node, &proto_list); -	assign_proto_idx(prot);  	mutex_unlock(&proto_list_mutex); -	return 0; +	return ret;  out_free_timewait_sock_slab_name: -	kfree(prot->twsk_prot->twsk_slab_name); +	if (alloc_slab && prot->twsk_prot) +		kfree(prot->twsk_prot->twsk_slab_name);  out_free_request_sock_slab: -	req_prot_cleanup(prot->rsk_prot); +	if (alloc_slab) { +		req_prot_cleanup(prot->rsk_prot); -	kmem_cache_destroy(prot->slab); -	prot->slab = NULL; +		kmem_cache_destroy(prot->slab); +		prot->slab = NULL; +	}  out: -	return -ENOBUFS; +	return ret;  }  EXPORT_SYMBOL(proto_register);  | 
