Revert "virtio_net: rx remove premapped failover code"
Subsystems (4)
A message that is not in the archive (sent off-list or not yet received): [email protected]
Michael S. Tsirkin
maintainerRFC PATCH 1/3 Revert "virtio_net: rx remove premapped failover code"
This reverts commit defd28aa5acb0fd7c15adc6bc40a8ac277d04dea.
leads to crashes with no ACCESS_PLATFORM when
sysctl net.core.high_order_alloc_disable=1
Message-ID: <[email protected]>
--- drivers/net/virtio_net.c | 89 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 37 deletions(-)
drivers/net/virtio_net.c +52 -37
@@ -348,6 +348,9 @@ struct receive_queue {/* Record the last dma info to free after new pages is allocated. */ struct virtnet_rq_dma *last_dma; + +/* Do dma by self */ +bool do_dma; };/* This structure can contain rss message with maximum settings for indirection table and keysize
@@ -848,7 +851,7 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)void *buf; buf =virtqueue_get_buf_ctx (rq->vq, len, ctx); -if (buf) +if (buf && rq->do_dma)virtnet_rq_unmap (rq, buf, *len);return buf;
@@ -861,6 +864,11 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)u32 offset;void *head; +if (!rq->do_dma) { +sg_init_one (rq->sg, buf, len); +return ; + } + head =page_address (rq->alloc_frag.page); offset = buf - head;
@@ -886,42 +894,44 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) head =page_address (alloc_frag->page); - dma = head; +if (rq->do_dma) { + dma = head; -/* new pages */ -if (!alloc_frag->offset) { -if (rq->last_dma) { -/* Now, the new page is allocated, the last dma -* will not be used. So the dma can be unmapped -* if the ref is 0. +/* new pages */ +if (!alloc_frag->offset) { +if (rq->last_dma) { +/* Now, the new page is allocated, the last dma +* will not be used. So the dma can be unmapped +* if the ref is 0. +*/ +virtnet_rq_unmap (rq, rq->last_dma,0 ); + rq->last_dma =NULL ; + } + + dma->len = alloc_frag->size -sizeof (*dma); + + addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , + dma->len,DMA_FROM_DEVICE ,0 ); +if (virtqueue_dma_mapping_error (rq->vq, addr)) +return NULL ; + + dma->addr = addr; + dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); + +/* Add a reference to dma to prevent the entire dma from +* being released during error handling. This reference +* will be freed after the pages are no longer used. */ -virtnet_rq_unmap (rq, rq->last_dma,0 ); - rq->last_dma =NULL ; +get_page (alloc_frag->page); + dma->ref =1 ; + alloc_frag->offset =sizeof (*dma); + + rq->last_dma = dma; } - dma->len = alloc_frag->size -sizeof (*dma); - - addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , - dma->len,DMA_FROM_DEVICE ,0 ); -if (virtqueue_dma_mapping_error (rq->vq, addr)) -return NULL ; - - dma->addr = addr; - dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); - -/* Add a reference to dma to prevent the entire dma from -* being released during error handling. This reference -* will be freed after the pages are no longer used. -*/ -get_page (alloc_frag->page); - dma->ref =1 ; - alloc_frag->offset =sizeof (*dma); - - rq->last_dma = dma; + ++dma->ref; } - ++dma->ref; - buf = head + alloc_frag->offset;get_page (alloc_frag->page);
@@ -938,9 +948,12 @@ static void virtnet_rq_set_premapped(struct virtnet_info *vi)if (!vi->mergeable_rx_bufs && vi->big_packets)return ; -for (i =0 ; i < vi->max_queue_pairs; i++) -/* error should never happen */ -BUG_ON (virtqueue_set_dma_premapped (vi->rq[i].vq)); +for (i =0 ; i < vi->max_queue_pairs; i++) { +if (virtqueue_set_dma_premapped (vi->rq[i].vq)) +continue ; + + vi->rq[i].do_dma = true; + } }static void virtnet_rq_unmap_free_buf (struct virtqueue *vq,void *buf)
@@ -2036,7 +2049,8 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }
@@ -2150,7 +2164,8 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, ctx =mergeable_len_to_ctx (len + room, headroom); err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }
@@ -5231,7 +5246,7 @@ static void free_receive_page_frags(struct virtnet_info *vi)int i;for (i =0 ; i < vi->max_queue_pairs; i++)if (vi->rq[i].alloc_frag.page) { -if (vi->rq[i].last_dma) +if (vi->rq[i].do_dma && vi->rq[i].last_dma)virtnet_rq_unmap (&vi->rq[i], vi->rq[i].last_dma,0 );put_page (vi->rq[i].alloc_frag.page); }
Signature · 1 line
MST
Hi Michael,
I've tested this on the system that was reproducing the panic, and it everything is working now as expected.
For the series then:
Thanks,
Darren.
Quoted 169 lines · Michael S. Tsirkin
This reverts commit
defd28aa5acb0fd7c15adc6bc40a8ac277d04dea.leads to crashes with no
ACCESS_PLATFORMwhen
sysctl net.core.high_order_alloc_disable=1Reported-by Si-Wei Liu <[email protected]>Message-ID: <[email protected]>
Signed-off-by Michael S. Tsirkin <[email protected]>--- drivers/net/virtio_net.c | 89 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 37 deletions(-)drivers/net/virtio_net.c +52
-37@@ -348,6 +348,9 @@ struct receive_queue {/* Record the last dma info to free after new pages is allocated. */ struct virtnet_rq_dma *last_dma; + +/* Do dma by self */ +bool do_dma; };/* This structure can contain rss message with maximum settings for indirection table and keysize @@ -848,7 +851,7 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)void *buf; buf =virtqueue_get_buf_ctx (rq->vq, len, ctx); -if (buf) +if (buf && rq->do_dma)virtnet_rq_unmap (rq, buf, *len);return buf;@@ -861,6 +864,11 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)u32 offset;void *head; +if (!rq->do_dma) { +sg_init_one (rq->sg, buf, len); +return ; + } + head =page_address (rq->alloc_frag.page); offset = buf - head;@@ -886,42 +894,44 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) head =page_address (alloc_frag->page); - dma = head; +if (rq->do_dma) { + dma = head; -/* new pages */ -if (!alloc_frag->offset) { -if (rq->last_dma) { -/* Now, the new page is allocated, the last dma -* will not be used. So the dma can be unmapped -* if the ref is 0. +/* new pages */ +if (!alloc_frag->offset) { +if (rq->last_dma) { +/* Now, the new page is allocated, the last dma +* will not be used. So the dma can be unmapped +* if the ref is 0. +*/ +virtnet_rq_unmap (rq, rq->last_dma,0 ); + rq->last_dma =NULL ; + } + + dma->len = alloc_frag->size -sizeof (*dma); + + addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , + dma->len,DMA_FROM_DEVICE ,0 ); +if (virtqueue_dma_mapping_error (rq->vq, addr)) +return NULL ; + + dma->addr = addr; + dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); + +/* Add a reference to dma to prevent the entire dma from +* being released during error handling. This reference +* will be freed after the pages are no longer used. */ -virtnet_rq_unmap (rq, rq->last_dma,0 ); - rq->last_dma =NULL ; +get_page (alloc_frag->page); + dma->ref =1 ; + alloc_frag->offset =sizeof (*dma); + + rq->last_dma = dma; } - dma->len = alloc_frag->size -sizeof (*dma); - - addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , - dma->len,DMA_FROM_DEVICE ,0 ); -if (virtqueue_dma_mapping_error (rq->vq, addr)) -return NULL ; - - dma->addr = addr; - dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); - -/* Add a reference to dma to prevent the entire dma from -* being released during error handling. This reference -* will be freed after the pages are no longer used. -*/ -get_page (alloc_frag->page); - dma->ref =1 ; - alloc_frag->offset =sizeof (*dma); - - rq->last_dma = dma; + ++dma->ref; } - ++dma->ref; - buf = head + alloc_frag->offset;get_page (alloc_frag->page);@@ -938,9 +948,12 @@ static void virtnet_rq_set_premapped(struct virtnet_info *vi)if (!vi->mergeable_rx_bufs && vi->big_packets)return ; -for (i =0 ; i < vi->max_queue_pairs; i++) -/* error should never happen */ -BUG_ON (virtqueue_set_dma_premapped (vi->rq[i].vq)); +for (i =0 ; i < vi->max_queue_pairs; i++) { +if (virtqueue_set_dma_premapped (vi->rq[i].vq)) +continue ; + + vi->rq[i].do_dma = true; + } }static void virtnet_rq_unmap_free_buf (struct virtqueue *vq,void *buf)@@ -2036,7 +2049,8 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }@@ -2150,7 +2164,8 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, ctx =mergeable_len_to_ctx (len + room, headroom); err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }@@ -5231,7 +5246,7 @@ static void free_receive_page_frags(struct virtnet_info *vi)int i;for (i =0 ; i < vi->max_queue_pairs; i++)if (vi->rq[i].alloc_frag.page) { -if (vi->rq[i].last_dma) +if (vi->rq[i].do_dma && vi->rq[i].last_dma)virtnet_rq_unmap (&vi->rq[i], vi->rq[i].last_dma,0 );put_page (vi->rq[i].alloc_frag.page); }Signature · 1 line
MST
Michael S. Tsirkin
maintainerCould you pls repeat this testing for v2? I had to revert more patches for that one.
Quoted 183 lines · Darren Kenny
Hi Michael,
I've tested this on the system that was reproducing the panic, and it everything is working now as expected.
For the series then:
Tested-by Darren Kenny <[email protected]>Thanks,
Darren.
Quoted 169 lines · Michael S. Tsirkin
This reverts commit
defd28aa5acb0fd7c15adc6bc40a8ac277d04dea.leads to crashes with no
ACCESS_PLATFORMwhen
sysctl net.core.high_order_alloc_disable=1Reported-by Si-Wei Liu <[email protected]>Message-ID: <[email protected]>
Signed-off-by Michael S. Tsirkin <[email protected]>--- drivers/net/virtio_net.c | 89 +++++++++++++++++++++++----------------- 1 file changed, 52 insertions(+), 37 deletions(-)drivers/net/virtio_net.c +52
-37@@ -348,6 +348,9 @@ struct receive_queue {/* Record the last dma info to free after new pages is allocated. */ struct virtnet_rq_dma *last_dma; + +/* Do dma by self */ +bool do_dma; };/* This structure can contain rss message with maximum settings for indirection table and keysize @@ -848,7 +851,7 @@ static void *virtnet_rq_get_buf(struct receive_queue *rq, u32 *len, void **ctx)void *buf; buf =virtqueue_get_buf_ctx (rq->vq, len, ctx); -if (buf) +if (buf && rq->do_dma)virtnet_rq_unmap (rq, buf, *len);return buf;@@ -861,6 +864,11 @@ static void virtnet_rq_init_one_sg(struct receive_queue *rq, void *buf, u32 len)u32 offset;void *head; +if (!rq->do_dma) { +sg_init_one (rq->sg, buf, len); +return ; + } + head =page_address (rq->alloc_frag.page); offset = buf - head;@@ -886,42 +894,44 @@ static void *virtnet_rq_alloc(struct receive_queue *rq, u32 size, gfp_t gfp) head =page_address (alloc_frag->page); - dma = head; +if (rq->do_dma) { + dma = head; -/* new pages */ -if (!alloc_frag->offset) { -if (rq->last_dma) { -/* Now, the new page is allocated, the last dma -* will not be used. So the dma can be unmapped -* if the ref is 0. +/* new pages */ +if (!alloc_frag->offset) { +if (rq->last_dma) { +/* Now, the new page is allocated, the last dma +* will not be used. So the dma can be unmapped +* if the ref is 0. +*/ +virtnet_rq_unmap (rq, rq->last_dma,0 ); + rq->last_dma =NULL ; + } + + dma->len = alloc_frag->size -sizeof (*dma); + + addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , + dma->len,DMA_FROM_DEVICE ,0 ); +if (virtqueue_dma_mapping_error (rq->vq, addr)) +return NULL ; + + dma->addr = addr; + dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); + +/* Add a reference to dma to prevent the entire dma from +* being released during error handling. This reference +* will be freed after the pages are no longer used. */ -virtnet_rq_unmap (rq, rq->last_dma,0 ); - rq->last_dma =NULL ; +get_page (alloc_frag->page); + dma->ref =1 ; + alloc_frag->offset =sizeof (*dma); + + rq->last_dma = dma; } - dma->len = alloc_frag->size -sizeof (*dma); - - addr =virtqueue_dma_map_single_attrs (rq->vq, dma +1 , - dma->len,DMA_FROM_DEVICE ,0 ); -if (virtqueue_dma_mapping_error (rq->vq, addr)) -return NULL ; - - dma->addr = addr; - dma->need_sync =virtqueue_dma_need_sync (rq->vq, addr); - -/* Add a reference to dma to prevent the entire dma from -* being released during error handling. This reference -* will be freed after the pages are no longer used. -*/ -get_page (alloc_frag->page); - dma->ref =1 ; - alloc_frag->offset =sizeof (*dma); - - rq->last_dma = dma; + ++dma->ref; } - ++dma->ref; - buf = head + alloc_frag->offset;get_page (alloc_frag->page);@@ -938,9 +948,12 @@ static void virtnet_rq_set_premapped(struct virtnet_info *vi)if (!vi->mergeable_rx_bufs && vi->big_packets)return ; -for (i =0 ; i < vi->max_queue_pairs; i++) -/* error should never happen */ -BUG_ON (virtqueue_set_dma_premapped (vi->rq[i].vq)); +for (i =0 ; i < vi->max_queue_pairs; i++) { +if (virtqueue_set_dma_premapped (vi->rq[i].vq)) +continue ; + + vi->rq[i].do_dma = true; + } }static void virtnet_rq_unmap_free_buf (struct virtqueue *vq,void *buf)@@ -2036,7 +2049,8 @@ static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq, err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }@@ -2150,7 +2164,8 @@ static int add_recvbuf_mergeable(struct virtnet_info *vi, ctx =mergeable_len_to_ctx (len + room, headroom); err =virtqueue_add_inbuf_ctx (rq->vq, rq->sg,1 , buf, ctx, gfp);if (err <0 ) { -virtnet_rq_unmap (rq, buf,0 ); +if (rq->do_dma) +virtnet_rq_unmap (rq, buf,0 );put_page (virt_to_head_page (buf)); }@@ -5231,7 +5246,7 @@ static void free_receive_page_frags(struct virtnet_info *vi)int i;for (i =0 ; i < vi->max_queue_pairs; i++)if (vi->rq[i].alloc_frag.page) { -if (vi->rq[i].last_dma) +if (vi->rq[i].do_dma && vi->rq[i].last_dma)virtnet_rq_unmap (&vi->rq[i], vi->rq[i].last_dma,0 );put_page (vi->rq[i].alloc_frag.page); }Signature · 1 line
MST
Michael S. Tsirkin
maintainerRFC PATCH 2/3 Revert "virtio_net: big mode skip the unmap check"
In reply to a message not in the archiveThis reverts commit a377ae542d8d0a20a3173da3bbba72e045bea7a9.
leads to crashes with no ACCESS_PLATFORM when
sysctl net.core.high_order_alloc_disable=1
Message-ID: <[email protected]>
--- drivers/net/virtio_net.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/virtio_net.c +2 -2
@@ -964,7 +964,7 @@ static void virtnet_rq_unmap_free_buf(struct virtqueue *vq, void *buf) rq = &vi->rq[i]; -if (!vi->big_packets || vi->mergeable_rx_bufs) +if (rq->do_dma)virtnet_rq_unmap (rq, buf,0 );virtnet_rq_free_buf (vi, rq, buf);
@@ -2296,7 +2296,7 @@ static int virtnet_receive(struct receive_queue *rq, int budget, } }else {while (packets < budget && - (buf =virtqueue_get_buf (rq->vq, &len)) !=NULL ) { + (buf =virtnet_rq_get_buf (rq, &len,NULL )) !=NULL ) {receive_buf (vi, rq, buf, len,NULL , xdp_xmit, &stats); packets++; }
Signature · 1 line
MST
Michael S. Tsirkin
maintainerRFC PATCH 3/3 Revert "virtio_ring: enable premapped mode whatever use_dma_api"
In reply to a message not in the archiveThis reverts commit f9dac92ba9081062a6477ee015bd3b8c5914efc4.
leads to crashes with no ACCESS_PLATFORM when
sysctl net.core.high_order_alloc_disable=1
Message-ID: <[email protected]>
--- drivers/virtio/virtio_ring.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
drivers/virtio/virtio_ring.c +6 -1
@@ -2782,7 +2782,7 @@ EXPORT_SYMBOL_GPL(virtqueue_resize);* * Returns zero or a negative error. * 0: success. -* -EINVAL: too late to enable premapped mode, the vq already contains buffers. +* -EINVAL: vring does not use the dma api, so we can not enable premapped mode. */ int virtqueue_set_dma_premapped (struct virtqueue *_vq) {
@@ -2798,6 +2798,11 @@ int virtqueue_set_dma_premapped(struct virtqueue *_vq)return -EINVAL ; } +if (!vq->use_dma_api) { +END_USE (vq); +return -EINVAL ; + } + vq->premapped = true; vq->do_unmap = false;
Signature · 1 line
MST