@samitouri / QOSamiQemu / commits / 558084367e

vhost: make vhost_memory_unmap() null-safe

This helps to simplify failure paths of vhost_virtqueue_start() a lot. We also need to zero-out pointers on unmap, to not try to unmap invalid pointers. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru> Reviewed-by: Daniil Tatianin <d-tatianin@yandex-team.ru> Reviewed-by: Raphael Norwitz <raphael.s.norwitz@gmail.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com> Message-Id: <20260420200339.708640-12-vsementsov@yandex-team.ru>

Vladimir Sementsov-Ogievskiy committed Apr 20, 2026 at 23:03 UTC 558084367e9059dbe9f851699cc90be3499ed0fa
1 file changed +21 -20
hw/virtio/vhost.c
+21 -20
@@ -473,14 +473,20 @@ static void *vhost_memory_map(struct vhost_dev *dev, hwaddr addr,
473 }
474 }
475
476 -static void vhost_memory_unmap(struct vhost_dev *dev, void *buffer,
476 +static void vhost_memory_unmap(struct vhost_dev *dev, void **buffer,
477 hwaddr len, int is_write,
478 hwaddr access_len)
479 {
480 + if (!*buffer) {
481 + return;
482 + }
483 +
484 if (!vhost_dev_has_iommu(dev)) {
481 - address_space_unmap(dev->vdev->dma_as, buffer, len, is_write,
485 + address_space_unmap(dev->vdev->dma_as, *buffer, len, is_write,
486 access_len);
487 }
488 +
489 + *buffer = NULL;
490 }
491
492 static int vhost_verify_ring_part_mapping(void *ring_hva,
@@ -1324,33 +1330,33 @@ int vhost_virtqueue_start(struct vhost_dev *dev,
1330 vq->desc = vhost_memory_map(dev, vq->desc_phys, l, false);
1331 if (!vq->desc) {
1332 r = -ENOMEM;
1327 - goto fail_alloc_desc;
1333 + goto fail;
1334 }
1335
1336 l = vq->avail_size;
1337 vq->avail = vhost_memory_map(dev, vq->avail_phys, l, false);
1338 if (!vq->avail) {
1339 r = -ENOMEM;
1334 - goto fail_alloc_avail;
1340 + goto fail;
1341 }
1342
1343 l = vq->used_size;
1344 vq->used = vhost_memory_map(dev, vq->used_phys, l, true);
1345 if (!vq->used) {
1346 r = -ENOMEM;
1341 - goto fail_alloc_used;
1347 + goto fail;
1348 }
1349
1350 r = vhost_virtqueue_set_addr(dev, vq, vhost_vq_index, dev->log_enabled);
1351 if (r < 0) {
1346 - goto fail_alloc;
1352 + goto fail;
1353 }
1354
1355 file.fd = event_notifier_get_fd(virtio_queue_get_host_notifier(vvq));
1356 r = dev->vhost_ops->vhost_set_vring_kick(dev, &file);
1357 if (r) {
1358 VHOST_OPS_DEBUG(r, "vhost_set_vring_kick failed");
1353 - goto fail_kick;
1359 + goto fail;
1360 }
1361
1362 /* Clear and discard previous events if any. */
@@ -1370,24 +1376,19 @@ int vhost_virtqueue_start(struct vhost_dev *dev,
1376 file.fd = -1;
1377 r = dev->vhost_ops->vhost_set_vring_call(dev, &file);
1378 if (r) {
1373 - goto fail_vector;
1379 + goto fail;
1380 }
1381 }
1382
1383 return 0;
1384
1379 -fail_vector:
1380 -fail_kick:
1381 -fail_alloc:
1382 - vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
1385 +fail:
1386 + vhost_memory_unmap(dev, &vq->used, virtio_queue_get_used_size(vdev, idx),
1387 0, 0);
1384 -fail_alloc_used:
1385 - vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
1388 + vhost_memory_unmap(dev, &vq->avail, virtio_queue_get_avail_size(vdev, idx),
1389 0, 0);
1387 -fail_alloc_avail:
1388 - vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
1390 + vhost_memory_unmap(dev, &vq->desc, virtio_queue_get_desc_size(vdev, idx),
1391 0, 0);
1390 -fail_alloc_desc:
1392 return r;
1393 }
1394
@@ -1434,11 +1435,11 @@ static int do_vhost_virtqueue_stop(struct vhost_dev *dev,
1435 vhost_vq_index);
1436 }
1437
1437 - vhost_memory_unmap(dev, vq->used, virtio_queue_get_used_size(vdev, idx),
1438 + vhost_memory_unmap(dev, &vq->used, virtio_queue_get_used_size(vdev, idx),
1439 1, virtio_queue_get_used_size(vdev, idx));
1439 - vhost_memory_unmap(dev, vq->avail, virtio_queue_get_avail_size(vdev, idx),
1440 + vhost_memory_unmap(dev, &vq->avail, virtio_queue_get_avail_size(vdev, idx),
1441 0, virtio_queue_get_avail_size(vdev, idx));
1441 - vhost_memory_unmap(dev, vq->desc, virtio_queue_get_desc_size(vdev, idx),
1442 + vhost_memory_unmap(dev, &vq->desc, virtio_queue_get_desc_size(vdev, idx),
1443 0, virtio_queue_get_desc_size(vdev, idx));
1444 return r;
1445 }