diff options
Diffstat (limited to 'include/net/sock.h')
| -rw-r--r-- | include/net/sock.h | 57 | 
1 files changed, 50 insertions, 7 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index bbf7c2cf15b4..52d27ee924f4 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -254,7 +254,6 @@ struct cg_proto;    *	@sk_wq: sock wait queue and async head    *	@sk_rx_dst: receive input route used by early demux    *	@sk_dst_cache: destination cache -  *	@sk_dst_lock: destination cache lock    *	@sk_policy: flow policy    *	@sk_receive_queue: incoming packets    *	@sk_wmem_alloc: transmit queue bytes committed @@ -384,14 +383,16 @@ struct sock {  	int			sk_rcvbuf;  	struct sk_filter __rcu	*sk_filter; -	struct socket_wq __rcu	*sk_wq; - +	union { +		struct socket_wq __rcu	*sk_wq; +		struct socket_wq	*sk_wq_raw; +	};  #ifdef CONFIG_XFRM  	struct xfrm_policy	*sk_policy[2];  #endif  	struct dst_entry	*sk_rx_dst;  	struct dst_entry __rcu	*sk_dst_cache; -	spinlock_t		sk_dst_lock; +	/* Note: 32bit hole on 64bit arches */  	atomic_t		sk_wmem_alloc;  	atomic_t		sk_omem_alloc;  	int			sk_sndbuf; @@ -2005,10 +2006,27 @@ static inline unsigned long sock_wspace(struct sock *sk)  	return amt;  } -static inline void sk_wake_async(struct sock *sk, int how, int band) +/* Note: + *  We use sk->sk_wq_raw, from contexts knowing this + *  pointer is not NULL and cannot disappear/change. + */ +static inline void sk_set_bit(int nr, struct sock *sk) +{ +	set_bit(nr, &sk->sk_wq_raw->flags); +} + +static inline void sk_clear_bit(int nr, struct sock *sk) +{ +	clear_bit(nr, &sk->sk_wq_raw->flags); +} + +static inline void sk_wake_async(const struct sock *sk, int how, int band)  { -	if (sock_flag(sk, SOCK_FASYNC)) -		sock_wake_async(sk->sk_socket, how, band); +	if (sock_flag(sk, SOCK_FASYNC)) { +		rcu_read_lock(); +		sock_wake_async(rcu_dereference(sk->sk_wq), how, band); +		rcu_read_unlock(); +	}  }  /* Since sk_{r,w}mem_alloc sums skb->truesize, even a small frame might @@ -2226,6 +2244,31 @@ static inline bool sk_listener(const struct sock *sk)  	return (1 << sk->sk_state) & (TCPF_LISTEN | TCPF_NEW_SYN_RECV);  } +/** + * sk_state_load - read sk->sk_state for lockless contexts + * @sk: socket pointer + * + * Paired with sk_state_store(). Used in places we do not hold socket lock : + * tcp_diag_get_info(), tcp_get_info(), tcp_poll(), get_tcp4_sock() ... + */ +static inline int sk_state_load(const struct sock *sk) +{ +	return smp_load_acquire(&sk->sk_state); +} + +/** + * sk_state_store - update sk->sk_state + * @sk: socket pointer + * @newstate: new state + * + * Paired with sk_state_load(). Should be used in contexts where + * state change might impact lockless readers. + */ +static inline void sk_state_store(struct sock *sk, int newstate) +{ +	smp_store_release(&sk->sk_state, newstate); +} +  void sock_enable_timestamp(struct sock *sk, int flag);  int sock_get_timestamp(struct sock *, struct timeval __user *);  int sock_get_timestampns(struct sock *, struct timespec __user *);  | 
