/* * Before killing the tcp socket this needs to serialize with callbacks. The * caller has already grabbed the sending sem so we're serialized with other * senders. * * TCP calls the callbacks with the sock lock so we hold it while we reset the * callbacks to those set by TCP. Our callbacks won't execute again once we * hold the sock lock. */ void rds_tcp_conn_path_shutdown(struct rds_conn_path *cp) { struct rds_tcp_connection *tc = cp->cp_transport_data; struct socket *sock = tc->t_sock; rdsdebug("shutting down conn %p tc %p sock %p\n", cp->cp_conn, tc, sock); if (sock) { if (rds_destroy_pending(cp->cp_conn)) rds_tcp_set_linger(sock); sock->ops->shutdown(sock, RCV_SHUTDOWN | SEND_SHUTDOWN); lock_sock(sock->sk); rds_tcp_restore_callbacks(sock, tc); /* tc->tc_sock = NULL */ release_sock(sock->sk); sock_release(sock); } if (tc->t_tinc) { rds_inc_put(&tc->t_tinc->ti_inc); tc->t_tinc = NULL; } tc->t_tinc_hdr_rem = sizeof(struct rds_header); tc->t_tinc_data_rem = 0; }
/* * The transport must make sure that this is serialized against other * rx and conn reset on this specific conn. * * We currently assert that only one fragmented message will be sent * down a connection at a time. This lets us reassemble in the conn * instead of per-flow which means that we don't have to go digging through * flows to tear down partial reassembly progress on conn failure and * we save flow lookup and locking for each frag arrival. It does mean * that small messages will wait behind large ones. Fragmenting at all * is only to reduce the memory consumption of pre-posted buffers. * * The caller passes in saddr and daddr instead of us getting it from the * conn. This lets loopback, who only has one conn for both directions, * tell us which roles the addrs in the conn are playing for this message. */ void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr, struct rds_incoming *inc, gfp_t gfp) { struct sk_buff *skb; struct rds_sock *rs; struct sock *sk; struct rds_nf_hdr *dst, *org; int ret; rdsdebug(KERN_ALERT "incoming: conn %p, inc %p, %u.%u.%u.%u : %d -> %u.%u.%u.%u : %d\n", conn, inc, NIPQUAD(saddr), inc->i_hdr.h_sport, NIPQUAD(daddr), inc->i_hdr.h_dport); /* initialize some globals */ rs = NULL; sk = NULL; /* save off the original connection against which the request arrived */ inc->i_oconn = conn; inc->i_skb = NULL; /* lets find a socket to which this request belongs */ rs = rds_find_bound(daddr, inc->i_hdr.h_dport); /* pass it on locally if there is no socket bound, or if netfilter is * disabled for this socket */ if (NULL == rs || !rs->rs_netfilter_enabled) { /* drop the reference if we had taken one */ if (NULL != rs) rds_sock_put(rs); rds_recv_local(conn, saddr, daddr, inc, gfp); return; } /* otherwise pull out the socket */ sk = rds_rs_to_sk(rs); /* create an skb with some additional space to store our rds_nf_hdr info */ skb = alloc_skb(sizeof(struct rds_nf_hdr) * 2, gfp); if (NULL == skb) { /* if we have allocation problems, then we just need to depart */ rdsdebug("failure to allocate space for inc %p, %u.%u.%u.%u -> %u.%d.%u.%u\n", inc, NIPQUAD(saddr), NIPQUAD(daddr)); rds_recv_local(conn, saddr, daddr, inc, gfp); return; } /* once we've allocated an skb, also store it in our structures */ inc->i_skb = skb; /* now pull out the rds headers */ dst = rds_nf_hdr_dst(skb); org = rds_nf_hdr_org(skb); /* now update our rds_nf_hdr for tracking locations of the request */ dst->saddr = saddr; dst->daddr = daddr; dst->sport = inc->i_hdr.h_sport; dst->dport = inc->i_hdr.h_dport; dst->flags = 0; /* assign the appropriate protocol if any */ if (NULL != sk) { dst->protocol = sk->sk_protocol; dst->sk = sk; } else { dst->protocol = 0; dst->sk = NULL; } /* cleanup any references taken */ if (NULL != rs) rds_sock_put(rs); /* the original info is just a copy */ memcpy(org, dst, sizeof(struct rds_nf_hdr)); /* convert our local data structures in the message to a generalized skb form */ if (conn->c_trans->inc_to_skb(inc, skb)) { rdsdebug("handing off to PRE_ROUTING hook\n"); /* call down through the hook layers */ ret = NF_HOOK(PF_RDS_HOOK, NF_RDS_PRE_ROUTING, skb, NULL, NULL, rds_recv_ok); } /* if we had a failure to convert, then just assuming to continue as local */ else { rdsdebug("failed to create skb form, conn %p, inc %p, %u.%u.%u.%u -> %u.%u.%u.%u\n", conn, inc, NIPQUAD(saddr), NIPQUAD(daddr)); ret = 1; } /* pull back out the rds headers */ dst = rds_nf_hdr_dst(skb); org = rds_nf_hdr_org(skb); /* now depending upon we got back we can perform appropriate activities */ if (dst->flags & RDS_NF_HDR_FLAG_DONE) { rds_recv_drop(conn, saddr, daddr, inc, gfp); } /* this is the normal good processed state */ else if (ret >= 0) { /* check the original header and if changed do the needful */ if (dst->saddr == org->saddr && dst->daddr == org->daddr && conn->c_trans->skb_local(skb)) { rds_recv_local(conn, saddr, daddr, inc, gfp); } /* the send both case does both a local recv and a reroute */ else if (dst->flags & RDS_NF_HDR_FLAG_BOTH) { /* we must be sure to take an extra reference on the inc * to be sure it doesn't accidentally get freed in between */ rds_inc_addref(inc); /* send it up the stream locally */ rds_recv_local(conn, saddr, daddr, inc, gfp); /* and also reroute the request */ rds_recv_route(conn, inc, gfp); /* since we are done with processing we can drop this additional reference */ rds_inc_put(inc); } /* anything else is a change in possible destination so pass to route */ else rds_recv_route(conn, inc, gfp); } /* we don't really expect an error state from this call that isn't the done above */ else { /* we don't really know how to handle this yet - just ignore for now */ printk(KERN_ERR "unacceptible state for skb ret %d, conn %p, inc %p, " "%u.%u.%u.%u -> %u.%u.%u.%u\n", ret, conn, inc, NIPQUAD(saddr), NIPQUAD(daddr)); } }