OSDN Git Service

SUNRPC: Restructure svc_tcp_recv_record()
authorChuck Lever <chuck.lever@oracle.com>
Mon, 16 Mar 2020 18:53:04 +0000 (14:53 -0400)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 18 May 2020 14:21:23 +0000 (10:21 -0400)
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: Chuck Lever <chuck.lever@oracle.com>
include/trace/events/sunrpc.h
net/sunrpc/svcsock.c

index 6d85bbb..ec4ae34 100644 (file)
@@ -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,
index d63b21f..9c1eb13 100644 (file)
@@ -828,47 +828,45 @@ out:
 }
 
 /*
- * 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;