diff options
Diffstat (limited to 'include/net/sock.h')
| -rw-r--r-- | include/net/sock.h | 83 | 
1 files changed, 71 insertions, 12 deletions
diff --git a/include/net/sock.h b/include/net/sock.h index f665d74ae509..2b229f7be8eb 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -298,6 +298,7 @@ struct sock_common {    *	@sk_filter: socket filtering instructions    *	@sk_timer: sock cleanup timer    *	@sk_stamp: time stamp of last packet received +  *	@sk_stamp_seq: lock for accessing sk_stamp on 32 bit architectures only    *	@sk_tsflags: SO_TIMESTAMPING socket options    *	@sk_tskey: counter to disambiguate concurrent tstamp requests    *	@sk_zckey: counter to order MSG_ZEROCOPY notifications @@ -474,6 +475,9 @@ struct sock {  	const struct cred	*sk_peer_cred;  	long			sk_rcvtimeo;  	ktime_t			sk_stamp; +#if BITS_PER_LONG==32 +	seqlock_t		sk_stamp_seq; +#endif  	u16			sk_tsflags;  	u8			sk_shutdown;  	u32			sk_tskey; @@ -1110,7 +1114,7 @@ struct proto {  	unsigned int		inuse_idx;  #endif -	bool			(*stream_memory_free)(const struct sock *sk); +	bool			(*stream_memory_free)(const struct sock *sk, int wake);  	bool			(*stream_memory_read)(const struct sock *sk);  	/* Memory pressure */  	void			(*enter_memory_pressure)(struct sock *sk); @@ -1192,19 +1196,29 @@ static inline void sk_refcnt_debug_release(const struct sock *sk)  #define sk_refcnt_debug_release(sk) do { } while (0)  #endif /* SOCK_REFCNT_DEBUG */ -static inline bool sk_stream_memory_free(const struct sock *sk) +static inline bool __sk_stream_memory_free(const struct sock *sk, int wake)  {  	if (sk->sk_wmem_queued >= sk->sk_sndbuf)  		return false;  	return sk->sk_prot->stream_memory_free ? -		sk->sk_prot->stream_memory_free(sk) : true; +		sk->sk_prot->stream_memory_free(sk, wake) : true;  } -static inline bool sk_stream_is_writeable(const struct sock *sk) +static inline bool sk_stream_memory_free(const struct sock *sk) +{ +	return __sk_stream_memory_free(sk, 0); +} + +static inline bool __sk_stream_is_writeable(const struct sock *sk, int wake)  {  	return sk_stream_wspace(sk) >= sk_stream_min_wspace(sk) && -	       sk_stream_memory_free(sk); +	       __sk_stream_memory_free(sk, wake); +} + +static inline bool sk_stream_is_writeable(const struct sock *sk) +{ +	return __sk_stream_is_writeable(sk, 0);  }  static inline int sk_under_cgroup_hierarchy(struct sock *sk, @@ -2287,6 +2301,34 @@ static inline void sk_drops_add(struct sock *sk, const struct sk_buff *skb)  	atomic_add(segs, &sk->sk_drops);  } +static inline ktime_t sock_read_timestamp(struct sock *sk) +{ +#if BITS_PER_LONG==32 +	unsigned int seq; +	ktime_t kt; + +	do { +		seq = read_seqbegin(&sk->sk_stamp_seq); +		kt = sk->sk_stamp; +	} while (read_seqretry(&sk->sk_stamp_seq, seq)); + +	return kt; +#else +	return sk->sk_stamp; +#endif +} + +static inline void sock_write_timestamp(struct sock *sk, ktime_t kt) +{ +#if BITS_PER_LONG==32 +	write_seqlock(&sk->sk_stamp_seq); +	sk->sk_stamp = kt; +	write_sequnlock(&sk->sk_stamp_seq); +#else +	sk->sk_stamp = kt; +#endif +} +  void __sock_recv_timestamp(struct msghdr *msg, struct sock *sk,  			   struct sk_buff *skb);  void __sock_recv_wifi_status(struct msghdr *msg, struct sock *sk, @@ -2311,7 +2353,7 @@ sock_recv_timestamp(struct msghdr *msg, struct sock *sk, struct sk_buff *skb)  	     (sk->sk_tsflags & SOF_TIMESTAMPING_RAW_HARDWARE)))  		__sock_recv_timestamp(msg, sk, skb);  	else -		sk->sk_stamp = kt; +		sock_write_timestamp(sk, kt);  	if (sock_flag(sk, SOCK_WIFI_STATUS) && skb->wifi_acked_valid)  		__sock_recv_wifi_status(msg, sk, skb); @@ -2332,30 +2374,47 @@ static inline void sock_recv_ts_and_drops(struct msghdr *msg, struct sock *sk,  	if (sk->sk_flags & FLAGS_TS_OR_DROPS || sk->sk_tsflags & TSFLAGS_ANY)  		__sock_recv_ts_and_drops(msg, sk, skb);  	else if (unlikely(sock_flag(sk, SOCK_TIMESTAMP))) -		sk->sk_stamp = skb->tstamp; +		sock_write_timestamp(sk, skb->tstamp);  	else if (unlikely(sk->sk_stamp == SK_DEFAULT_STAMP)) -		sk->sk_stamp = 0; +		sock_write_timestamp(sk, 0);  }  void __sock_tx_timestamp(__u16 tsflags, __u8 *tx_flags);  /** - * sock_tx_timestamp - checks whether the outgoing packet is to be time stamped + * _sock_tx_timestamp - checks whether the outgoing packet is to be time stamped   * @sk:		socket sending this packet   * @tsflags:	timestamping flags to use   * @tx_flags:	completed with instructions for time stamping + * @tskey:      filled in with next sk_tskey (not for TCP, which uses seqno)   *   * Note: callers should take care of initial ``*tx_flags`` value (usually 0)   */ -static inline void sock_tx_timestamp(const struct sock *sk, __u16 tsflags, -				     __u8 *tx_flags) +static inline void _sock_tx_timestamp(struct sock *sk, __u16 tsflags, +				      __u8 *tx_flags, __u32 *tskey)  { -	if (unlikely(tsflags)) +	if (unlikely(tsflags)) {  		__sock_tx_timestamp(tsflags, tx_flags); +		if (tsflags & SOF_TIMESTAMPING_OPT_ID && tskey && +		    tsflags & SOF_TIMESTAMPING_TX_RECORD_MASK) +			*tskey = sk->sk_tskey++; +	}  	if (unlikely(sock_flag(sk, SOCK_WIFI_STATUS)))  		*tx_flags |= SKBTX_WIFI_STATUS;  } +static inline void sock_tx_timestamp(struct sock *sk, __u16 tsflags, +				     __u8 *tx_flags) +{ +	_sock_tx_timestamp(sk, tsflags, tx_flags, NULL); +} + +static inline void skb_setup_tx_timestamp(struct sk_buff *skb, __u16 tsflags) +{ +	_sock_tx_timestamp(skb->sk, tsflags, &skb_shinfo(skb)->tx_flags, +			   &skb_shinfo(skb)->tskey); +} +  /**   * sk_eat_skb - Release a skb if it is no longer needed   * @sk: socket to eat this skb from  |