VSOCK: support receive mergeable rx buffer in guest
Subsystems (6)
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.
--- 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(-)
include/linux/virtio_vsock.h +9 -0
@@ -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 {
net/vmw_vsock/virtio_transport.c +67 -8
99 lines not on this page · raw message
net/vmw_vsock/virtio_transport_common.c +51 -8
73 lines not on this page · raw message
Signature · 1 line
1.8.3.1
Quoted 37 lines · jiangyiwen
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 <[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;
include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 48 lines
include/linux/virtio_vsock.h +0
-0struct virtio_vsock_pkt_info {net/vmw_vsock/virtio_transport.c +38
-0@@ -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--; +
net/vmw_vsock/virtio_transport.c static bool virtio_transport_more_replies(struct virtio_vsock *vsock) · line 409
Quoted 10 lines
net/vmw_vsock/virtio_transport.c +10
-0+ 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.
Quoted 74 lines
net/vmw_vsock/virtio_transport.c +19
-8+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); }net/vmw_vsock/virtio_transport_common.c +14
-3@@ -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);
net/vmw_vsock/virtio_transport_common.c static int virtio_transport_send_credit_update(struct vsock_sock *vsk, · line 298
Quoted 10 lines
net/vmw_vsock/virtio_transport_common.c +10
-0+ 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
Quoted 34 lines
net/vmw_vsock/virtio_transport_common.c +20
-5+ +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) {
net/vmw_vsock/virtio_transport_common.c void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) · line 1100
Quoted 10 lines
net/vmw_vsock/virtio_transport_common.c +7
-0+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);
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Quoted 49 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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 <[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 2 lines
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.
Quoted 154 lines
Quoted 49 lines
include/linux/virtio_vsock.h +0
-0struct virtio_vsock_pkt_info {net/vmw_vsock/virtio_transport.c +38
-0@@ -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--; +net/vmw_vsock/virtio_transport.c static bool virtio_transport_more_replies(struct virtio_vsock *vsock) · line 409
Quoted 10 lines
net/vmw_vsock/virtio_transport.c +10
-0+ 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.
Quoted 74 lines
net/vmw_vsock/virtio_transport.c +19
-8+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); }net/vmw_vsock/virtio_transport_common.c +14
-3@@ -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);net/vmw_vsock/virtio_transport_common.c static int virtio_transport_send_credit_update(struct vsock_sock *vsk, · line 298
Quoted 10 lines
net/vmw_vsock/virtio_transport_common.c +10
-0+ 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_iterhelper to avoid the above open-coding I believe.
Quoted 4 lines
And you can also drop the if (mergeable) condition.
Thanks
Thanks, I will try to use iov instead.
Quoted 48 lines
Quoted 35 lines
net/vmw_vsock/virtio_transport_common.c +20
-5+ +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) {net/vmw_vsock/virtio_transport_common.c void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) · line 1100
Quoted 10 lines
net/vmw_vsock/virtio_transport_common.c +7
-0+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);.
Quoted 47 lines · jiangyiwen
Quoted 46 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 5 lines
Quoted 2 lines
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.
I mean there a void *buf in struct virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.
Thanks
Quoted 3 lines
Thanks.
Quoted 51 lines · Jason Wang
Quoted 49 lines · jiangyiwen
Quoted 48 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 9 lines
Quoted 3 lines
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.
I mean there a void *buf in struct
virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.Thanks
Yes, I understand your idea, I don't want to modify tx process method, so I keep the buf.
Quoted 7 lines
Quoted 4 lines
Thanks.
.
Quoted 54 lines · jiangyiwen
Quoted 53 lines · Jason Wang
Quoted 52 lines · jiangyiwen
Quoted 46 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 2 lines
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.
Quoted 7 lines
Quoted 4 lines
I mean there a void *buf in struct
virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.Thanks
Yes, I understand your idea, I don't want to modify tx process method, so I keep the buf.
I'm afraid this will end of codes that is hard to be maintained. Let's try to unify them.
Thanks
Quoted 54 lines · jiangyiwen
Quoted 53 lines · Jason Wang
Quoted 52 lines · jiangyiwen
Quoted 46 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 2 lines
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.
Quoted 7 lines
Quoted 4 lines
I mean there a void *buf in struct
virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.Thanks
Yes, I understand your idea, I don't want to modify tx process method, so I keep the buf.
I'm afraid this will end of codes that is hard to be maintained. Let's try to unify them.
Thanks
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Quoted 51 lines · Jason Wang
Quoted 49 lines · jiangyiwen
Quoted 48 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 9 lines
Quoted 3 lines
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.
I mean there a void *buf in struct
virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.Thanks
Yes, I understand your idea, I don't want to modify tx process method, so I keep the buf.
Quoted 7 lines
Quoted 4 lines
Thanks.
.
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Quoted 47 lines · jiangyiwen
Quoted 46 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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<[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 5 lines
Quoted 2 lines
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.
I mean there a void *buf in struct virtio_vsock_pkt. You can drop it and switch to use iov(iter) or other data structure that supports sg.
Thanks
Quoted 3 lines
Thanks.
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization
Quoted 49 lines · Jason Wang
Quoted 37 lines · jiangyiwen
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 <[email protected]>--- 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(-)include/linux/virtio_vsock.h +7
-0@@ -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;include/linux/virtio_vsock.h struct virtio_vsock_pkt { · line 71
Quoted 6 lines
include/linux/virtio_vsock.h +2
-0@@ -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.
Quoted 2 lines
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.
Quoted 154 lines
Quoted 49 lines
include/linux/virtio_vsock.h +0
-0struct virtio_vsock_pkt_info {net/vmw_vsock/virtio_transport.c +38
-0@@ -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--; +net/vmw_vsock/virtio_transport.c static bool virtio_transport_more_replies(struct virtio_vsock *vsock) · line 409
Quoted 10 lines
net/vmw_vsock/virtio_transport.c +10
-0+ 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.
Quoted 74 lines
net/vmw_vsock/virtio_transport.c +19
-8+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); }net/vmw_vsock/virtio_transport_common.c +14
-3@@ -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);net/vmw_vsock/virtio_transport_common.c static int virtio_transport_send_credit_update(struct vsock_sock *vsk, · line 298
Quoted 10 lines
net/vmw_vsock/virtio_transport_common.c +10
-0+ 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_iterhelper to avoid the above open-coding I believe.
Quoted 4 lines
And you can also drop the if (mergeable) condition.
Thanks
Thanks, I will try to use iov instead.
Quoted 39 lines
Quoted 39 lines
net/vmw_vsock/virtio_transport_common.c +24
-5+ +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 {
Quoted 9 lines
net/vmw_vsock/virtio_transport_common.c void virtio_transport_recv_pkt(struct virtio_vsock_pkt *pkt) · line 1100
Quoted 6 lines
net/vmw_vsock/virtio_transport_common.c +3
-0+kfree (pkt->buf); +kfree (pkt); + } }EXPORT_SYMBOL_GPL (virtio_transport_free_pkt);.
_______________________________________________
Virtualization mailing list
[email protected]
https://lists.linuxfoundation.org/mailman/listinfo/virtualization