Beispiel #1
0
/*
 * 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;
}
Beispiel #2
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));
	}
}