net/rds/tcp_recv.c

Source file repositories/reference/linux-study-clean/net/rds/tcp_recv.c

File Facts

System
Linux kernel
Corpus path
net/rds/tcp_recv.c
Extension
.c
Size
9524 bytes
Lines
354
Domain
Networking Core
Bucket
Sockets, Protocols, Packet Path, And Network Policy
Inferred role
Networking Core: implementation source
Status
source implementation candidate

Why This File Exists

Networking stack implementation surface: socket APIs, protocol dispatch, packet flow, routing, filtering, and network namespaces.

Dependency Surface

Detected Declarations

Annotated Snippet

struct rds_tcp_desc_arg {
	struct rds_conn_path *conn_path;
	gfp_t gfp;
};

static int rds_tcp_data_recv(read_descriptor_t *desc, struct sk_buff *skb,
			     unsigned int offset, size_t len)
{
	struct rds_tcp_desc_arg *arg = desc->arg.data;
	struct rds_conn_path *cp = arg->conn_path;
	struct rds_tcp_connection *tc = cp->cp_transport_data;
	struct rds_tcp_incoming *tinc = tc->t_tinc;
	struct sk_buff *clone;
	size_t left = len, to_copy;

	rdsdebug("tcp data tc %p skb %p offset %u len %zu\n", tc, skb, offset,
		 len);

	/*
	 * tcp_read_sock() interprets partial progress as an indication to stop
	 * processing.
	 */
	while (left) {
		if (!tinc) {
			tinc = kmem_cache_alloc(rds_tcp_incoming_slab,
						arg->gfp);
			if (!tinc) {
				desc->error = -ENOMEM;
				goto out;
			}
			tc->t_tinc = tinc;
			rdsdebug("allocated tinc %p\n", tinc);
			rds_inc_path_init(&tinc->ti_inc, cp,
					  &cp->cp_conn->c_faddr);
			tinc->ti_inc.i_rx_lat_trace[RDS_MSG_RX_HDR] =
					local_clock();

			/*
			 * XXX * we might be able to use the __ variants when
			 * we've already serialized at a higher level.
			 */
			skb_queue_head_init(&tinc->ti_skb_list);
		}

		if (left && tc->t_tinc_hdr_rem) {
			to_copy = min(tc->t_tinc_hdr_rem, left);
			rdsdebug("copying %zu header from skb %p\n", to_copy,
				 skb);
			skb_copy_bits(skb, offset,
				      (char *)&tinc->ti_inc.i_hdr +
						sizeof(struct rds_header) -
						tc->t_tinc_hdr_rem,
				      to_copy);
			tc->t_tinc_hdr_rem -= to_copy;
			left -= to_copy;
			offset += to_copy;

			if (tc->t_tinc_hdr_rem == 0) {
				/* could be 0 for a 0 len message */
				tc->t_tinc_data_rem =
					be32_to_cpu(tinc->ti_inc.i_hdr.h_len);
				tinc->ti_inc.i_rx_lat_trace[RDS_MSG_RX_START] =
					local_clock();
			}
		}

		if (left && tc->t_tinc_data_rem) {
			to_copy = min(tc->t_tinc_data_rem, left);

			clone = pskb_extract(skb, offset, to_copy, arg->gfp);
			if (!clone) {
				desc->error = -ENOMEM;
				goto out;
			}

			skb_queue_tail(&tinc->ti_skb_list, clone);

			rdsdebug("skb %p data %p len %d off %u to_copy %zu -> "
				 "clone %p data %p len %d\n",
				 skb, skb->data, skb->len, offset, to_copy,
				 clone, clone->data, clone->len);

			tc->t_tinc_data_rem -= to_copy;
			left -= to_copy;
			offset += to_copy;
		}

		if (tc->t_tinc_hdr_rem == 0 && tc->t_tinc_data_rem == 0) {
			struct rds_connection *conn = cp->cp_conn;

Annotation

Implementation Notes