]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
SUNRPC: Teach server to use xprt_sock_sendmsg for socket sends
authorChuck Lever <chuck.lever@oracle.com>
Mon, 2 Mar 2020 20:20:33 +0000 (15:20 -0500)
committerChuck Lever <chuck.lever@oracle.com>
Mon, 16 Mar 2020 16:04:33 +0000 (12:04 -0400)
xprt_sock_sendmsg uses the more efficient iov_iter-enabled kernel
socket API, and is a pre-requisite for server send-side support for
TLS.

Note that svc_process no longer needs to reserve a word for the
stream record marker, since the TCP transport now provides the
record marker automatically in a separate buffer.

The dprintk() in svc_send_common is also removed. It didn't seem
crucial for field troubleshooting. If more is needed there, a trace
point could be added in xprt_sock_sendmsg().

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
net/sunrpc/sunrpc.h
net/sunrpc/svc.c
net/sunrpc/svcsock.c
net/sunrpc/xprtsock.c

index c9bacb3c930fa7feeb4fdb110cdfc8e3ee0c177a..47a756503d11c2dba51d5ef4f966b73c3ea22082 100644 (file)
@@ -50,10 +50,6 @@ static inline int sock_is_loopback(struct sock *sk)
        return loopback;
 }
 
-int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
-                   struct page *headpage, unsigned long headoffset,
-                   struct page *tailpage, unsigned long tailoffset);
-
 int rpc_clients_notifier_register(void);
 void rpc_clients_notifier_unregister(void);
 #endif /* _NET_SUNRPC_SUNRPC_H */
index 18676d36f49097390c7ae712ac8bbf8b13edc0a9..9ed3126600ce8b43d623f5b670bc96a70ff758eb 100644 (file)
@@ -1529,10 +1529,6 @@ svc_process(struct svc_rqst *rqstp)
                goto out_drop;
        }
 
-       /* Reserve space for the record marker */
-       if (rqstp->rq_prot == IPPROTO_TCP)
-               svc_putnl(resv, 0);
-
        /* Returns 1 for send, 0 for drop */
        if (likely(svc_process_common(rqstp, argv, resv)))
                return svc_send(rqstp);
index 1cc5c224392b2b92c268d9ad8b321601eb43b7d2..519cf9c4f8fd8bf46539c8b0ddca293838fde26a 100644 (file)
@@ -175,111 +175,6 @@ static void svc_set_cmsg_data(struct svc_rqst *rqstp, struct cmsghdr *cmh)
        }
 }
 
