Skip to content

Commit 64c99d2

Browse files
Arseniy KrasnovPaolo Abeni
authored andcommitted
vsock/virtio: support to send non-linear skb
For non-linear skb use its pages from fragment array as buffers in virtio tx queue. These pages are already pinned by 'get_user_pages()' during such skb creation. Signed-off-by: Arseniy Krasnov <avkrasnov@salutedevices.com> Reviewed-by: Stefano Garzarella <sgarzare@redhat.com> Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 0df7cd3 commit 64c99d2

1 file changed

Lines changed: 53 additions & 7 deletions

File tree

net/vmw_vsock/virtio_transport.c

Lines changed: 53 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,17 @@ struct virtio_vsock {
6363

6464
u32 guest_cid;
6565
bool seqpacket_allow;
66+
67+
/* These fields are used only in tx path in function
68+
* 'virtio_transport_send_pkt_work()', so to save
69+
* stack space in it, place both of them here. Each
70+
* pointer from 'out_sgs' points to the corresponding
71+
* element in 'out_bufs' - this is initialized in
72+
* 'virtio_vsock_probe()'. Both fields are protected
73+
* by 'tx_lock'. +1 is needed for packet header.
74+
*/
75+
struct scatterlist *out_sgs[MAX_SKB_FRAGS + 1];
76+
struct scatterlist out_bufs[MAX_SKB_FRAGS + 1];
6677
};
6778

6879
static u32 virtio_transport_get_local_cid(void)
@@ -100,8 +111,8 @@ virtio_transport_send_pkt_work(struct work_struct *work)
100111
vq = vsock->vqs[VSOCK_VQ_TX];
101112

102113
for (;;) {
103-
struct scatterlist hdr, buf, *sgs[2];
104114
int ret, in_sg = 0, out_sg = 0;
115+
struct scatterlist **sgs;
105116
struct sk_buff *skb;
106117
bool reply;
107118

@@ -111,12 +122,43 @@ virtio_transport_send_pkt_work(struct work_struct *work)
111122

112123
virtio_transport_deliver_tap_pkt(skb);
113124
reply = virtio_vsock_skb_reply(skb);
114-
115-
sg_init_one(&hdr, virtio_vsock_hdr(skb), sizeof(*virtio_vsock_hdr(skb)));
116-
sgs[out_sg++] = &hdr;
117-
if (skb->len > 0) {
118-
sg_init_one(&buf, skb->data, skb->len);
119-
sgs[out_sg++] = &buf;
125+
sgs = vsock->out_sgs;
126+
sg_init_one(sgs[out_sg], virtio_vsock_hdr(skb),
127+
sizeof(*virtio_vsock_hdr(skb)));
128+
out_sg++;
129+
130+
if (!skb_is_nonlinear(skb)) {
131+
if (skb->len > 0) {
132+
sg_init_one(sgs[out_sg], skb->data, skb->len);
133+
out_sg++;
134+
}
135+
} else {
136+
struct skb_shared_info *si;
137+
int i;
138+
139+
/* If skb is nonlinear, then its buffer must contain
140+
* only header and nothing more. Data is stored in
141+
* the fragged part.
142+
*/
143+
WARN_ON_ONCE(skb_headroom(skb) != sizeof(*virtio_vsock_hdr(skb)));
144+
145+
si = skb_shinfo(skb);
146+
147+
for (i = 0; i < si->nr_frags; i++) {
148+
skb_frag_t *skb_frag = &si->frags[i];
149+
void *va;
150+
151+
/* We will use 'page_to_virt()' for the userspace page
152+
* here, because virtio or dma-mapping layers will call
153+
* 'virt_to_phys()' later to fill the buffer descriptor.
154+
* We don't touch memory at "virtual" address of this page.
155+
*/
156+
va = page_to_virt(skb_frag->bv_page);
157+
sg_init_one(sgs[out_sg],
158+
va + skb_frag->bv_offset,
159+
skb_frag->bv_len);
160+
out_sg++;
161+
}
120162
}
121163

122164
ret = virtqueue_add_sgs(vq, sgs, out_sg, in_sg, skb, GFP_KERNEL);
@@ -621,6 +663,7 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
621663
{
622664
struct virtio_vsock *vsock = NULL;
623665
int ret;
666+
int i;
624667

625668
ret = mutex_lock_interruptible(&the_virtio_vsock_mutex);
626669
if (ret)
@@ -663,6 +706,9 @@ static int virtio_vsock_probe(struct virtio_device *vdev)
663706
if (ret < 0)
664707
goto out;
665708

709+
for (i = 0; i < ARRAY_SIZE(vsock->out_sgs); i++)
710+
vsock->out_sgs[i] = &vsock->out_bufs[i];
711+
666712
rcu_assign_pointer(the_virtio_vsock, vsock);
667713

668714
mutex_unlock(&the_virtio_vsock_mutex);

0 commit comments

Comments
 (0)