jiangyiwen
2018-Nov-05  07:47 UTC
[PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
Guest receive mergeable rx buffer, it can merge
scatter rx buffer into a big buffer and then copy
to user space.
Signed-off-by: Yiwen Jiang <jiangyiwen at huawei.com>
---
 include/linux/virtio_vsock.h            |  9 ++++
 net/vmw_vsock/virtio_transport.c        | 75 +++++++++++++++++++++++++++++----
 net/vmw_vsock/virtio_transport_common.c | 59 ++++++++++++++++++++++----
 3 files changed, 127 insertions(+), 16 deletions(-)
diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h
index da9e1fe..6be3cd7 100644
--- a/include/linux/virtio_vsock.h
+++ b/include/linux/virtio_vsock.h
@@ -13,6 +13,8 @@
 #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE	(1024 * 4)
 #define VIRTIO_VSOCK_MAX_BUF_SIZE		0xFFFFFFFFUL
 #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE		(1024 * 64)
+/* virtio_vsock_pkt + max_pkt_len(default MAX_PKT_BUF_SIZE) */
+#define VIRTIO_VSOCK_MAX_MRG_BUF_NUM ((VIRTIO_VSOCK_MAX_PKT_BUF_SIZE /
PAGE_SIZE) + 1)
 /* Virtio-vsock feature */
 #define VIRTIO_VSOCK_F_MRG_RXBUF 0 /* Host can merge receive buffers. */
@@ -48,6 +50,11 @@ struct virtio_vsock_sock {
 	struct list_head rx_queue;
 };
+struct virtio_vsock_mrg_rxbuf {
+	void *buf;
+	u32 len;
+};
+
 struct virtio_vsock_pkt {
 	struct virtio_vsock_hdr	hdr;
 	struct virtio_vsock_mrg_rxbuf_hdr mrg_rxbuf_hdr;
@@ -59,6 +66,8 @@ struct virtio_vsock_pkt {
 	u32 len;
 	u32 off;
 	bool reply;
+	bool mergeable;
+	struct virtio_vsock_mrg_rxbuf mrg_rxbuf[VIRTIO_VSOCK_MAX_MRG_BUF_NUM];
 };
 struct virtio_vsock_pkt_info {
diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c
index 2040a9e..3557ad3 100644
--- a/net/vmw_vsock/virtio_transport.c
+++ b/net/vmw_vsock/virtio_transport.c
@@ -359,11 +359,62 @@ static bool virtio_transport_more_replies(struct
virtio_vsock *vsock)
 	return val < virtqueue_get_vring_size(vq);
 }
+static struct virtio_vsock_pkt *receive_mergeable(struct virtqueue *vq,
+		struct virtio_vsock *vsock, unsigned int *total_len)
+{
+	struct virtio_vsock_pkt *pkt;
+	u16 num_buf;
+	void *page;
+	unsigned int len;
+	int i = 0;
+
+	page = virtqueue_get_buf(vq, &len);
+	if (!page)
+		return NULL;
+
+	*total_len = len;
+	vsock->rx_buf_nr--;
+
+	pkt = page;
+	num_buf = le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers);
+	if (!num_buf || num_buf > VIRTIO_VSOCK_MAX_MRG_BUF_NUM)
+		goto err;
+
+	pkt->mergeable = true;
+	if (!le32_to_cpu(pkt->hdr.len))
+		return pkt;
+
+	len -= sizeof(struct virtio_vsock_pkt);
+	pkt->mrg_rxbuf[i].buf = page + sizeof(struct virtio_vsock_pkt);
+	pkt->mrg_rxbuf[i].len = len;
+	i++;
+
+	while (--num_buf) {
+		page = virtqueue_get_buf(vq, &len);
+		if (!page)
+			goto err;
+
+		*total_len += len;
+		vsock->rx_buf_nr--;
+
+		pkt->mrg_rxbuf[i].buf = page;
+		pkt->mrg_rxbuf[i].len = len;
+		i++;
+	}
+
+	return pkt;
+err:
+	virtio_transport_free_pkt(pkt);
+	return NULL;
+}
+
 static void virtio_transport_rx_work(struct work_struct *work)
 {
 	struct virtio_vsock *vsock  		container_of(work, struct virtio_vsock,
rx_work);
 	struct virtqueue *vq;
+	size_t vsock_hlen = vsock->mergeable ? sizeof(struct virtio_vsock_pkt) :
+			sizeof(struct virtio_vsock_hdr);
 	vq = vsock->vqs[VSOCK_VQ_RX];
@@ -383,21 +434,29 @@ static void virtio_transport_rx_work(struct work_struct
*work)
 				goto out;
 			}
