qemu_command_builder/
blockdev.rs

1use std::collections::HashMap;
2
3use bon::Builder;
4
5use crate::common::{IgnoreUnmap, OnOff, OnOffUnmap};
6use crate::to_command::{ToArg, ToCommand};
7
8/// Define a new block driver node. Some of the options apply to all
9/// block drivers, other options are only accepted for a specific block
10/// driver. See below for a list of generic options and options for the
11/// most common block drivers.
12///
13/// Options that expect a reference to another node (e.g. ``file``) can
14/// be given in two ways. Either you specify the node name of an already
15/// existing node (file=node-name), or you define a new node inline,
16/// adding options for the referenced node after a dot
17/// (file.filename=path,file.aio=native).
18///
19/// A block driver node created with ``-blockdev`` can be used for a
20/// guest device by specifying its node name for the ``drive`` property
21/// in a ``-device`` argument that defines a block device.
22///
23/// TODO
24/// - constrain driver opts
25#[derive(Builder)]
26pub struct BlockDev {
27    /// Specifies the block driver to use for the given node.
28    pub driver: String,
29
30    /// This defines the name of the block driver node by which it
31    /// will be referenced later. The name must be unique, i.e. it
32    /// must not match the name of a different block driver node, or
33    /// (if you use ``-drive`` as well) the ID of a drive.
34    ///
35    /// If no node name is specified, it is automatically generated.
36    /// The generated node name is not intended to be predictable
37    /// and changes between QEMU invocations. For the top level, an
38    /// explicit node name must be specified.
39    pub node_name: Option<String>,
40
41    /// discard is one of "ignore" (or "off") or "unmap" (or "on")
42    /// and controls whether ``discard`` (also known as ``trim`` or
43    /// ``unmap``) requests are ignored or passed to the filesystem.
44    /// Some machine types may not support discard requests.
45    pub discard: Option<IgnoreUnmap>,
46
47    /// The host page cache can be avoided with ``cache.direct=on``.
48    /// This will attempt to do disk IO directly to the guest's
49    /// memory. QEMU may still perform an internal copy of the data.
50    pub cache_direct: Option<OnOff>,
51
52    /// In case you don't care about data integrity over host
53    /// failures, you can use ``cache.no-flush=on``. This option
54    /// tells QEMU that it never needs to write any data to the disk
55    /// but can instead keep things in cache. If anything goes
56    /// wrong, like your host losing power, the disk storage getting
57    /// disconnected accidentally, etc. your image will most
58    /// probably be rendered unusable.
59    pub cache_no_flush: Option<OnOff>,
60
61    /// Open the node read-only. Guest write attempts will fail.
62    ///
63    /// Note that some block drivers support only read-only access,
64    /// either generally or in certain configurations. In this case,
65    /// the default value ``read-only=off`` does not work and the
66    /// option must be specified explicitly.
67    pub read_only: Option<OnOff>,
68
69    /// If ``auto-read-only=on`` is set, QEMU may fall back to
70    /// read-only usage even when ``read-only=off`` is requested, or
71    /// even switch between modes as needed, e.g. depending on
72    /// whether the image file is writable or whether a writing user
73    /// is attached to the node.
74    pub auto_read_only: Option<OnOff>,
75
76    /// Override the image locking system of QEMU by forcing the
77    /// node to utilize weaker shared access for permissions where
78    /// it would normally request exclusive access. When there is
79    /// the potential for multiple instances to have the same file
80    /// open (whether this invocation of QEMU is the first or the
81    /// second instance), both instances must permit shared access
82    /// for the second instance to succeed at opening the file.
83    ///
84    /// Enabling ``force-share=on`` requires ``read-only=on``.
85    pub force_share: Option<OnOff>,
86
87    /// detect-zeroes is "off", "on" or "unmap" and enables the
88    /// automatic conversion of plain zero writes by the OS to
89    /// driver specific optimized zero write commands. You may even
90    /// choose "unmap" if discard is set to "unmap" to allow a zero
91    /// write to be converted to an ``unmap`` operation.
92    pub detect_zeroes: Option<OnOffUnmap>,
93
94    pub driver_opts: Option<HashMap<String, String>>,
95}
96
97impl ToCommand for BlockDev {
98    fn to_command(&self) -> Vec<String> {
99        let mut cmd = vec![];
100
101        cmd.push("-blockdev".to_string());
102
103        let mut args = vec![];
104
105        args.push(format!("driver={}", self.driver));
106        if let Some(node_name) = &self.node_name {
107            args.push(format!("node-name={}", node_name));
108        }
109        if let Some(discard) = &self.discard {
110            args.push(format!("discard={}", discard.to_arg()));
111        }
112        if let Some(cache_direct) = &self.cache_direct {
113            args.push(format!("cache.direct={}", cache_direct.to_arg()));
114        }
115        if let Some(cache_no_flush) = &self.cache_no_flush {
116            args.push(format!("cache.no-flush={}", cache_no_flush.to_arg()));
117        }
118        if let Some(read_only) = &self.read_only {
119            args.push(format!("read-only={}", read_only.to_arg()));
120        }
121        if let Some(auto_read_only) = &self.auto_read_only {
122            args.push(format!("auto-read-only={}", auto_read_only.to_arg()));
123        }
124        if let Some(force_share) = &self.force_share {
125            args.push(format!("force-share={}", force_share.to_arg()));
126        }
127        if let Some(detect_zeroes) = &self.detect_zeroes {
128            args.push(format!("detect-zeroes={}", detect_zeroes.to_arg()));
129        }
130        if let Some(driver_opts) = &self.driver_opts {
131            for (key, val) in driver_opts {
132                args.push(format!("{}={}", key, val));
133            }
134        }
135
136        cmd.push(args.join(","));
137
138        cmd
139    }
140}