Skip to content

Commit

Permalink
vmnet: stop recieving events when VM is stopped
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: Jason Wang <[email protected]>
  • Loading branch information
Joelle van Dyne authored and jasowang committed Feb 17, 2023
1 parent 0c65ef4 commit 993f71e
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 13 deletions.
48 changes: 35 additions & 13 deletions net/vmnet-common.m
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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;
}
Expand All @@ -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,
Expand Down
2 changes: 2 additions & 0 deletions net/vmnet_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 993f71e

Please sign in to comment.