-			pkt = virtqueue_get_buf(vq, &len);
-			if (!pkt) {
-				break;
-			}
+			if (likely(vsock->mergeable)) {
+				pkt = receive_mergeable(vq, vsock, &len);
+				if (!pkt)
+					break;
-			vsock->rx_buf_nr--;
+				pkt->len = le32_to_cpu(pkt->hdr.len);
+			} else {
+				pkt = virtqueue_get_buf(vq, &len);
+				if (!pkt) {
+					break;
+				}
+
+				vsock->rx_buf_nr--;
+			}
 			/* Drop short/long packets */
-			if (unlikely(len < sizeof(pkt->hdr) ||
-				     len > sizeof(pkt->hdr) + pkt->len)) {
+			if (unlikely(len < vsock_hlen ||
+				     len > vsock_hlen + pkt->len)) {
 				virtio_transport_free_pkt(pkt);
 				continue;
 			}
-			pkt->len = len - sizeof(pkt->hdr);
+			pkt->len = len - vsock_hlen;
 			virtio_transport_deliver_tap_pkt(pkt);
 			virtio_transport_recv_pkt(pkt);
 		}
diff --git a/net/vmw_vsock/virtio_transport_common.c
b/net/vmw_vsock/virtio_transport_common.c
index 3ae3a33..7bef1d5 100644
--- a/net/vmw_vsock/virtio_transport_common.c
+++ b/net/vmw_vsock/virtio_transport_common.c
@@ -272,14 +272,49 @@ static int virtio_transport_send_credit_update(struct
vsock_sock *vsk,
 		 */
 		spin_unlock_bh(&vvs->rx_lock);
-		err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
-		if (err)
-			goto out;
+		if (pkt->mergeable) {
+			struct virtio_vsock_mrg_rxbuf *buf = pkt->mrg_rxbuf;
+			size_t mrg_copy_bytes, last_buf_total = 0, rxbuf_off;
+			size_t tmp_bytes = bytes;
+			int i;
+
+			for (i = 0; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) {
+				if (pkt->off > last_buf_total + buf[i].len) {
+					last_buf_total += buf[i].len;
+					continue;
+				}
+
+				rxbuf_off = pkt->off - last_buf_total;
+				mrg_copy_bytes = min(buf[i].len - rxbuf_off, tmp_bytes);
+				err = memcpy_to_msg(msg, buf[i].buf + rxbuf_off, mrg_copy_bytes);
+				if (err)
+					goto out;
+
+				tmp_bytes -= mrg_copy_bytes;
+				pkt->off += mrg_copy_bytes;
+				last_buf_total += buf[i].len;
+				if (!tmp_bytes)
+					break;
+			}
+
+			if (tmp_bytes) {
+				printk(KERN_WARNING "WARNING! bytes = %llu, "
+						"bytes = %llu\n",
+						(unsigned long long)bytes,
+						(unsigned long long)tmp_bytes);
+			}
+
+			total += (bytes - tmp_bytes);
+		} else {
+			err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes);
+			if (err)
+				goto out;
+
+			total += bytes;
+			pkt->off += bytes;
+		}
 		spin_lock_bh(&vvs->rx_lock);
