diff options
Diffstat (limited to 'net/core/sock.c')
| -rw-r--r-- | net/core/sock.c | 88 | 
1 files changed, 41 insertions, 47 deletions
diff --git a/net/core/sock.c b/net/core/sock.c index 026e01f70274..9c3f823e76a9 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -166,7 +166,7 @@ EXPORT_SYMBOL(sk_ns_capable);  /**   * sk_capable - Socket global capability test   * @sk: Socket to use a capability on or through - * @cap: The global capbility to use + * @cap: The global capability to use   *   * Test to see if the opener of the socket had when the socket was   * created and the current process has the capability @cap in all user @@ -183,7 +183,7 @@ EXPORT_SYMBOL(sk_capable);   * @sk: Socket to use a capability on or through   * @cap: The capability to use   * - * Test to see if the opener of the socket had when the socke was created + * Test to see if the opener of the socket had when the socket was created   * and the current process has the capability @cap over the network namespace   * the socket is a member of.   */ @@ -491,7 +491,7 @@ int sk_receive_skb(struct sock *sk, struct sk_buff *skb, const int nested)  	skb->dev = NULL; -	if (sk_rcvqueues_full(sk, skb, sk->sk_rcvbuf)) { +	if (sk_rcvqueues_full(sk, sk->sk_rcvbuf)) {  		atomic_inc(&sk->sk_drops);  		goto discard_and_relse;  	} @@ -848,24 +848,25 @@ set_rcvbuf:  			ret = -EINVAL;  			break;  		} -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE, -				  val & SOF_TIMESTAMPING_TX_HARDWARE); -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE, -				  val & SOF_TIMESTAMPING_TX_SOFTWARE); -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE, -				  val & SOF_TIMESTAMPING_RX_HARDWARE); +		if (val & SOF_TIMESTAMPING_OPT_ID && +		    !(sk->sk_tsflags & SOF_TIMESTAMPING_OPT_ID)) { +			if (sk->sk_protocol == IPPROTO_TCP) { +				if (sk->sk_state != TCP_ESTABLISHED) { +					ret = -EINVAL; +					break; +				} +				sk->sk_tskey = tcp_sk(sk)->snd_una; +			} else { +				sk->sk_tskey = 0; +			} +		} +		sk->sk_tsflags = val;  		if (val & SOF_TIMESTAMPING_RX_SOFTWARE)  			sock_enable_timestamp(sk,  					      SOCK_TIMESTAMPING_RX_SOFTWARE);  		else  			sock_disable_timestamp(sk,  					       (1UL << SOCK_TIMESTAMPING_RX_SOFTWARE)); -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_SOFTWARE, -				  val & SOF_TIMESTAMPING_SOFTWARE); -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE, -				  val & SOF_TIMESTAMPING_SYS_HARDWARE); -		sock_valbool_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE, -				  val & SOF_TIMESTAMPING_RAW_HARDWARE);  		break;  	case SO_RCVLOWAT: @@ -1091,21 +1092,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,  		break;  	case SO_TIMESTAMPING: -		v.val = 0; -		if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE)) -			v.val |= SOF_TIMESTAMPING_TX_HARDWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE)) -			v.val |= SOF_TIMESTAMPING_TX_SOFTWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE)) -			v.val |= SOF_TIMESTAMPING_RX_HARDWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE)) -			v.val |= SOF_TIMESTAMPING_RX_SOFTWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE)) -			v.val |= SOF_TIMESTAMPING_SOFTWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE)) -			v.val |= SOF_TIMESTAMPING_SYS_HARDWARE; -		if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE)) -			v.val |= SOF_TIMESTAMPING_RAW_HARDWARE; +		v.val = sk->sk_tsflags;  		break;  	case SO_RCVTIMEO: @@ -1478,6 +1465,7 @@ static void sk_update_clone(const struct sock *sk, struct sock *newsk)  struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)  {  	struct sock *newsk; +	bool is_charged = true;  	newsk = sk_prot_alloc(sk->sk_prot, priority, sk->sk_family);  	if (newsk != NULL) { @@ -1522,9 +1510,13 @@ struct sock *sk_clone_lock(const struct sock *sk, const gfp_t priority)  		filter = rcu_dereference_protected(newsk->sk_filter, 1);  		if (filter != NULL) -			sk_filter_charge(newsk, filter); +			/* though it's an empty new sock, the charging may fail +			 * if sysctl_optmem_max was changed between creation of +			 * original socket and cloning +			 */ +			is_charged = sk_filter_charge(newsk, filter); -		if (unlikely(xfrm_sk_clone_policy(newsk))) { +		if (unlikely(!is_charged || xfrm_sk_clone_policy(newsk))) {  			/* It is still raw copy of parent, so invalidate  			 * destructor and make plain sk_free() */  			newsk->sk_destruct = NULL; @@ -1830,6 +1822,9 @@ struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,  							   order);  					if (page)  						goto fill_page; +					/* Do not retry other high order allocations */ +					order = 1; +					max_page_order = 0;  				}  				order--;  			} @@ -1871,16 +1866,14 @@ EXPORT_SYMBOL(sock_alloc_send_skb);   * skb_page_frag_refill - check that a page_frag contains enough room   * @sz: minimum size of the fragment we want to get   * @pfrag: pointer to page_frag - * @prio: priority for memory allocation + * @gfp: priority for memory allocation   *   * Note: While this allocator tries to use high order pages, there is   * no guarantee that allocations succeed. Therefore, @sz MUST be   * less or equal than PAGE_SIZE.   */ -bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio) +bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t gfp)  { -	int order; -  	if (pfrag->page) {  		if (atomic_read(&pfrag->page->_count) == 1) {  			pfrag->offset = 0; @@ -1891,20 +1884,21 @@ bool skb_page_frag_refill(unsigned int sz, struct page_frag *pfrag, gfp_t prio)  		put_page(pfrag->page);  	} -	order = SKB_FRAG_PAGE_ORDER; -	do { -		gfp_t gfp = prio; - -		if (order) -			gfp |= __GFP_COMP | __GFP_NOWARN | __GFP_NORETRY; -		pfrag->page = alloc_pages(gfp, order); +	pfrag->offset = 0; +	if (SKB_FRAG_PAGE_ORDER) { +		pfrag->page = alloc_pages(gfp | __GFP_COMP | +					  __GFP_NOWARN | __GFP_NORETRY, +					  SKB_FRAG_PAGE_ORDER);  		if (likely(pfrag->page)) { -			pfrag->offset = 0; -			pfrag->size = PAGE_SIZE << order; +			pfrag->size = PAGE_SIZE << SKB_FRAG_PAGE_ORDER;  			return true;  		} -	} while (--order >= 0); - +	} +	pfrag->page = alloc_page(gfp); +	if (likely(pfrag->page)) { +		pfrag->size = PAGE_SIZE; +		return true; +	}  	return false;  }  EXPORT_SYMBOL(skb_page_frag_refill);  |