gpio: re-arrange start_backend to handle config errors

The compiler warns with the move that:

  error: variants `CouldNotOpenDevice`, `CouldNotCreateGpioController`, `CouldNotCreateBackend`, and `CouldNotCreateDaemon` are never constructed
    --> crates/vhost-device-gpio/src/backend.rs:43:5
     |
  31 | pub(crate) enum Error {
     |                 ----- variants in this enum
  ...
  43 |     CouldNotOpenDevice(crate::gpio::Error),
     |     ^^^^^^^^^^^^^^^^^^
  44 |     #[error("Could not create gpio controller: {0}")]
  45 |     CouldNotCreateGpioController(crate::gpio::Error),
     |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  46 |     #[error("Could not create gpio backend: {0}")]
  47 |     CouldNotCreateBackend(crate::vhu_gpio::Error),
     |     ^^^^^^^^^^^^^^^^^^^^^
  48 |     #[error("Could not create daemon: {0}")]
  49 |     CouldNotCreateDaemon(vhost_user_backend::Error),
     |     ^^^^^^^^^^^^^^^^^^^^
     |
     = note: `Error` has a derived impl for the trait `Debug`, but this is intentionally ignored during dead code analysis
     = note: `-D dead-code` implied by `-D warnings`

  error: could not compile `vhost-device-gpio` (bin "vhost-device-gpio") due to previous error

Because we never really care about failure within the spawn loop.
Handle this by ensuring errors propagate back to the caller.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
This commit is contained in:
Alex Bennée 2023-09-14 14:12:35 +01:00 committed by Alex Bennée
parent e4aefda817
commit 026cf0e532

View File

@ -174,9 +174,11 @@ impl TryFrom<GpioArgs> for GpioConfiguration {
}
}
fn start_device_backend<D: GpioDevice>(device: D, socket: String) {
let controller = GpioController::<D>::new(device).unwrap();
let backend = Arc::new(RwLock::new(VhostUserGpioBackend::new(controller).unwrap()));
fn start_device_backend<D: GpioDevice>(device: D, socket: String) -> Result<()> {
let controller = GpioController::new(device).map_err(Error::CouldNotCreateGpioController)?;
let backend = Arc::new(RwLock::new(
VhostUserGpioBackend::new(controller).map_err(Error::CouldNotCreateBackend)?,
));
let listener = Listener::new(socket, true).unwrap();
let mut daemon = VhostUserDaemon::new(
@ -184,7 +186,7 @@ fn start_device_backend<D: GpioDevice>(device: D, socket: String) {
backend.clone(),
GuestMemoryAtomic::new(GuestMemoryMmap::new()),
)
.unwrap();
.map_err(Error::CouldNotCreateDaemon)?;
daemon.start(listener).unwrap();
@ -201,6 +203,7 @@ fn start_device_backend<D: GpioDevice>(device: D, socket: String) {
}
// No matter the result, we need to shut down the worker thread.
backend.read().unwrap().exit_event.write(1).unwrap();
Ok(())
}
fn start_backend(args: GpioArgs) -> Result<()> {
@ -212,23 +215,23 @@ fn start_backend(args: GpioArgs) -> Result<()> {
let cfg = config.devices.inner[i];
let handle: JoinHandle<Result<()>> = spawn(move || loop {
// A separate thread is spawned for each socket and can connect to a separate guest.
// These are run in an infinite loop to not require the daemon to be restarted once a
// guest exits.
// A separate thread is spawned for each socket and can
// connect to a separate guest. These are run in an
// infinite loop to not require the daemon to be restarted
// once a guest exits.
//
// There isn't much value in complicating code here to return an error from the
// threads, and so the code uses unwrap() instead. The panic on a thread won't cause
// trouble to other threads/guests or the main() function and should be safe for the
// daemon.
// However if we fail to spawn (due to bad config or
// other reason) we will bail out of the spawning and
// propagate the error back to gpio_init().
match cfg {
GpioDeviceType::PhysicalDevice { id } => {
let controller = PhysDevice::open(id).unwrap();
start_device_backend(controller, socket.clone());
let controller = PhysDevice::open(id).map_err(Error::CouldNotOpenDevice)?;
start_device_backend(controller, socket.clone())?;
}
#[cfg(any(test, feature = "mock_gpio"))]
GpioDeviceType::SimulatedDevice { num_gpios } => {
let controller = MockGpioDevice::open(num_gpios).unwrap();
start_device_backend(controller, socket.clone());
let controller = MockGpioDevice::open(num_gpios).unwrap(); // cannot fail
start_device_backend(controller, socket.clone())?;
}
};
});