-
-		total += bytes;
-		pkt->off += bytes;
 		if (pkt->off == pkt->len) {
 			virtio_transport_dec_rx_pkt(vvs, pkt);
 			list_del(&pkt->list);
@@ -1050,8 +1085,16 @@ void virtio_transport_recv_pkt(struct virtio_vsock_pkt
*pkt)
 void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt)
 {
-	kfree(pkt->buf);
-	kfree(pkt);
+	int i;
+
+	if (pkt->mergeable) {
+		for (i = 1; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++)
+			free_page((unsigned long)pkt->mrg_rxbuf[i].buf);
+		free_page((unsigned long)(void *)pkt);
+	} else {
+		kfree(pkt->buf);
+		kfree(pkt);
+	}
 }
 EXPORT_SYMBOL_GPL(virtio_transport_free_pkt);
-- 
1.8.3.1
Jason Wang
2018-Nov-06  04:00 UTC
[PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
On 2018/11/5 ??3:47, jiangyiwen wrote:> Guest receive mergeable rx buffer, it can merge > scatter rx buffer into a big buffer and then copy > to user space. > > Signed-off-by: Yiwen Jiang <jiangyiwen at huawei.com> > --- > include/linux/virtio_vsock.h | 9 ++++ > net/vmw_vsock/virtio_transport.c | 75 +++++++++++++++++++++++++++++---- > net/vmw_vsock/virtio_transport_common.c | 59 ++++++++++++++++++++++---- > 3 files changed, 127 insertions(+), 16 deletions(-) > > diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h > index da9e1fe..6be3cd7 100644 > --- a/include/linux/virtio_vsock.h > +++ b/include/linux/virtio_vsock.h > @@ -13,6 +13,8 @@ > #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4) > #define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL > #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) > +/* virtio_vsock_pkt + max_pkt_len(default MAX_PKT_BUF_SIZE) */ > +#define VIRTIO_VSOCK_MAX_MRG_BUF_NUM ((VIRTIO_VSOCK_MAX_PKT_BUF_SIZE / PAGE_SIZE) + 1) > > /* Virtio-vsock feature */ > #define VIRTIO_VSOCK_F_MRG_RXBUF 0 /* Host can merge receive buffers. */ > @@ -48,6 +50,11 @@ struct virtio_vsock_sock { > struct list_head rx_queue; > }; > > +struct virtio_vsock_mrg_rxbuf { > + void *buf; > + u32 len; > +}; > + > struct virtio_vsock_pkt { > struct virtio_vsock_hdr hdr; > struct virtio_vsock_mrg_rxbuf_hdr mrg_rxbuf_hdr; > @@ -59,6 +66,8 @@ struct virtio_vsock_pkt { > u32 len; > u32 off; > bool reply; > + bool mergeable; > + struct virtio_vsock_mrg_rxbuf mrg_rxbuf[VIRTIO_VSOCK_MAX_MRG_BUF_NUM]; > };It's better to use iov here I think, and drop buf completely. And this is better to be done in an independent patch.> > struct virtio_vsock_pkt_info { > diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c > index 2040a9e..3557ad3 100644 > --- a/net/vmw_vsock/virtio_transport.c > +++ b/net/vmw_vsock/virtio_transport.c > @@ -359,11 +359,62 @@ static bool virtio_transport_more_replies(struct virtio_vsock *vsock) > return val < virtqueue_get_vring_size(vq); > } > > +static struct virtio_vsock_pkt *receive_mergeable(struct virtqueue *vq, > + struct virtio_vsock *vsock, unsigned int *total_len) > +{ > + struct virtio_vsock_pkt *pkt; > + u16 num_buf; > + void *page; > + unsigned int len; > + int i = 0; > + > + page = virtqueue_get_buf(vq, &len); > + if (!page) > + return NULL; > + > + *total_len = len; > + vsock->rx_buf_nr--; > + > + pkt = page; > + num_buf = le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); > + if (!num_buf || num_buf > VIRTIO_VSOCK_MAX_MRG_BUF_NUM) > + goto err; > + > + pkt->mergeable = true; > + if (!le32_to_cpu(pkt->hdr.len)) > + return pkt; > + > + len -= sizeof(struct virtio_vsock_pkt); > + pkt->mrg_rxbuf[i].buf = page + sizeof(struct virtio_vsock_pkt); > + pkt->mrg_rxbuf[i].len = len; > + i++; > + > + while (--num_buf) { > + page = virtqueue_get_buf(vq, &len); > + if (!page) > + goto err; > + > + *total_len += len; > + vsock->rx_buf_nr--; > + > + pkt->mrg_rxbuf[i].buf = page; > + pkt->mrg_rxbuf[i].len = len; > + i++; > + } > + > + return pkt; > +err: > + virtio_transport_free_pkt(pkt); > + return NULL; > +}Similar logic could be found at virtio-net driver. Haven't thought this deeply, but it looks to me use virtio-net driver is also possible, e.g for data-path, just register vsock specific callbacks.> + > static void virtio_transport_rx_work(struct work_struct *work) > { > struct virtio_vsock *vsock > container_of(work, struct virtio_vsock, rx_work); > struct virtqueue *vq; > + size_t vsock_hlen = vsock->mergeable ? sizeof(struct virtio_vsock_pkt) : > + sizeof(struct virtio_vsock_hdr); > > vq = vsock->vqs[VSOCK_VQ_RX]; > > @@ -383,21 +434,29 @@ static void virtio_transport_rx_work(struct work_struct *work) > goto out; > } > > - pkt = virtqueue_get_buf(vq, &len); > - if (!pkt) { > - break; > - } > + if (likely(vsock->mergeable)) { > + pkt = receive_mergeable(vq, vsock, &len); > + if (!pkt) > + break; > > - vsock->rx_buf_nr--; > + pkt->len = le32_to_cpu(pkt->hdr.len); > + } else { > + pkt = virtqueue_get_buf(vq, &len); > + if (!pkt) { > + break; > + } > + > + vsock->rx_buf_nr--; > + } > > /* Drop short/long packets */ > - if (unlikely(len < sizeof(pkt->hdr) || > - len > sizeof(pkt->hdr) + pkt->len)) { > + if (unlikely(len < vsock_hlen || > + len > vsock_hlen + pkt->len)) { > virtio_transport_free_pkt(pkt); > continue; > } > > - pkt->len = len - sizeof(pkt->hdr); > + pkt->len = len - vsock_hlen; > virtio_transport_deliver_tap_pkt(pkt); > virtio_transport_recv_pkt(pkt); > } > diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c > index 3ae3a33..7bef1d5 100644 > --- a/net/vmw_vsock/virtio_transport_common.c > +++ b/net/vmw_vsock/virtio_transport_common.c > @@ -272,14 +272,49 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk, > */ > spin_unlock_bh(&vvs->rx_lock); > > - err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); > - if (err) > - goto out; > + if (pkt->mergeable) { > + struct virtio_vsock_mrg_rxbuf *buf = pkt->mrg_rxbuf; > + size_t mrg_copy_bytes, last_buf_total = 0, rxbuf_off; > + size_t tmp_bytes = bytes; > + int i; > + > + for (i = 0; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) { > + if (pkt->off > last_buf_total + buf[i].len) { > + last_buf_total += buf[i].len; > + continue; > + } > + > + rxbuf_off = pkt->off - last_buf_total; > + mrg_copy_bytes = min(buf[i].len - rxbuf_off, tmp_bytes); > + err = memcpy_to_msg(msg, buf[i].buf + rxbuf_off, mrg_copy_bytes); > + if (err) > + goto out; > + > + tmp_bytes -= mrg_copy_bytes; > + pkt->off += mrg_copy_bytes; > + last_buf_total += buf[i].len; > + if (!tmp_bytes) > + break; > + }After switch to use iov, you can user iov_iter helper to avoid the above open-coding I believe. And you can also drop the if (mergeable) condition. Thanks> + > + if (tmp_bytes) { > + printk(KERN_WARNING "WARNING! bytes = %llu, " > + "bytes = %llu\n", > + (unsigned long long)bytes, > + (unsigned long long)tmp_bytes); > + } > + > + total += (bytes - tmp_bytes); > + } else { > + err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); > + if (err) > + goto out; > + > + total += bytes; > + pkt->off += bytes; > + } > > spin_lock_bh(&vvs->rx_lock); > - > - total += bytes; > - pkt->off += bytes; > if (pkt->off == pkt->len) { > virtio_transport_dec_rx_pkt(vvs, pkt); > list_del(&pkt->list); > @@ -1050,8 +1085,16 @@ void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) > > void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt) > { > - kfree(pkt->buf); > - kfree(pkt); > + int i; > + > + if (pkt->mergeable) { > + for (i = 1; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) > + free_page((unsigned long)pkt->mrg_rxbuf[i].buf); > + free_page((unsigned long)(void *)pkt); > + } else { > + kfree(pkt->buf); > + kfree(pkt); > + } > } > EXPORT_SYMBOL_GPL(virtio_transport_free_pkt); >
jiangyiwen
2018-Nov-06  06:41 UTC
[PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
On 2018/11/6 12:00, Jason Wang wrote:> > On 2018/11/5 ??3:47, jiangyiwen wrote: >> Guest receive mergeable rx buffer, it can merge >> scatter rx buffer into a big buffer and then copy >> to user space. >> >> Signed-off-by: Yiwen Jiang <jiangyiwen at huawei.com> >> --- >> include/linux/virtio_vsock.h | 9 ++++ >> net/vmw_vsock/virtio_transport.c | 75 +++++++++++++++++++++++++++++---- >> net/vmw_vsock/virtio_transport_common.c | 59 ++++++++++++++++++++++---- >> 3 files changed, 127 insertions(+), 16 deletions(-) >> >> diff --git a/include/linux/virtio_vsock.h b/include/linux/virtio_vsock.h >> index da9e1fe..6be3cd7 100644 >> --- a/include/linux/virtio_vsock.h >> +++ b/include/linux/virtio_vsock.h >> @@ -13,6 +13,8 @@ >> #define VIRTIO_VSOCK_DEFAULT_RX_BUF_SIZE (1024 * 4) >> #define VIRTIO_VSOCK_MAX_BUF_SIZE 0xFFFFFFFFUL >> #define VIRTIO_VSOCK_MAX_PKT_BUF_SIZE (1024 * 64) >> +/* virtio_vsock_pkt + max_pkt_len(default MAX_PKT_BUF_SIZE) */ >> +#define VIRTIO_VSOCK_MAX_MRG_BUF_NUM ((VIRTIO_VSOCK_MAX_PKT_BUF_SIZE / PAGE_SIZE) + 1) >> >> /* Virtio-vsock feature */ >> #define VIRTIO_VSOCK_F_MRG_RXBUF 0 /* Host can merge receive buffers. */ >> @@ -48,6 +50,11 @@ struct virtio_vsock_sock { >> struct list_head rx_queue; >> }; >> >> +struct virtio_vsock_mrg_rxbuf { >> + void *buf; >> + u32 len; >> +}; >> + >> struct virtio_vsock_pkt { >> struct virtio_vsock_hdr hdr; >> struct virtio_vsock_mrg_rxbuf_hdr mrg_rxbuf_hdr; >> @@ -59,6 +66,8 @@ struct virtio_vsock_pkt { >> u32 len; >> u32 off; >> bool reply; >> + bool mergeable; >> + struct virtio_vsock_mrg_rxbuf mrg_rxbuf[VIRTIO_VSOCK_MAX_MRG_BUF_NUM]; >> }; > > > It's better to use iov here I think, and drop buf completely. > > And this is better to be done in an independent patch. >You're right, I can use kvec instead of customized structure, in addition, I don't understand about drop buf completely and an independent patch. Thanks.> >> >> struct virtio_vsock_pkt_info { >> diff --git a/net/vmw_vsock/virtio_transport.c b/net/vmw_vsock/virtio_transport.c >> index 2040a9e..3557ad3 100644 >> --- a/net/vmw_vsock/virtio_transport.c >> +++ b/net/vmw_vsock/virtio_transport.c >> @@ -359,11 +359,62 @@ static bool virtio_transport_more_replies(struct virtio_vsock *vsock) >> return val < virtqueue_get_vring_size(vq); >> } >> >> +static struct virtio_vsock_pkt *receive_mergeable(struct virtqueue *vq, >> + struct virtio_vsock *vsock, unsigned int *total_len) >> +{ >> + struct virtio_vsock_pkt *pkt; >> + u16 num_buf; >> + void *page; >> + unsigned int len; >> + int i = 0; >> + >> + page = virtqueue_get_buf(vq, &len); >> + if (!page) >> + return NULL; >> + >> + *total_len = len; >> + vsock->rx_buf_nr--; >> + >> + pkt = page; >> + num_buf = le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); >> + if (!num_buf || num_buf > VIRTIO_VSOCK_MAX_MRG_BUF_NUM) >> + goto err; >> + >> + pkt->mergeable = true; >> + if (!le32_to_cpu(pkt->hdr.len)) >> + return pkt; >> + >> + len -= sizeof(struct virtio_vsock_pkt); >> + pkt->mrg_rxbuf[i].buf = page + sizeof(struct virtio_vsock_pkt); >> + pkt->mrg_rxbuf[i].len = len; >> + i++; >> + >> + while (--num_buf) { >> + page = virtqueue_get_buf(vq, &len); >> + if (!page) >> + goto err; >> + >> + *total_len += len; >> + vsock->rx_buf_nr--; >> + >> + pkt->mrg_rxbuf[i].buf = page; >> + pkt->mrg_rxbuf[i].len = len; >> + i++; >> + } >> + >> + return pkt; >> +err: >> + virtio_transport_free_pkt(pkt); >> + return NULL; >> +} > > > Similar logic could be found at virtio-net driver. > > Haven't thought this deeply, but it looks to me use virtio-net driver is also possible, e.g for data-path, just register vsock specific callbacks. > > >> + >> static void virtio_transport_rx_work(struct work_struct *work) >> { >> struct virtio_vsock *vsock >> container_of(work, struct virtio_vsock, rx_work); >> struct virtqueue *vq; >> + size_t vsock_hlen = vsock->mergeable ? sizeof(struct virtio_vsock_pkt) : >> + sizeof(struct virtio_vsock_hdr); >> >> vq = vsock->vqs[VSOCK_VQ_RX]; >> >> @@ -383,21 +434,29 @@ static void virtio_transport_rx_work(struct work_struct *work) >> goto out; >> } >> >> - pkt = virtqueue_get_buf(vq, &len); >> - if (!pkt) { >> - break; >> - } >> + if (likely(vsock->mergeable)) { >> + pkt = receive_mergeable(vq, vsock, &len); >> + if (!pkt) >> + break; >> >> - vsock->rx_buf_nr--; >> + pkt->len = le32_to_cpu(pkt->hdr.len); >> + } else { >> + pkt = virtqueue_get_buf(vq, &len); >> + if (!pkt) { >> + break; >> + } >> + >> + vsock->rx_buf_nr--; >> + } >> >> /* Drop short/long packets */ >> - if (unlikely(len < sizeof(pkt->hdr) || >> - len > sizeof(pkt->hdr) + pkt->len)) { >> + if (unlikely(len < vsock_hlen || >> + len > vsock_hlen + pkt->len)) { >> virtio_transport_free_pkt(pkt); >> continue; >> } >> >> - pkt->len = len - sizeof(pkt->hdr); >> + pkt->len = len - vsock_hlen; >> virtio_transport_deliver_tap_pkt(pkt); >> virtio_transport_recv_pkt(pkt); >> } >> diff --git a/net/vmw_vsock/virtio_transport_common.c b/net/vmw_vsock/virtio_transport_common.c >> index 3ae3a33..7bef1d5 100644 >> --- a/net/vmw_vsock/virtio_transport_common.c >> +++ b/net/vmw_vsock/virtio_transport_common.c >> @@ -272,14 +272,49 @@ static int virtio_transport_send_credit_update(struct vsock_sock *vsk, >> */ >> spin_unlock_bh(&vvs->rx_lock); >> >> - err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); >> - if (err) >> - goto out; >> + if (pkt->mergeable) { >> + struct virtio_vsock_mrg_rxbuf *buf = pkt->mrg_rxbuf; >> + size_t mrg_copy_bytes, last_buf_total = 0, rxbuf_off; >> + size_t tmp_bytes = bytes; >> + int i; >> + >> + for (i = 0; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) { >> + if (pkt->off > last_buf_total + buf[i].len) { >> + last_buf_total += buf[i].len; >> + continue; >> + } >> + >> + rxbuf_off = pkt->off - last_buf_total; >> + mrg_copy_bytes = min(buf[i].len - rxbuf_off, tmp_bytes); >> + err = memcpy_to_msg(msg, buf[i].buf + rxbuf_off, mrg_copy_bytes); >> + if (err) >> + goto out; >> + >> + tmp_bytes -= mrg_copy_bytes; >> + pkt->off += mrg_copy_bytes; >> + last_buf_total += buf[i].len; >> + if (!tmp_bytes) >> + break; >> + } > > > After switch to use iov, you can user iov_iter helper to avoid the above open-coding I believe. > > And you can also drop the if (mergeable) condition. > > Thanks >Thanks, I will try to use iov instead.> >> + >> + if (tmp_bytes) { >> + printk(KERN_WARNING "WARNING! bytes = %llu, " >> + "bytes = %llu\n", >> + (unsigned long long)bytes, >> + (unsigned long long)tmp_bytes); >> + } >> + >> + total += (bytes - tmp_bytes); >> + } else { >> + err = memcpy_to_msg(msg, pkt->buf + pkt->off, bytes); >> + if (err) >> + goto out; >> + >> + total += bytes; >> + pkt->off += bytes; >> + } >> >> spin_lock_bh(&vvs->rx_lock); >> - >> - total += bytes; >> - pkt->off += bytes; >> if (pkt->off == pkt->len) { >> virtio_transport_dec_rx_pkt(vvs, pkt); >> list_del(&pkt->list); >> @@ -1050,8 +1085,16 @@ void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) >> >> void virtio_transport_free_pkt(struct virtio_vsock_pkt *pkt) >> { >> - kfree(pkt->buf); >> - kfree(pkt); >> + int i; >> + >> + if (pkt->mergeable) { >> + for (i = 1; i < le16_to_cpu(pkt->mrg_rxbuf_hdr.num_buffers); i++) >> + free_page((unsigned long)pkt->mrg_rxbuf[i].buf); >> + free_page((unsigned long)(void *)pkt); >> + } else { >> + kfree(pkt->buf); >> + kfree(pkt); >> + } >> } >> EXPORT_SYMBOL_GPL(virtio_transport_free_pkt); >> > > . >
Reasonably Related Threads
- [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
- [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
- [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
- [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest
- [PATCH 3/5] VSOCK: support receive mergeable rx buffer in guest