diff --git a/include/net/tcp.h b/include/net/tcp.h index 3cac91513eb4..33307aaa734b 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -749,7 +749,7 @@ static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize) } /* tcp.c */ -void tcp_get_info(struct sock *, struct tcp_info *); +void tcp_get_info(struct sock *, struct tcp_info *, bool no_lock); /* Read 'sendfile()'-style from a TCP socket */ int tcp_read_sock(struct sock *sk, read_descriptor_t *desc, diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 73dc7ae60166..ccdc1076f464 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -3279,7 +3279,7 @@ static void tcp_get_info_chrono_stats(const struct tcp_sock *tp, } /* Return information about state of tcp endpoint in API format. */ -void tcp_get_info(struct sock *sk, struct tcp_info *info) +void tcp_get_info(struct sock *sk, struct tcp_info *info, bool no_lock) { const struct tcp_sock *tp = tcp_sk(sk); /* iff sk_type == SOCK_STREAM */ const struct inet_connection_sock *icsk = inet_csk(sk); @@ -3316,7 +3316,8 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) return; } - slow = lock_sock_fast(sk); + if (!no_lock) + slow = lock_sock_fast(sk); info->tcpi_ca_state = icsk->icsk_ca_state; info->tcpi_retransmits = icsk->icsk_retransmits; @@ -3390,7 +3391,9 @@ void tcp_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_bytes_retrans = tp->bytes_retrans; info->tcpi_dsack_dups = tp->dsack_dups; info->tcpi_reord_seen = tp->reord_seen; - unlock_sock_fast(sk, slow); + + if (!no_lock) + unlock_sock_fast(sk, slow); } EXPORT_SYMBOL_GPL(tcp_get_info); @@ -3535,7 +3538,7 @@ static int do_tcp_getsockopt(struct sock *sk, int level, if (get_user(len, optlen)) return -EFAULT; - tcp_get_info(sk, &info); + tcp_get_info(sk, &info, false); len = min_t(unsigned int, len, sizeof(info)); if (put_user(len, optlen)) diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 81148f7a2323..87d94074044e 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -34,7 +34,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, r->idiag_wqueue = tp->write_seq - tp->snd_una; } if (info) - tcp_get_info(sk, info); + tcp_get_info(sk, info, false); } #ifdef CONFIG_TCP_MD5SIG diff --git a/net/mptcp/mptcp_ctrl.c b/net/mptcp/mptcp_ctrl.c index 7bc562ef9a34..32b5bcf87f00 100644 --- a/net/mptcp/mptcp_ctrl.c +++ b/net/mptcp/mptcp_ctrl.c @@ -1530,7 +1530,7 @@ void mptcp_del_sock(struct sock *sk) GFP_ATOMIC); if (mpcb->master_info) - tcp_get_info(sk, mpcb->master_info); + tcp_get_info(sk, mpcb->master_info, true); } mpcb->master_sk = NULL; @@ -2718,7 +2718,7 @@ int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) if (mpcb->master_sk) { struct tcp_info info; - tcp_get_info(mpcb->master_sk, &info); + tcp_get_info(mpcb->master_sk, &info, true); if (copy_to_user((void __user *)m_info.initial, &info, info_len)) return -EFAULT; } else if (meta_tp->record_master_info && mpcb->master_info) { @@ -2741,7 +2741,7 @@ int mptcp_get_info(const struct sock *meta_sk, char __user *optval, int optlen) struct tcp_info t_info; unsigned int tmp_len; - tcp_get_info(mptcp_to_sock(mptcp), &t_info); + tcp_get_info(mptcp_to_sock(mptcp), &t_info, true); tmp_len = min_t(unsigned int, len, info_len); len -= tmp_len;