• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use anyhow::bail;
6 use anyhow::Context;
7 use argh::FromArgs;
8 use base::info;
9 use cros_async::Executor;
10 use hypervisor::ProtectionType;
11 
12 use crate::virtio::base_features;
13 use crate::virtio::block::block::DiskOption;
14 use crate::virtio::vhost::user::device::listener::sys::VhostUserListener;
15 use crate::virtio::vhost::user::device::listener::VhostUserListenerTrait;
16 use crate::virtio::vhost::user::VhostUserDevice;
17 use crate::virtio::BlockAsync;
18 
19 #[derive(FromArgs)]
20 #[argh(subcommand, name = "block")]
21 /// Block device
22 pub struct Options {
23     #[argh(option, arg_name = "PATH<:read-only>")]
24     /// path and options of the disk file.
25     file: String,
26     #[argh(option, arg_name = "PATH")]
27     /// path to a vhost-user socket
28     socket: Option<String>,
29     #[argh(option, arg_name = "STRING")]
30     /// VFIO-PCI device name (e.g. '0000:00:07.0')
31     vfio: Option<String>,
32 }
33 
34 /// Starts a vhost-user block device.
35 /// Returns an error if the given `args` is invalid or the device fails to run.
start_device(opts: Options) -> anyhow::Result<()>36 pub fn start_device(opts: Options) -> anyhow::Result<()> {
37     if !(opts.socket.is_some() ^ opts.vfio.is_some()) {
38         bail!("Exactly one of `--socket` or `--vfio` is required");
39     }
40 
41     let ex = Executor::new().context("failed to create executor")?;
42 
43     let mut fileopts = opts.file.split(":").collect::<Vec<_>>();
44     let filename = fileopts.remove(0);
45 
46     let disk = DiskOption {
47         path: filename.into(),
48         read_only: fileopts.contains(&"read-only"),
49         root: false,
50         sparse: false,
51         direct: false,
52         block_size: 512,
53         id: None,
54         multiple_workers: false,
55         async_executor: None,
56     };
57 
58     let block = Box::new(BlockAsync::new(
59         base_features(ProtectionType::Unprotected),
60         disk.open()?,
61         disk.read_only,
62         disk.sparse,
63         disk.block_size,
64         false,
65         None,
66         None,
67         None,
68         None,
69         None,
70     )?);
71 
72     let listener = VhostUserListener::new_from_socket_or_vfio(
73         &opts.socket,
74         &opts.vfio,
75         block.max_queue_num(),
76         None,
77     )?;
78     info!("vhost-user disk device ready, starting run loop...");
79 
80     listener.run_device(ex, block)
81 }
82