Re: [PATCH] net/ceph/messenger: print TCP connect error
From: Ilya Dryomov
Date: Mon Nov 02 2026 - 17:39:20 EST
On Thu, Sep 10, 2026 at 2:39 PM Max Kellermann <max.kellermann@xxxxxxxxx> wrote:
>
> A non-blocking connect() usually returns `-EINPROGRESS` and fails
> later, asynchronously; the actual error is then only visible as
> `sk->sk_err` in the sk_state_change() callback and was silently
> dropped. All the user got was:
>
> libceph: mon4 (1)192.168.1.42:6789 socket closed (con state V1_BANNER)
>
> Save the error in the new field `ceph_connection.error_code` and let
> con_fault() print it next to `error_msg`:
Hi Max,
I wonder if saving the error that way is actually needed. Can
con_fault() just reap it with sock_error() at the time it runs?
Thanks,
Ilya
>
> libceph: mon4 (1)192.168.1.42:6789 socket closed (con state V1_BANNER) (-ECONNREFUSED)
>
> Signed-off-by: Max Kellermann <max.kellermann@xxxxxxxxx>
> ---
> include/linux/ceph/messenger.h | 1 +
> net/ceph/messenger.c | 23 ++++++++++++++++++-----
> 2 files changed, 19 insertions(+), 5 deletions(-)
>
> diff --git a/include/linux/ceph/messenger.h b/include/linux/ceph/messenger.h
> index 6aa4c6478c9f..f3aa977d7886 100644
> --- a/include/linux/ceph/messenger.h
> +++ b/include/linux/ceph/messenger.h
> @@ -482,6 +482,7 @@ struct ceph_connection {
>
> unsigned long flags; /* CEPH_CON_F_* */
> const char *error_msg; /* error message, if any */
> + int error_code; /* errno (negative), if any */
>
> struct ceph_entity_name peer_name; /* peer name */
> struct ceph_entity_addr peer_addr; /* peer address */
> diff --git a/net/ceph/messenger.c b/net/ceph/messenger.c
> index 212e7797f9e4..f989e043686d 100644
> --- a/net/ceph/messenger.c
> +++ b/net/ceph/messenger.c
> @@ -398,6 +398,7 @@ static void ceph_sock_state_change(struct sock *sk)
> case TCP_CLOSE_WAIT:
> dout("%s TCP_CLOSE_WAIT\n", __func__);
> con_sock_state_closing(con);
> + WRITE_ONCE(con->error_code, -READ_ONCE(sk->sk_err));
> ceph_con_flag_set(con, CEPH_CON_F_SOCK_CLOSED);
> queue_con(con);
> break;
> @@ -448,8 +449,10 @@ int ceph_tcp_connect(struct ceph_connection *con)
> ret = sock_create_kern(read_pnet(&con->msgr->net), ss.ss_family,
> SOCK_STREAM, IPPROTO_TCP, &sock);
> memalloc_noio_restore(noio_flag);
> - if (ret)
> + if (ret) {
> + con->error_code = ret;
> return ret;
> + }
> sock->sk->sk_allocation = GFP_NOFS;
> sock->sk->sk_use_task_frag = false;
>
> @@ -467,9 +470,9 @@ int ceph_tcp_connect(struct ceph_connection *con)
> ceph_pr_addr(&con->peer_addr),
> sock->sk->sk_state);
> } else if (ret < 0) {
> - pr_err("connect %s error %d\n",
> - ceph_pr_addr(&con->peer_addr), ret);
> sock_release(sock);
> + /* reported by con_fault() */
> + con->error_code = ret;
> return ret;
> }
>
> @@ -501,6 +504,7 @@ int ceph_con_close_socket(struct ceph_connection *con)
> * shut the socket down.
> */
> ceph_con_flag_clear(con, CEPH_CON_F_SOCK_CLOSED);
> + con->error_code = 0;
>
> con_sock_state_closed(con);
> return rc;
> @@ -1613,12 +1617,21 @@ static void ceph_con_workfn(struct work_struct *work)
> */
> static void con_fault(struct ceph_connection *con)
> {
> + int error_code;
> +
> dout("fault %p state %d to peer %s\n",
> con, con->state, ceph_pr_addr(&con->peer_addr));
>
> - pr_warn("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
> - ceph_pr_addr(&con->peer_addr), con->error_msg);
> + error_code = READ_ONCE(con->error_code);
> + if (error_code)
> + pr_warn("%s%lld %s %s (%pe)\n", ENTITY_NAME(con->peer_name),
> + ceph_pr_addr(&con->peer_addr), con->error_msg,
> + ERR_PTR(error_code));
> + else
> + pr_warn("%s%lld %s %s\n", ENTITY_NAME(con->peer_name),
> + ceph_pr_addr(&con->peer_addr), con->error_msg);
> con->error_msg = NULL;
> + con->error_code = 0;
>
> WARN_ON(con->state == CEPH_CON_S_STANDBY ||
> con->state == CEPH_CON_S_CLOSED);
> --
> 2.47.3
>