Skip to content

Commit c611c76

Browse files
bonzinimstsirkin
authored andcommitted
virtio: add MemoryListener to cache ring translations
The cached translations are RCU-protected to allow efficient use when processing virtqueues. Reviewed-by: Stefan Hajnoczi <[email protected]> Signed-off-by: Paolo Bonzini <[email protected]> Reviewed-by: Michael S. Tsirkin <[email protected]> Signed-off-by: Michael S. Tsirkin <[email protected]>
1 parent 5eba040 commit c611c76

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

hw/virtio/virtio.c

Lines changed: 102 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,13 @@ typedef struct VRingUsed
6060
VRingUsedElem ring[0];
6161
} VRingUsed;
6262

63+
typedef struct VRingMemoryRegionCaches {
64+
struct rcu_head rcu;
65+
MemoryRegionCache desc;
66+
MemoryRegionCache avail;
67+
MemoryRegionCache used;
68+
} VRingMemoryRegionCaches;
69+
6370
typedef struct VRing
6471
{
6572
unsigned int num;
@@ -68,6 +75,7 @@ typedef struct VRing
6875
hwaddr desc;
6976
hwaddr avail;
7077
hwaddr used;
78+
VRingMemoryRegionCaches *caches;
7179
} VRing;
7280

7381
struct VirtQueue
@@ -104,6 +112,51 @@ struct VirtQueue
104112
QLIST_ENTRY(VirtQueue) node;
105113
};
106114

115+
static void virtio_free_region_cache(VRingMemoryRegionCaches *caches)
116+
{
117+
if (!caches) {
118+
return;
119+
}
120+
121+
address_space_cache_destroy(&caches->desc);
122+
address_space_cache_destroy(&caches->avail);
123+
address_space_cache_destroy(&caches->used);
124+
g_free(caches);
125+
}
126+
127+
static void virtio_init_region_cache(VirtIODevice *vdev, int n)
128+
{
129+
VirtQueue *vq = &vdev->vq[n];
130+
VRingMemoryRegionCaches *old = vq->vring.caches;
131+
VRingMemoryRegionCaches *new;
132+
hwaddr addr, size;
133+
int event_size;
134+
135+
event_size = virtio_vdev_has_feature(vq->vdev, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
136+
137+
addr = vq->vring.desc;
138+
if (!addr) {
139+
return;
140+
}
141+
new = g_new0(VRingMemoryRegionCaches, 1);
142+
size = virtio_queue_get_desc_size(vdev, n);
143+
address_space_cache_init(&new->desc, vdev->dma_as,
144+
addr, size, false);
145+
146+
size = virtio_queue_get_used_size(vdev, n) + event_size;
147+
address_space_cache_init(&new->used, vdev->dma_as,
148+
vq->vring.used, size, true);
149+
150+
size = virtio_queue_get_avail_size(vdev, n) + event_size;
151+
address_space_cache_init(&new->avail, vdev->dma_as,
152+
vq->vring.avail, size, false);
153+
154+
atomic_rcu_set(&vq->vring.caches, new);
155+
if (old) {
156+
call_rcu(old, virtio_free_region_cache, rcu);
157+
}
158+
}
159+
107160
/* virt queue functions */
108161
void virtio_queue_update_rings(VirtIODevice *vdev, int n)
109162
{
@@ -117,6 +170,7 @@ void virtio_queue_update_rings(VirtIODevice *vdev, int n)
117170
vring->used = vring_align(vring->avail +
118171
offsetof(VRingAvail, ring[vring->num]),
119172
vring->align);
173+
virtio_init_region_cache(vdev, n);
120174
}
121175

122176
static void vring_desc_read(VirtIODevice *vdev, VRingDesc *desc,
@@ -1264,6 +1318,7 @@ void virtio_queue_set_rings(VirtIODevice *vdev, int n, hwaddr desc,
12641318
vdev->vq[n].vring.desc = desc;
12651319
vdev->vq[n].vring.avail = avail;
12661320
vdev->vq[n].vring.used = used;
1321+
virtio_init_region_cache(vdev, n);
12671322
}
12681323

12691324
void virtio_queue_set_num(VirtIODevice *vdev, int n, int num)
@@ -1984,9 +2039,6 @@ int virtio_load(VirtIODevice *vdev, QEMUFile *f, int version_id)
19842039
void virtio_cleanup(VirtIODevice *vdev)
19852040
{
19862041
qemu_del_vm_change_state_handler(vdev->vmstate);
1987-
g_free(vdev->config);
1988-
g_free(vdev->vq);
1989-
g_free(vdev->vector_queues);
19902042
}
19912043

19922044
static void virtio_vmstate_change(void *opaque, int running, RunState state)
@@ -2248,6 +2300,19 @@ void GCC_FMT_ATTR(2, 3) virtio_error(VirtIODevice *vdev, const char *fmt, ...)
22482300
}
22492301
}
22502302