-/*
- * send routine intended to be shared by the fore- and back-channel
- */
-int svc_send_common(struct socket *sock, struct xdr_buf *xdr,
-                   struct page *headpage, unsigned long headoffset,
-                   struct page *tailpage, unsigned long tailoffset)
-{
-       int             result;
-       int             size;
-       struct page     **ppage = xdr->pages;
-       size_t          base = xdr->page_base;
-       unsigned int    pglen = xdr->page_len;
-       unsigned int    flags = MSG_MORE | MSG_SENDPAGE_NOTLAST;
-       int             slen;
-       int             len = 0;
-
-       slen = xdr->len;
-
-       /* send head */
-       if (slen == xdr->head[0].iov_len)
-               flags = 0;
-       len = kernel_sendpage(sock, headpage, headoffset,
-                                 xdr->head[0].iov_len, flags);
-       if (len != xdr->head[0].iov_len)
-               goto out;
-       slen -= xdr->head[0].iov_len;
-       if (slen == 0)
-               goto out;
-
-       /* send page data */
-       size = PAGE_SIZE - base < pglen ? PAGE_SIZE - base : pglen;
-       while (pglen > 0) {
-               if (slen == size)
-                       flags = 0;
-               result = kernel_sendpage(sock, *ppage, base, size, flags);
-               if (result > 0)
-                       len += result;
-               if (result != size)
-                       goto out;
-               slen -= size;
-               pglen -= size;
-               size = PAGE_SIZE < pglen ? PAGE_SIZE : pglen;
-               base = 0;
-               ppage++;
-       }
-
-       /* send tail */
-       if (xdr->tail[0].iov_len) {
-               result = kernel_sendpage(sock, tailpage, tailoffset,
-                                  xdr->tail[0].iov_len, 0);
-               if (result > 0)
-                       len += result;
-       }
-
-out:
-       return len;
-}
-
-
-/*
- * Generic sendto routine
- */
-static int svc_sendto(struct svc_rqst *rqstp, struct xdr_buf *xdr)
-{
-       struct svc_sock *svsk =
-               container_of(rqstp->rq_xprt, struct svc_sock, sk_xprt);
-       struct socket   *sock = svsk->sk_sock;
-       union {
-               struct cmsghdr  hdr;
-               long            all[SVC_PKTINFO_SPACE / sizeof(long)];
-       } buffer;
-       struct cmsghdr *cmh = &buffer.hdr;
-       int             len = 0;
-       unsigned long tailoff;
-       unsigned long headoff;
-       RPC_IFDEBUG(char buf[RPC_MAX_ADDRBUFLEN]);
-
-       if (rqstp->rq_prot == IPPROTO_UDP) {
-               struct msghdr msg = {
-                       .msg_name       = &rqstp->rq_addr,
-                       .msg_namelen    = rqstp->rq_addrlen,
-                       .msg_control    = cmh,
-                       .msg_controllen = sizeof(buffer),
-                       .msg_flags      = MSG_MORE,
-               };
-
-               svc_set_cmsg_data(rqstp, cmh);
-
-               if (sock_sendmsg(sock, &msg) < 0)
-                       goto out;
-       }
-
-       tailoff = ((unsigned long)xdr->tail[0].iov_base) & (PAGE_SIZE-1);
-       headoff = 0;
-       len = svc_send_common(sock, xdr, rqstp->rq_respages[0], headoff,
-                              rqstp->rq_respages[0], tailoff);
-
-out:
-       dprintk("svc: socket %p sendto([%p %zu... ], %d) = %d (addr %s)\n",
-               svsk, xdr->head[0].iov_base, xdr->head[0].iov_len,
-               xdr->len, len, svc_print_addr(rqstp, buf, sizeof(buf)));
-
-       return len;
-}
-
 static int svc_sock_read_payload(struct svc_rqst *rqstp, unsigned int offset,
                                 unsigned int length)
 {
@@ -607,17 +502,43 @@ out_free:
        return 0;
 }
 
-static int
-svc_udp_sendto(struct svc_rqst *rqstp)
+/**
+ * svc_udp_sendto - Send out a reply on a UDP socket
+ * @rqstp: completed svc_rqst
+ *
+ * Returns the number of bytes sent, or a negative errno.
+ */
+static int svc_udp_sendto(struct svc_rqst *rqstp)
 {
-       int             error;
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       struct xdr_buf *xdr = &rqstp->rq_res;
+       union {
+               struct cmsghdr  hdr;
+               long            all[SVC_PKTINFO_SPACE / sizeof(long)];
+       } buffer;
+       struct cmsghdr *cmh = &buffer.hdr;
+       struct msghdr msg = {
+               .msg_name       = &rqstp->rq_addr,
+               .msg_namelen    = rqstp->rq_addrlen,
+               .msg_control    = cmh,
+               .msg_controllen = sizeof(buffer),
+       };
+       unsigned int uninitialized_var(sent);
+       int err;
 
-       error = svc_sendto(rqstp, &rqstp->rq_res);
-       if (error == -ECONNREFUSED)
-               /* ICMP error on earlier request. */
-               error = svc_sendto(rqstp, &rqstp->rq_res);
+       svc_set_cmsg_data(rqstp, cmh);
 
-       return error;
+       err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
+       xdr_free_bvec(xdr);
+       if (err == -ECONNREFUSED) {
+               /* ICMP error on earlier request. */
+               err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, 0, &sent);
+               xdr_free_bvec(xdr);
+       }
+       if (err < 0)
+               return err;
+       return sent;
 }
 
 static int svc_udp_has_wspace(struct svc_xprt *xprt)
@@ -1136,35 +1057,39 @@ err_noclose:
        return 0;       /* record not complete */
 }
 
-/*
- * Send out data on TCP socket.
+/**
+ * svc_tcp_sendto - Send out a reply on a TCP socket
+ * @rqstp: completed svc_rqst
+ *
+ * Returns the number of bytes sent, or a negative errno.
  */
 static int svc_tcp_sendto(struct svc_rqst *rqstp)
 {
-       struct xdr_buf  *xbufp = &rqstp->rq_res;
-       int sent;
-       __be32 reclen;
+       struct svc_xprt *xprt = rqstp->rq_xprt;
+       struct svc_sock *svsk = container_of(xprt, struct svc_sock, sk_xprt);
+       struct xdr_buf *xdr = &rqstp->rq_res;
+       rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
+                                        (u32)xdr->len);
+       struct msghdr msg = {
+               .msg_flags      = 0,
+       };
+       unsigned int uninitialized_var(sent);
+       int err;
 
