diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2014-12-10 15:51:28 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2015-02-04 01:34:16 -0500 |
commit | ba7438aed924133df54a60e4cd5499d359bcf2a8 (patch) | |
tree | e29c9a26421611c374667b022c9904ab527c496f /drivers/vhost | |
parent | 98a527aac1eb198dbc4405b800e102563ed8e4dd (diff) |
vhost: don't bother copying iovecs in handle_rx(), kill memcpy_toiovecend()
Cc: Michael S. Tsirkin <mst@redhat.com>
Cc: kvm@vger.kernel.org
Cc: virtualization@lists.linux-foundation.org
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'drivers/vhost')
-rw-r--r-- | drivers/vhost/net.c | 82 |
1 files changed, 23 insertions, 59 deletions
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c index d86cc9bb9ea4..e022cc40303d 100644 --- a/drivers/vhost/net.c +++ b/drivers/vhost/net.c | |||
@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref { | |||
84 | 84 | ||
85 | struct vhost_net_virtqueue { | 85 | struct vhost_net_virtqueue { |
86 | struct vhost_virtqueue vq; | 86 | struct vhost_virtqueue vq; |
87 | /* hdr is used to store the virtio header. | ||
88 | * Since each iovec has >= 1 byte length, we never need more than | ||
89 | * header length entries to store the header. */ | ||
90 | struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)]; | ||
91 | size_t vhost_hlen; | 87 | size_t vhost_hlen; |
92 | size_t sock_hlen; | 88 | size_t sock_hlen; |
93 | /* vhost zerocopy support fields below: */ | 89 | /* vhost zerocopy support fields below: */ |
@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock) | |||
235 | sock_flag(sock->sk, SOCK_ZEROCOPY); | 231 | sock_flag(sock->sk, SOCK_ZEROCOPY); |
236 | } | 232 | } |
237 | 233 | ||
238 | /* Pop first len bytes from iovec. Return number of segments used. */ | ||
239 | static int move_iovec_hdr(struct iovec *from, struct iovec *to, | ||
240 | size_t len, int iov_count) | ||
241 | { | ||
242 | int seg = 0; | ||
243 | size_t size; | ||
244 | |||
245 | while (len && seg < iov_count) { | ||
246 | size = min(from->iov_len, len); | ||
247 | to->iov_base = from->iov_base; | ||
248 | to->iov_len = size; | ||
249 | from->iov_len -= size; | ||
250 | from->iov_base += size; | ||
251 | len -= size; | ||
252 | ++from; | ||
253 | ++to; | ||
254 | ++seg; | ||
255 | } | ||
256 | return seg; | ||
257 | } | ||
258 | /* Copy iovec entries for len bytes from iovec. */ | ||
259 | static void copy_iovec_hdr(const struct iovec *from, struct iovec *to, | ||
260 | size_t len, int iovcount) | ||
261 | { | ||
262 | int seg = 0; | ||
263 | size_t size; | ||
264 | |||
265 | while (len && seg < iovcount) { | ||
266 | size = min(from->iov_len, len); | ||
267 | to->iov_base = from->iov_base; | ||
268 | to->iov_len = size; | ||
269 | len -= size; | ||
270 | ++from; | ||
271 | ++to; | ||
272 | ++seg; | ||
273 | } | ||
274 | } | ||
275 | |||
276 | /* In case of DMA done not in order in lower device driver for some reason. | 234 | /* In case of DMA done not in order in lower device driver for some reason. |
277 | * upend_idx is used to track end of used idx, done_idx is used to track head | 235 | * upend_idx is used to track end of used idx, done_idx is used to track head |
278 | * of used idx. Once lower device DMA done contiguously, we will signal KVM | 236 | * of used idx. Once lower device DMA done contiguously, we will signal KVM |
@@ -570,9 +528,9 @@ static void handle_rx(struct vhost_net *net) | |||
570 | .msg_controllen = 0, | 528 | .msg_controllen = 0, |
571 | .msg_flags = MSG_DONTWAIT, | 529 | .msg_flags = MSG_DONTWAIT, |
572 | }; | 530 | }; |
573 | struct virtio_net_hdr_mrg_rxbuf hdr = { | 531 | struct virtio_net_hdr hdr = { |
574 | .hdr.flags = 0, | 532 | .flags = 0, |
575 | .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE | 533 | .gso_type = VIRTIO_NET_HDR_GSO_NONE |
576 | }; | 534 | }; |
577 | size_t total_len = 0; | 535 | size_t total_len = 0; |
578 | int err, mergeable; | 536 | int err, mergeable; |
@@ -580,6 +538,7 @@ static void handle_rx(struct vhost_net *net) | |||
580 | size_t vhost_hlen, sock_hlen; | 538 | size_t vhost_hlen, sock_hlen; |
581 | size_t vhost_len, sock_len; | 539 | size_t vhost_len, sock_len; |
582 | struct socket *sock; | 540 | struct socket *sock; |
541 | struct iov_iter fixup; | ||
583 | 542 | ||
584 | mutex_lock(&vq->mutex); | 543 | mutex_lock(&vq->mutex); |
585 | sock = vq->private_data; | 544 | sock = vq->private_data; |
@@ -624,14 +583,19 @@ static void handle_rx(struct vhost_net *net) | |||
624 | break; | 583 | break; |
625 | } | 584 | } |
626 | /* We don't need to be notified again. */ | 585 | /* We don't need to be notified again. */ |
627 | if (unlikely((vhost_hlen))) | 586 | iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len); |
628 | /* Skip header. TODO: support TSO. */ | 587 | fixup = msg.msg_iter; |
629 | move_iovec_hdr(vq->iov, nvq->hdr, vhost_hlen, in); | 588 | if (unlikely((vhost_hlen))) { |
630 | else | 589 | /* We will supply the header ourselves |
631 | /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF: | 590 | * TODO: support TSO. |
632 | * needed because recvmsg can modify msg_iov. */ | 591 | */ |
633 | copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in); | 592 | iov_iter_advance(&msg.msg_iter, vhost_hlen); |
634 | iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len); | 593 | } else { |
594 | /* It'll come from socket; we'll need to patch | ||
595 | * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF | ||
596 | */ | ||
597 | iov_iter_advance(&fixup, sizeof(hdr)); | ||
598 | } | ||
635 | err = sock->ops->recvmsg(NULL, sock, &msg, | 599 | err = sock->ops->recvmsg(NULL, sock, &msg, |
636 | sock_len, MSG_DONTWAIT | MSG_TRUNC); | 600 | sock_len, MSG_DONTWAIT | MSG_TRUNC); |
637 | /* Userspace might have consumed the packet meanwhile: | 601 | /* Userspace might have consumed the packet meanwhile: |
@@ -643,18 +607,18 @@ static void handle_rx(struct vhost_net *net) | |||
643 | vhost_discard_vq_desc(vq, headcount); | 607 | vhost_discard_vq_desc(vq, headcount); |
644 | continue; | 608 | continue; |
645 | } | 609 | } |
610 | /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */ | ||
646 | if (unlikely(vhost_hlen) && | 611 | if (unlikely(vhost_hlen) && |
647 | memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0, | 612 | copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) { |
648 | vhost_hlen)) { | ||
649 | vq_err(vq, "Unable to write vnet_hdr at addr %p\n", | 613 | vq_err(vq, "Unable to write vnet_hdr at addr %p\n", |
650 | vq->iov->iov_base); | 614 | vq->iov->iov_base); |
651 | break; | 615 | break; |
652 | } | 616 | } |
653 | /* TODO: Should check and handle checksum. */ | 617 | /* Supply (or replace) ->num_buffers if VIRTIO_NET_F_MRG_RXBUF |
618 | * TODO: Should check and handle checksum. | ||
619 | */ | ||
654 | if (likely(mergeable) && | 620 | if (likely(mergeable) && |
655 | memcpy_toiovecend(nvq->hdr, (unsigned char *)&headcount, | 621 | copy_to_iter(&headcount, 2, &fixup) != 2) { |
656 | offsetof(typeof(hdr), num_buffers), | ||
657 | sizeof hdr.num_buffers)) { | ||
658 | vq_err(vq, "Failed num_buffers write"); | 622 | vq_err(vq, "Failed num_buffers write"); |
659 | vhost_discard_vq_desc(vq, headcount); | 623 | vhost_discard_vq_desc(vq, headcount); |
660 | break; | 624 | break; |