2303+
static void virtio_memory_listener_commit(MemoryListener *listener)
2304+
{
2305+
VirtIODevice *vdev = container_of(listener, VirtIODevice, listener);
2306+
int i;
2307+
2308+
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
2309+
if (vdev->vq[i].vring.num == 0) {
2310+
break;
2311+
}
2312+
virtio_init_region_cache(vdev, i);
2313+
}
2314+
}
2315+
22512316
static void virtio_device_realize(DeviceState *dev, Error **errp)
22522317
{
22532318
VirtIODevice *vdev = VIRTIO_DEVICE(dev);
@@ -2270,6 +2335,9 @@ static void virtio_device_realize(DeviceState *dev, Error **errp)
22702335
error_propagate(errp, err);
22712336
return;
22722337
}
2338+
2339+
vdev->listener.commit = virtio_memory_listener_commit;
2340+
memory_listener_register(&vdev->listener, vdev->dma_as);
22732341
}
22742342

22752343
static void virtio_device_unrealize(DeviceState *dev, Error **errp)
@@ -2292,6 +2360,36 @@ static void virtio_device_unrealize(DeviceState *dev, Error **errp)
22922360
vdev->bus_name = NULL;
22932361
}
22942362

2363+
static void virtio_device_free_virtqueues(VirtIODevice *vdev)
2364+
{
2365+
int i;
2366+
if (!vdev->vq) {
2367+
return;
2368+
}
2369+
2370+
for (i = 0; i < VIRTIO_QUEUE_MAX; i++) {
2371+
VRingMemoryRegionCaches *caches;
2372+
if (vdev->vq[i].vring.num == 0) {
2373+
break;
2374+
}
2375+
caches = atomic_read(&vdev->vq[i].vring.caches);
2376+
atomic_set(&vdev->vq[i].vring.caches, NULL);
2377+
virtio_free_region_cache(caches);
2378+
}
2379+
g_free(vdev->vq);
2380+
}
2381+
2382+
static void virtio_device_instance_finalize(Object *obj)
2383+
{
2384+
VirtIODevice *vdev = VIRTIO_DEVICE(obj);
2385+
2386+
memory_listener_unregister(&vdev->listener);
2387+
virtio_device_free_virtqueues(vdev);
2388+
2389+
g_free(vdev->config);
2390+
g_free(vdev->vector_queues);
2391+
}
2392+
22952393
static Property virtio_properties[] = {
22962394
DEFINE_VIRTIO_COMMON_FEATURES(VirtIODevice, host_features),
22972395
DEFINE_PROP_END_OF_LIST(),
@@ -2418,6 +2516,7 @@ static const TypeInfo virtio_device_info = {
24182516
.parent = TYPE_DEVICE,
24192517
.instance_size = sizeof(VirtIODevice),
24202518
.class_init = virtio_device_class_init,
2519+
.instance_finalize = virtio_device_instance_finalize,
24212520
.abstract = true,
24222521
.class_size = sizeof(VirtioDeviceClass),
24232522
};

include/hw/virtio/virtio.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ struct VirtIODevice
8585
uint32_t generation;
8686
int nvectors;
8787
VirtQueue *vq;
88+
MemoryListener listener;
8889
uint16_t device_id;
8990
bool vm_running;
9091
bool broken; /* device in invalid state, needs reset */

0 commit comments

Comments
 (0)