void rds_connect_worker(struct work_struct *work) { struct rds_connection *conn = container_of(work, struct rds_connection, c_conn_w.work); int ret; clear_bit(RDS_RECONNECT_PENDING, &conn->c_flags); if (rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) { /* * record the time we started trying to connect so that we can * drop the connection if it doesn't work out after a while */ conn->c_connection_start = get_seconds(); ret = conn->c_trans->conn_connect(conn); rdsdebug("conn %p for %pI4 to %pI4 dispatched, ret %d\n", conn, &conn->c_laddr, &conn->c_faddr, ret); if (ret) { if (rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_DOWN)) { rds_queue_reconnect(conn); } else rds_conn_error(conn, "RDS: connect failed\n"); } } }
void rds_shutdown_worker(struct work_struct *work) { struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w); /* shut it down unless it's down already */ if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) { /* * Quiesce the connection mgmt handlers before we start tearing * things down. We don't hold the mutex for the entire * duration of the shutdown operation, else we may be * deadlocking with the CM handler. Instead, the CM event * handler is supposed to check for state DISCONNECTING */ mutex_lock(&conn->c_cm_lock); if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) { rds_conn_error(conn, "shutdown called in state %d\n", atomic_read(&conn->c_state)); mutex_unlock(&conn->c_cm_lock); return; } mutex_unlock(&conn->c_cm_lock); mutex_lock(&conn->c_send_lock); conn->c_trans->conn_shutdown(conn); rds_conn_reset(conn); mutex_unlock(&conn->c_send_lock); if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) { /* This can happen - eg when we're in the middle of tearing * down the connection, and someone unloads the rds module. * Quite reproduceable with loopback connections. * Mostly harmless. */ rds_conn_error(conn, "%s: failed to transition to state DOWN, " "current state is %d\n", __func__, atomic_read(&conn->c_state)); return; } } /* Then reconnect if it's still live. * The passive side of an IB loopback connection is never added * to the conn hash, so we never trigger a reconnect on this * conn - the reconnect is always triggered by the active peer. */ cancel_delayed_work(&conn->c_conn_w); if (!hlist_unhashed(&conn->c_hash_node)) rds_queue_reconnect(conn); }
void rds_connect_complete(struct rds_connection *conn) { if (!rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_UP)) { printk(KERN_WARNING "%s: Cannot transition to state UP" ", current state is %d\n", __func__, atomic_read(&conn->c_state)); atomic_set(&conn->c_state, RDS_CONN_ERROR); queue_work(rds_wq, &conn->c_down_w); return; } rdsdebug("conn %p for %pI4 to %pI4 complete\n", conn, &conn->c_laddr, &conn->c_faddr); conn->c_reconnect_jiffies = 0; set_bit(0, &conn->c_map_queued); queue_delayed_work(rds_wq, &conn->c_send_w, 0); queue_delayed_work(rds_wq, &conn->c_recv_w, 0); queue_delayed_work(rds_wq, &conn->c_hb_w, 0); conn->c_hb_start = 0; conn->c_connection_start = get_seconds(); conn->c_reconnect = 1; conn->c_committed_version = conn->c_version; conn->c_proposed_version = RDS_PROTOCOL_VERSION; }
static int rds_tcp_accept_one(struct socket *sock) { struct socket *new_sock = NULL; struct rds_connection *conn; int ret; struct inet_sock *inet; ret = sock_create_lite(sock->sk->sk_family, sock->sk->sk_type, sock->sk->sk_protocol, &new_sock); if (ret) goto out; new_sock->type = sock->type; new_sock->ops = sock->ops; ret = sock->ops->accept(sock, new_sock, O_NONBLOCK); if (ret < 0) goto out; rds_tcp_tune(new_sock); inet = inet_sk(new_sock->sk); rdsdebug("accepted tcp %pI4:%u -> %pI4:%u\n", &inet->inet_saddr, ntohs(inet->inet_sport), &inet->inet_daddr, ntohs(inet->inet_dport)); conn = rds_conn_create(inet->inet_saddr, inet->inet_daddr, &rds_tcp_transport, GFP_KERNEL); if (IS_ERR(conn)) { ret = PTR_ERR(conn); goto out; } /* * see the comment above rds_queue_delayed_reconnect() */ if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) { if (rds_conn_state(conn) == RDS_CONN_UP) rds_tcp_stats_inc(s_tcp_listen_closed_stale); else rds_tcp_stats_inc(s_tcp_connect_raced); rds_conn_drop(conn); ret = 0; goto out; } rds_tcp_set_callbacks(new_sock, conn); rds_connect_complete(conn); new_sock = NULL; ret = 0; out: if (new_sock) sock_release(new_sock); return ret; }
void rds_connect_worker(struct work_struct *work) { struct rds_connection *conn = container_of(work, struct rds_connection, c_conn_w.work); int ret; clear_bit(RDS_RECONNECT_PENDING, &conn->c_flags); if (rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) { ret = conn->c_trans->conn_connect(conn); rdsdebug("conn %p for %pI4 to %pI4 dispatched, ret %d\n", conn, &conn->c_laddr, &conn->c_faddr, ret); if (ret) { if (rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_DOWN)) rds_queue_reconnect(conn); else rds_conn_error(conn, "RDS: connect failed\n"); } } }
void rds_shutdown_worker(struct work_struct *work) { struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w); if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) { mutex_lock(&conn->c_cm_lock); if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING) && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) { rds_conn_error(conn, "shutdown called in state %d\n", atomic_read(&conn->c_state)); mutex_unlock(&conn->c_cm_lock); return; } mutex_unlock(&conn->c_cm_lock); mutex_lock(&conn->c_send_lock); conn->c_trans->conn_shutdown(conn); rds_conn_reset(conn); mutex_unlock(&conn->c_send_lock); if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) { rds_conn_error(conn, "%s: failed to transition to state DOWN, " "current state is %d\n", __func__, atomic_read(&conn->c_state)); return; } } cancel_delayed_work(&conn->c_conn_w); if (!hlist_unhashed(&conn->c_hash_node)) rds_queue_reconnect(conn); }
void rds_connect_complete(struct rds_connection *conn) { if (!rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_UP)) { printk(KERN_WARNING "%s: Cannot transition to state UP, " "current state is %d\n", __func__, atomic_read(&conn->c_state)); atomic_set(&conn->c_state, RDS_CONN_ERROR); queue_work(rds_wq, &conn->c_down_w); return; } rdsdebug("conn %p for %pI4 to %pI4 complete\n", conn, &conn->c_laddr, &conn->c_faddr); conn->c_reconnect_jiffies = 0; set_bit(0, &conn->c_map_queued); queue_delayed_work(rds_wq, &conn->c_send_w, 0); queue_delayed_work(rds_wq, &conn->c_recv_w, 0); }
int rds_tcp_accept_one(struct socket *sock) { struct socket *new_sock = NULL; struct rds_connection *conn; int ret; struct inet_sock *inet; struct rds_tcp_connection *rs_tcp; ret = sock_create_kern(sock_net(sock->sk), sock->sk->sk_family, sock->sk->sk_type, sock->sk->sk_protocol, &new_sock); if (ret) goto out; new_sock->type = sock->type; new_sock->ops = sock->ops; ret = sock->ops->accept(sock, new_sock, O_NONBLOCK); if (ret < 0) goto out; ret = rds_tcp_keepalive(new_sock); if (ret < 0) goto out; rds_tcp_tune(new_sock); inet = inet_sk(new_sock->sk); rdsdebug("accepted tcp %pI4:%u -> %pI4:%u\n", &inet->inet_saddr, ntohs(inet->inet_sport), &inet->inet_daddr, ntohs(inet->inet_dport)); conn = rds_conn_create(sock_net(sock->sk), inet->inet_saddr, inet->inet_daddr, &rds_tcp_transport, GFP_KERNEL); if (IS_ERR(conn)) { ret = PTR_ERR(conn); goto out; } /* An incoming SYN request came in, and TCP just accepted it. * * If the client reboots, this conn will need to be cleaned up. * rds_tcp_state_change() will do that cleanup */ rs_tcp = (struct rds_tcp_connection *)conn->c_transport_data; if (rs_tcp->t_sock && ntohl(inet->inet_saddr) < ntohl(inet->inet_daddr)) { struct sock *nsk = new_sock->sk; nsk->sk_user_data = NULL; nsk->sk_prot->disconnect(nsk, 0); tcp_done(nsk); new_sock = NULL; ret = 0; goto out; } else if (rs_tcp->t_sock) { rds_tcp_restore_callbacks(rs_tcp->t_sock, rs_tcp); conn->c_outgoing = 0; } rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING); rds_tcp_set_callbacks(new_sock, conn); rds_connect_complete(conn); new_sock = NULL; ret = 0; out: if (new_sock) sock_release(new_sock); return ret; }