vmnet: stop recieving events when VM is stopped
When the VM is stopped using the HMP command "stop", soon the handler will stop reading from the vmnet interface. This causes a flood of `VMNET_INTERFACE_PACKETS_AVAILABLE` events to arrive and puts the host CPU at 100%. We fix this by removing the event handler from vmnet when the VM is no longer in a running state and restore it when we return to a running state. Signed-off-by: Joelle van Dyne <j@getutm.app> Signed-off-by: Jason Wang <jasowang@redhat.com>
This commit is contained in:
parent
0c65ef4fbb
commit
993f71ee33
@ -17,6 +17,7 @@
|
||||
#include "clients.h"
|
||||
#include "qemu/error-report.h"
|
||||
#include "qapi/error.h"
|
||||
#include "sysemu/runstate.h"
|
||||
|
||||
#include <vmnet/vmnet.h>
|
||||
#include <dispatch/dispatch.h>
|
||||
@ -242,6 +243,35 @@ static void vmnet_bufs_init(VmnetState *s)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called on state change to un-register/re-register handlers
|
||||
*/
|
||||
static void vmnet_vm_state_change_cb(void *opaque, bool running, RunState state)
|
||||
{
|
||||
VmnetState *s = opaque;
|
||||
|
||||
if (running) {
|
||||
vmnet_interface_set_event_callback(
|
||||
s->vmnet_if,
|
||||
VMNET_INTERFACE_PACKETS_AVAILABLE,
|
||||
s->if_queue,
|
||||
^(interface_event_t event_id, xpc_object_t event) {
|
||||
assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
|
||||
/*
|
||||
* This function is being called from a non qemu thread, so
|
||||
* we only schedule a BH, and do the rest of the io completion
|
||||
* handling from vmnet_send_bh() which runs in a qemu context.
|
||||
*/
|
||||
qemu_bh_schedule(s->send_bh);
|
||||
});
|
||||
} else {
|
||||
vmnet_interface_set_event_callback(
|
||||
s->vmnet_if,
|
||||
VMNET_INTERFACE_PACKETS_AVAILABLE,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int vmnet_if_create(NetClientState *nc,
|
||||
xpc_object_t if_desc,
|
||||
@ -329,19 +359,9 @@ int vmnet_if_create(NetClientState *nc,
|
||||
s->packets_send_current_pos = 0;
|
||||
s->packets_send_end_pos = 0;
|
||||
|
||||
vmnet_interface_set_event_callback(
|
||||
s->vmnet_if,
|
||||
VMNET_INTERFACE_PACKETS_AVAILABLE,
|
||||
s->if_queue,
|
||||
^(interface_event_t event_id, xpc_object_t event) {
|
||||
assert(event_id == VMNET_INTERFACE_PACKETS_AVAILABLE);
|
||||
/*
|
||||
* This function is being called from a non qemu thread, so
|
||||
* we only schedule a BH, and do the rest of the io completion
|
||||
* handling from vmnet_send_bh() which runs in a qemu context.
|
||||
*/
|
||||
qemu_bh_schedule(s->send_bh);
|
||||
});
|
||||
vmnet_vm_state_change_cb(s, 1, RUN_STATE_RUNNING);
|
||||
|
||||
s->change = qemu_add_vm_change_state_handler(vmnet_vm_state_change_cb, s);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -356,6 +376,8 @@ void vmnet_cleanup_common(NetClientState *nc)
|
||||
return;
|
||||
}
|
||||
|
||||
vmnet_vm_state_change_cb(s, 0, RUN_STATE_SHUTDOWN);
|
||||
qemu_del_vm_change_state_handler(s->change);
|
||||
if_stopped_sem = dispatch_semaphore_create(0);
|
||||
vmnet_stop_interface(
|
||||
s->vmnet_if,
|
||||
|
@ -45,6 +45,8 @@ typedef struct VmnetState {
|
||||
int packets_send_end_pos;
|
||||
|
||||
struct iovec iov_buf[VMNET_PACKETS_LIMIT];
|
||||
|
||||
VMChangeStateEntry *change;
|
||||
} VmnetState;
|
||||
|
||||
const char *vmnet_status_map_str(vmnet_return_t status);
|
||||
|
Loading…
Reference in New Issue
Block a user