Commit a5cda73e authored by Chuck Lever's avatar Chuck Lever
Browse files

SUNRPC: Restructure svc_tcp_recv_record()



Refactor: svc_recvfrom() is going to be converted to read into
bio_vecs in a moment. Unhook the only other caller,
svc_tcp_recv_record(), which just wants to read the 4-byte stream
record marker into a kvec.

While we're in the area, streamline this helper by straight-lining
the hot path, replace dprintk call sites with tracepoints, and
reduce the number of atomic bit operations in this path.

Signed-off-by: default avatarChuck Lever <chuck.lever@oracle.com>
parent 02648908
Loading
Loading
Loading
Loading
+24 −0
Original line number Diff line number Diff line
@@ -1443,6 +1443,30 @@ TRACE_EVENT(svcsock_new_socket,
	)
);

TRACE_EVENT(svcsock_marker,
	TP_PROTO(
		const struct svc_xprt *xprt,
		__be32 marker
	),

	TP_ARGS(xprt, marker),

	TP_STRUCT__entry(
		__field(unsigned int, length)
		__field(bool, last)
		__string(addr, xprt->xpt_remotebuf)
	),

	TP_fast_assign(
		__entry->length = be32_to_cpu(marker) & RPC_FRAGMENT_SIZE_MASK;
		__entry->last = be32_to_cpu(marker) & RPC_LAST_STREAM_FRAGMENT;
		__assign_str(addr, xprt->xpt_remotebuf);
	),

	TP_printk("addr=%s length=%u%s", __get_str(addr),
		__entry->length, __entry->last ? " (last)" : "")
);

DECLARE_EVENT_CLASS(svcsock_class,
	TP_PROTO(
		const struct svc_xprt *xprt,
+25 −26
Original line number Diff line number Diff line
@@ -828,47 +828,45 @@ static void svc_tcp_clear_pages(struct svc_sock *svsk)
}

/*
 * Receive fragment record header.
 * If we haven't gotten the record length yet, get the next four bytes.
 * Receive fragment record header into sk_marker.
 */
static int svc_tcp_recv_record(struct svc_sock *svsk, struct svc_rqst *rqstp)
static ssize_t svc_tcp_read_marker(struct svc_sock *svsk,
				   struct svc_rqst *rqstp)
{
	struct svc_serv	*serv = svsk->sk_xprt.xpt_server;
	unsigned int want;
	int len;
	ssize_t want, len;

	/* If we haven't gotten the record length yet,
	 * get the next four bytes.
	 */
	if (svsk->sk_tcplen < sizeof(rpc_fraghdr)) {
		struct msghdr	msg = { NULL };
		struct kvec	iov;

		want = sizeof(rpc_fraghdr) - svsk->sk_tcplen;
		iov.iov_base = ((char *)&svsk->sk_marker) + svsk->sk_tcplen;
		iov.iov_len  = want;
		len = svc_recvfrom(rqstp, &iov, 1, want, 0);
		iov_iter_kvec(&msg.msg_iter, READ, &iov, 1, want);
		len = sock_recvmsg(svsk->sk_sock, &msg, MSG_DONTWAIT);
		if (len < 0)
			goto error;
			return len;
		svsk->sk_tcplen += len;

		if (len < want) {
			dprintk("svc: short recvfrom while reading record "
				"length (%d of %d)\n", len, want);
			return -EAGAIN;
			/* call again to read the remaining bytes */
			goto err_short;
		}

		dprintk("svc: TCP record, %d bytes\n", svc_sock_reclen(svsk));
		trace_svcsock_marker(&svsk->sk_xprt, svsk->sk_marker);
		if (svc_sock_reclen(svsk) + svsk->sk_datalen >
							serv->sv_max_mesg) {
			net_notice_ratelimited("RPC: fragment too large: %d\n",
					svc_sock_reclen(svsk));
			goto err_delete;
		}
		    svsk->sk_xprt.xpt_server->sv_max_mesg)
			goto err_too_large;
	}

	return svc_sock_reclen(svsk);
error:
	dprintk("RPC: TCP recv_record got %d\n", len);
	return len;
err_delete:

err_too_large:
	net_notice_ratelimited("svc: %s %s RPC fragment too large: %d\n",
			       __func__, svsk->sk_xprt.xpt_server->sv_name,
			       svc_sock_reclen(svsk));
	set_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags);
err_short:
	return -EAGAIN;
}

@@ -961,12 +959,13 @@ static int svc_tcp_recvfrom(struct svc_rqst *rqstp)
		test_bit(XPT_CONN, &svsk->sk_xprt.xpt_flags),
		test_bit(XPT_CLOSE, &svsk->sk_xprt.xpt_flags));

	len = svc_tcp_recv_record(svsk, rqstp);
	clear_bit(XPT_DATA, &svsk->sk_xprt.xpt_flags);
	len = svc_tcp_read_marker(svsk, rqstp);
	if (len < 0)
		goto error;

	base = svc_tcp_restore_pages(svsk, rqstp);
	want = svc_sock_reclen(svsk) - (svsk->sk_tcplen - sizeof(rpc_fraghdr));
	want = len - (svsk->sk_tcplen - sizeof(rpc_fraghdr));

	vec = rqstp->rq_vec;