-       /* Set up the first element of the reply kvec.
-        * Any other kvecs that may be in use have been taken
-        * care of by the server implementation itself.
-        */
-       reclen = htonl(0x80000000|((xbufp->len ) - 4));
-       memcpy(xbufp->head[0].iov_base, &reclen, 4);
-
-       sent = svc_sendto(rqstp, &rqstp->rq_res);
-       if (sent != xbufp->len) {
-               printk(KERN_NOTICE
-                      "rpc-srv/tcp: %s: %s %d when sending %d bytes "
-                      "- shutting down socket\n",
-                      rqstp->rq_xprt->xpt_server->sv_name,
-                      (sent<0)?"got error":"sent only",
-                      sent, xbufp->len);
-               set_bit(XPT_CLOSE, &rqstp->rq_xprt->xpt_flags);
-               svc_xprt_enqueue(rqstp->rq_xprt);
-               sent = -EAGAIN;
-       }
+       err = xprt_sock_sendmsg(svsk->sk_sock, &msg, xdr, 0, marker, &sent);
+       xdr_free_bvec(xdr);
+       if (err < 0 || sent != (xdr->len + sizeof(marker)))
+               goto out_close;
        return sent;
+
+out_close:
+       pr_notice("rpc-srv/tcp: %s: %s %d when sending %d bytes - shutting down socket\n",
+                 xprt->xpt_server->sv_name,
+                 (err < 0) ? "got error" : "sent",
+                 (err < 0) ? err : sent, xdr->len);
+       set_bit(XPT_CLOSE, &xprt->xpt_flags);
+       svc_xprt_enqueue(xprt);
+       return -EAGAIN;
 }
 
 static struct svc_xprt *svc_tcp_create(struct svc_serv *serv,
index 1a7c0856c5b6e4be4452c1e7d76c195f07b0fd63..17cb902e5153ef3acb1d201372a7e806fc6f4296 100644 (file)
@@ -2527,46 +2527,25 @@ static void bc_free(struct rpc_task *task)
        free_page((unsigned long)buf);
 }
 
-/*
- * Use the svc_sock to send the callback. Must be called with svsk->sk_mutex
- * held. Borrows heavily from svc_tcp_sendto and xs_tcp_send_request.
- */
 static int bc_sendto(struct rpc_rqst *req)
 {
-       int len;
-       struct xdr_buf *xbufp = &req->rq_snd_buf;
+       struct xdr_buf *xdr = &req->rq_snd_buf;
        struct sock_xprt *transport =
                        container_of(req->rq_xprt, struct sock_xprt, xprt);
-       unsigned long headoff;
-       unsigned long tailoff;
-       struct page *tailpage;
        struct msghdr msg = {
-               .msg_flags      = MSG_MORE
+               .msg_flags      = 0,
        };
        rpc_fraghdr marker = cpu_to_be32(RPC_LAST_STREAM_FRAGMENT |
-                                        (u32)xbufp->len);
-       struct kvec iov = {
-               .iov_base       = &marker,
-               .iov_len        = sizeof(marker),
-       };
+                                        (u32)xdr->len);
+       unsigned int sent = 0;
+       int err;
 
        req->rq_xtime = ktime_get();
-
-       len = kernel_sendmsg(transport->sock, &msg, &iov, 1, iov.iov_len);
-       if (len != iov.iov_len)
+       err = xprt_sock_sendmsg(transport->sock, &msg, xdr, 0, marker, &sent);
+       xdr_free_bvec(xdr);
+       if (err < 0 || sent != (xdr->len + sizeof(marker)))
                return -EAGAIN;
-
-       tailpage = NULL;
-       if (xbufp->tail[0].iov_len)
-               tailpage = virt_to_page(xbufp->tail[0].iov_base);
-       tailoff = (unsigned long)xbufp->tail[0].iov_base & ~PAGE_MASK;
-       headoff = (unsigned long)xbufp->head[0].iov_base & ~PAGE_MASK;
-       len = svc_send_common(transport->sock, xbufp,
-                             virt_to_page(xbufp->head[0].iov_base), headoff,
-                             tailpage, tailoff);
-       if (len != xbufp->len)
-               return -EAGAIN;
-       return len;
+       return sent;
 }
 
 /*