diff options
Diffstat (limited to 'net/core/sock.c')
| -rw-r--r-- | net/core/sock.c | 47 | 
1 files changed, 35 insertions, 12 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index fb608011146..e5af8d5d5b5 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1009,6 +1009,36 @@ static void sock_copy(struct sock *nsk, const struct sock *osk)  #endif  } +/* + * caches using SLAB_DESTROY_BY_RCU should let .next pointer from nulls nodes + * un-modified. Special care is taken when initializing object to zero. + */ +static inline void sk_prot_clear_nulls(struct sock *sk, int size) +{ +	if (offsetof(struct sock, sk_node.next) != 0) +		memset(sk, 0, offsetof(struct sock, sk_node.next)); +	memset(&sk->sk_node.pprev, 0, +	       size - offsetof(struct sock, sk_node.pprev)); +} + +void sk_prot_clear_portaddr_nulls(struct sock *sk, int size) +{ +	unsigned long nulls1, nulls2; + +	nulls1 = offsetof(struct sock, __sk_common.skc_node.next); +	nulls2 = offsetof(struct sock, __sk_common.skc_portaddr_node.next); +	if (nulls1 > nulls2) +		swap(nulls1, nulls2); + +	if (nulls1 != 0) +		memset((char *)sk, 0, nulls1); +	memset((char *)sk + nulls1 + sizeof(void *), 0, +	       nulls2 - nulls1 - sizeof(void *)); +	memset((char *)sk + nulls2 + sizeof(void *), 0, +	       size - nulls2 - sizeof(void *)); +} +EXPORT_SYMBOL(sk_prot_clear_portaddr_nulls); +  static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,  		int family)  { @@ -1021,19 +1051,12 @@ static struct sock *sk_prot_alloc(struct proto *prot, gfp_t priority,  		if (!sk)  			return sk;  		if (priority & __GFP_ZERO) { -			/* -			 * caches using SLAB_DESTROY_BY_RCU should let -			 * sk_node.next un-modified. Special care is taken -			 * when initializing object to zero. -			 */ -			if (offsetof(struct sock, sk_node.next) != 0) -				memset(sk, 0, offsetof(struct sock, sk_node.next)); -			memset(&sk->sk_node.pprev, 0, -			       prot->obj_size - offsetof(struct sock, -							 sk_node.pprev)); +			if (prot->clear_sk) +				prot->clear_sk(sk, prot->obj_size); +			else +				sk_prot_clear_nulls(sk, prot->obj_size);  		} -	} -	else +	} else  		sk = kmalloc(prot->obj_size, priority);  	if (sk != NULL) {  |