aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/tcp.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv4/tcp.c')
-rw-r--r--net/ipv4/tcp.c42
1 files changed, 36 insertions, 6 deletions
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index 18e3a12eb1b2..46efa03d2b11 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -252,6 +252,7 @@
252#include <linux/types.h> 252#include <linux/types.h>
253#include <linux/fcntl.h> 253#include <linux/fcntl.h>
254#include <linux/poll.h> 254#include <linux/poll.h>
255#include <linux/inet_diag.h>
255#include <linux/init.h> 256#include <linux/init.h>
256#include <linux/fs.h> 257#include <linux/fs.h>
257#include <linux/skbuff.h> 258#include <linux/skbuff.h>
@@ -520,8 +521,10 @@ unsigned int tcp_poll(struct file *file, struct socket *sock, poll_table *wait)
520 521
521 /* Race breaker. If space is freed after 522 /* Race breaker. If space is freed after
522 * wspace test but before the flags are set, 523 * wspace test but before the flags are set,
523 * IO signal will be lost. 524 * IO signal will be lost. Memory barrier
525 * pairs with the input side.
524 */ 526 */
527 smp_mb__after_atomic();
525 if (sk_stream_is_writeable(sk)) 528 if (sk_stream_is_writeable(sk))
526 mask |= POLLOUT | POLLWRNORM; 529 mask |= POLLOUT | POLLWRNORM;
527 } 530 }
@@ -2590,11 +2593,12 @@ EXPORT_SYMBOL(compat_tcp_setsockopt);
2590#endif 2593#endif
2591 2594
2592/* Return information about state of tcp endpoint in API format. */ 2595/* Return information about state of tcp endpoint in API format. */
2593void tcp_get_info(const struct sock *sk, struct tcp_info *info) 2596void tcp_get_info(struct sock *sk, struct tcp_info *info)
2594{ 2597{
2595 const struct tcp_sock *tp = tcp_sk(sk); 2598 const struct tcp_sock *tp = tcp_sk(sk);
2596 const struct inet_connection_sock *icsk = inet_csk(sk); 2599 const struct inet_connection_sock *icsk = inet_csk(sk);
2597 u32 now = tcp_time_stamp; 2600 u32 now = tcp_time_stamp;
2601 u32 rate;
2598 2602
2599 memset(info, 0, sizeof(*info)); 2603 memset(info, 0, sizeof(*info));
2600 2604
@@ -2655,10 +2659,16 @@ void tcp_get_info(const struct sock *sk, struct tcp_info *info)
2655 2659
2656 info->tcpi_total_retrans = tp->total_retrans; 2660 info->tcpi_total_retrans = tp->total_retrans;
2657 2661
2658 info->tcpi_pacing_rate = sk->sk_pacing_rate != ~0U ? 2662 rate = READ_ONCE(sk->sk_pacing_rate);
2659 sk->sk_pacing_rate : ~0ULL; 2663 info->tcpi_pacing_rate = rate != ~0U ? rate : ~0ULL;
2660 info->tcpi_max_pacing_rate = sk->sk_max_pacing_rate != ~0U ? 2664
2661 sk->sk_max_pacing_rate : ~0ULL; 2665 rate = READ_ONCE(sk->sk_max_pacing_rate);
2666 info->tcpi_max_pacing_rate = rate != ~0U ? rate : ~0ULL;
2667
2668 spin_lock_bh(&sk->sk_lock.slock);
2669 info->tcpi_bytes_acked = tp->bytes_acked;
2670 info->tcpi_bytes_received = tp->bytes_received;
2671 spin_unlock_bh(&sk->sk_lock.slock);
2662} 2672}
2663EXPORT_SYMBOL_GPL(tcp_get_info); 2673EXPORT_SYMBOL_GPL(tcp_get_info);
2664 2674
@@ -2730,6 +2740,26 @@ static int do_tcp_getsockopt(struct sock *sk, int level,
2730 return -EFAULT; 2740 return -EFAULT;
2731 return 0; 2741 return 0;
2732 } 2742 }
2743 case TCP_CC_INFO: {
2744 const struct tcp_congestion_ops *ca_ops;
2745 union tcp_cc_info info;
2746 size_t sz = 0;
2747 int attr;
2748
2749 if (get_user(len, optlen))
2750 return -EFAULT;
2751
2752 ca_ops = icsk->icsk_ca_ops;
2753 if (ca_ops && ca_ops->get_info)
2754 sz = ca_ops->get_info(sk, ~0U, &attr, &info);
2755
2756 len = min_t(unsigned int, len, sz);
2757 if (put_user(len, optlen))
2758 return -EFAULT;
2759 if (copy_to_user(optval, &info, len))
2760 return -EFAULT;
2761 return 0;
2762 }
2733 case TCP_QUICKACK: 2763 case TCP_QUICKACK:
2734 val = !icsk->icsk_ack.pingpong; 2764 val = !icsk->icsk_ack.pingpong;
2735 break; 2765 break;