vmm: fix missed API or debug events

Previously, we were assuming that every time an eventfd notified us,
there was only a single event waiting for us.  This meant that if,
while one API request was being processed, two more arrived, the
second one would not be processed (until the next one arrived, when it
would be processed instead of that event, and so on).  To fix this,
make sure we're processing the number of API and debug requests we've
been told have arrived, rather than just one.  This is easy to
demonstrate by sending lots of API events and adding some sleeps to
make sure multiple events can arrive while each is being processed.

For other uses of eventfd, like the exit event, this doesn't matter —
even if we've received multiple exit events in quick succession, we
only need to exit once.  So I've only made this change where receiving
an event is non-idempotent, i.e. where it matters that we process the
event the right number of times.

Technically, reset requests are also non-idempotent — there's an
observable difference between a VM resetting once, and a VM resetting
once and then immediately resetting again.  But I've left that alone
for now because two resets in immediate succession doesn't sound like
something anyone would ever want to me.

Signed-off-by: Alyssa Ross <hi@alyssa.is>
This commit is contained in:
Alyssa Ross 2022-07-13 09:10:11 +00:00 committed by Rob Bradford
parent 4a1eab11b4
commit a455917db5

View File

@ -1685,252 +1685,254 @@ impl Vmm {
} }
} }
EpollDispatch::Api => { EpollDispatch::Api => {
// Consume the event. // Consume the events.
self.api_evt.read().map_err(Error::EventFdRead)?; for _ in 0..self.api_evt.read().map_err(Error::EventFdRead)? {
// Read from the API receiver channel
let api_request = api_receiver.recv().map_err(Error::ApiRequestRecv)?;
// Read from the API receiver channel info!("API request event: {:?}", api_request);
let api_request = api_receiver.recv().map_err(Error::ApiRequestRecv)?; match api_request {
ApiRequest::VmCreate(config, sender) => {
let response = self
.vm_create(config)
.map_err(ApiError::VmCreate)
.map(|_| ApiResponsePayload::Empty);
info!("API request event: {:?}", api_request); sender.send(response).map_err(Error::ApiResponseSend)?;
match api_request { }
ApiRequest::VmCreate(config, sender) => { ApiRequest::VmDelete(sender) => {
let response = self let response = self
.vm_create(config) .vm_delete()
.map_err(ApiError::VmCreate) .map_err(ApiError::VmDelete)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmDelete(sender) => { ApiRequest::VmBoot(sender) => {
let response = self let response = self
.vm_delete() .vm_boot()
.map_err(ApiError::VmDelete) .map_err(ApiError::VmBoot)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmBoot(sender) => { ApiRequest::VmShutdown(sender) => {
let response = self let response = self
.vm_boot() .vm_shutdown()
.map_err(ApiError::VmBoot) .map_err(ApiError::VmShutdown)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmShutdown(sender) => { ApiRequest::VmReboot(sender) => {
let response = self let response = self
.vm_shutdown() .vm_reboot()
.map_err(ApiError::VmShutdown) .map_err(ApiError::VmReboot)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmReboot(sender) => { ApiRequest::VmInfo(sender) => {
let response = self let response = self
.vm_reboot() .vm_info()
.map_err(ApiError::VmReboot) .map_err(ApiError::VmInfo)
.map(|_| ApiResponsePayload::Empty); .map(ApiResponsePayload::VmInfo);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmInfo(sender) => { ApiRequest::VmmPing(sender) => {
let response = self let response = ApiResponsePayload::VmmPing(self.vmm_ping());
.vm_info()
.map_err(ApiError::VmInfo)
.map(ApiResponsePayload::VmInfo);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(Ok(response)).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmmPing(sender) => { ApiRequest::VmPause(sender) => {
let response = ApiResponsePayload::VmmPing(self.vmm_ping()); let response = self
.vm_pause()
.map_err(ApiError::VmPause)
.map(|_| ApiResponsePayload::Empty);
sender.send(Ok(response)).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmPause(sender) => { ApiRequest::VmResume(sender) => {
let response = self let response = self
.vm_pause() .vm_resume()
.map_err(ApiError::VmPause) .map_err(ApiError::VmResume)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmResume(sender) => { ApiRequest::VmSnapshot(snapshot_data, sender) => {
let response = self let response = self
.vm_resume() .vm_snapshot(&snapshot_data.destination_url)
.map_err(ApiError::VmResume) .map_err(ApiError::VmSnapshot)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmSnapshot(snapshot_data, sender) => { ApiRequest::VmRestore(restore_data, sender) => {
let response = self let response = self
.vm_snapshot(&snapshot_data.destination_url) .vm_restore(restore_data.as_ref().clone())
.map_err(ApiError::VmSnapshot) .map_err(ApiError::VmRestore)
.map(|_| ApiResponsePayload::Empty); .map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmRestore(restore_data, sender) => { #[cfg(feature = "guest_debug")]
let response = self ApiRequest::VmCoredump(coredump_data, sender) => {
.vm_restore(restore_data.as_ref().clone()) let response = self
.map_err(ApiError::VmRestore) .vm_coredump(&coredump_data.destination_url)
.map(|_| ApiResponsePayload::Empty); .map_err(ApiError::VmCoredump)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
#[cfg(feature = "guest_debug")] ApiRequest::VmmShutdown(sender) => {
ApiRequest::VmCoredump(coredump_data, sender) => { let response = self
let response = self .vmm_shutdown()
.vm_coredump(&coredump_data.destination_url) .map_err(ApiError::VmmShutdown)
.map_err(ApiError::VmCoredump) .map(|_| ApiResponsePayload::Empty);
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmmShutdown(sender) => {
let response = self
.vmm_shutdown()
.map_err(ApiError::VmmShutdown)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?; break 'outer;
}
ApiRequest::VmResize(resize_data, sender) => {
let response = self
.vm_resize(
resize_data.desired_vcpus,
resize_data.desired_ram,
resize_data.desired_balloon,
)
.map_err(ApiError::VmResize)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmResizeZone(resize_zone_data, sender) => {
let response = self
.vm_resize_zone(
resize_zone_data.id.clone(),
resize_zone_data.desired_ram,
)
.map_err(ApiError::VmResizeZone)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddDevice(add_device_data, sender) => {
let response = self
.vm_add_device(add_device_data.as_ref().clone())
.map_err(ApiError::VmAddDevice)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddUserDevice(add_device_data, sender) => {
let response = self
.vm_add_user_device(add_device_data.as_ref().clone())
.map_err(ApiError::VmAddUserDevice)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmRemoveDevice(remove_device_data, sender) => {
let response = self
.vm_remove_device(remove_device_data.id.clone())
.map_err(ApiError::VmRemoveDevice)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddDisk(add_disk_data, sender) => {
let response = self
.vm_add_disk(add_disk_data.as_ref().clone())
.map_err(ApiError::VmAddDisk)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddFs(add_fs_data, sender) => {
let response = self
.vm_add_fs(add_fs_data.as_ref().clone())
.map_err(ApiError::VmAddFs)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddPmem(add_pmem_data, sender) => {
let response = self
.vm_add_pmem(add_pmem_data.as_ref().clone())
.map_err(ApiError::VmAddPmem)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddNet(add_net_data, sender) => {
let response = self
.vm_add_net(add_net_data.as_ref().clone())
.map_err(ApiError::VmAddNet)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddVdpa(add_vdpa_data, sender) => {
let response = self
.vm_add_vdpa(add_vdpa_data.as_ref().clone())
.map_err(ApiError::VmAddVdpa)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddVsock(add_vsock_data, sender) => {
let response = self
.vm_add_vsock(add_vsock_data.as_ref().clone())
.map_err(ApiError::VmAddVsock)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmCounters(sender) => {
let response = self
.vm_counters()
.map_err(ApiError::VmInfo)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmReceiveMigration(receive_migration_data, sender) => {
let response = self
.vm_receive_migration(
receive_migration_data.as_ref().clone(),
)
.map_err(ApiError::VmReceiveMigration)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmSendMigration(send_migration_data, sender) => {
let response = self
.vm_send_migration(send_migration_data.as_ref().clone())
.map_err(ApiError::VmSendMigration)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmPowerButton(sender) => {
let response = self
.vm_power_button()
.map_err(ApiError::VmPowerButton)
.map(|_| ApiResponsePayload::Empty);
break 'outer; sender.send(response).map_err(Error::ApiResponseSend)?;
} }
ApiRequest::VmResize(resize_data, sender) => {
let response = self
.vm_resize(
resize_data.desired_vcpus,
resize_data.desired_ram,
resize_data.desired_balloon,
)
.map_err(ApiError::VmResize)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmResizeZone(resize_zone_data, sender) => {
let response = self
.vm_resize_zone(
resize_zone_data.id.clone(),
resize_zone_data.desired_ram,
)
.map_err(ApiError::VmResizeZone)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddDevice(add_device_data, sender) => {
let response = self
.vm_add_device(add_device_data.as_ref().clone())
.map_err(ApiError::VmAddDevice)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddUserDevice(add_device_data, sender) => {
let response = self
.vm_add_user_device(add_device_data.as_ref().clone())
.map_err(ApiError::VmAddUserDevice)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmRemoveDevice(remove_device_data, sender) => {
let response = self
.vm_remove_device(remove_device_data.id.clone())
.map_err(ApiError::VmRemoveDevice)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddDisk(add_disk_data, sender) => {
let response = self
.vm_add_disk(add_disk_data.as_ref().clone())
.map_err(ApiError::VmAddDisk)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddFs(add_fs_data, sender) => {
let response = self
.vm_add_fs(add_fs_data.as_ref().clone())
.map_err(ApiError::VmAddFs)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddPmem(add_pmem_data, sender) => {
let response = self
.vm_add_pmem(add_pmem_data.as_ref().clone())
.map_err(ApiError::VmAddPmem)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddNet(add_net_data, sender) => {
let response = self
.vm_add_net(add_net_data.as_ref().clone())
.map_err(ApiError::VmAddNet)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddVdpa(add_vdpa_data, sender) => {
let response = self
.vm_add_vdpa(add_vdpa_data.as_ref().clone())
.map_err(ApiError::VmAddVdpa)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmAddVsock(add_vsock_data, sender) => {
let response = self
.vm_add_vsock(add_vsock_data.as_ref().clone())
.map_err(ApiError::VmAddVsock)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmCounters(sender) => {
let response = self
.vm_counters()
.map_err(ApiError::VmInfo)
.map(ApiResponsePayload::VmAction);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmReceiveMigration(receive_migration_data, sender) => {
let response = self
.vm_receive_migration(receive_migration_data.as_ref().clone())
.map_err(ApiError::VmReceiveMigration)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmSendMigration(send_migration_data, sender) => {
let response = self
.vm_send_migration(send_migration_data.as_ref().clone())
.map_err(ApiError::VmSendMigration)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
}
ApiRequest::VmPowerButton(sender) => {
let response = self
.vm_power_button()
.map_err(ApiError::VmPowerButton)
.map(|_| ApiResponsePayload::Empty);
sender.send(response).map_err(Error::ApiResponseSend)?;
} }
} }
} }
#[cfg(feature = "gdb")] #[cfg(feature = "gdb")]
EpollDispatch::Debug => { EpollDispatch::Debug => {
// Consume the event. // Consume the events.
self.debug_evt.read().map_err(Error::EventFdRead)?; for _ in 0..self.debug_evt.read().map_err(Error::EventFdRead)? {
// Read from the API receiver channel
let gdb_request = gdb_receiver.recv().map_err(Error::GdbRequestRecv)?;
// Read from the API receiver channel let response = if let Some(ref mut vm) = self.vm {
let gdb_request = gdb_receiver.recv().map_err(Error::GdbRequestRecv)?; vm.debug_request(&gdb_request.payload, gdb_request.cpu_id)
} else {
Err(VmError::VmNotRunning)
}
.map_err(gdb::Error::Vm);
let response = if let Some(ref mut vm) = self.vm { gdb_request
vm.debug_request(&gdb_request.payload, gdb_request.cpu_id) .sender
} else { .send(response)
Err(VmError::VmNotRunning) .map_err(Error::GdbResponseSend)?;
} }
.map_err(gdb::Error::Vm);
gdb_request
.sender
.send(response)
.map_err(Error::GdbResponseSend)?;
} }
#[cfg(not(feature = "gdb"))] #[cfg(not(feature = "gdb"))]
EpollDispatch::Debug => {} EpollDispatch::Debug => {}