qemu_command_builder/
fsdev.rs

1use crate::to_command::ToArg;
2use crate::to_command::ToCommand;
3use bon::Builder;
4use std::path::PathBuf;
5
6#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
7pub enum SecurityModel {
8    Passthrough,
9    MappedXAttr,
10    MappedFile,
11    None,
12}
13
14impl ToArg for SecurityModel {
15    fn to_arg(&self) -> &str {
16        match self {
17            SecurityModel::Passthrough => "passthrough",
18            SecurityModel::MappedXAttr => "mapped-xattr",
19            SecurityModel::MappedFile => "mapped-file",
20            SecurityModel::None => "none",
21        }
22    }
23}
24/// Accesses to the filesystem are done by QEMU
25#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq, Builder)]
26pub struct FsDevLocal {
27    /// Specifies identifier for this device.
28    id: String,
29
30    /// Specifies the export path for the file system device. Files
31    /// under this path will be available to the 9p client on the guest.
32    path: PathBuf,
33
34    /// Specifies the security model to be used for this export path.
35    /// Supported security models are "passthrough", "mapped-xattr",
36    /// "mapped-file" and "none". In "passthrough" security model, files
37    /// are stored using the same credentials as they are created on the
38    /// guest. This requires QEMU to run as root. In "mapped-xattr"
39    /// security model, some of the file attributes like uid, gid, mode
40    /// bits and link target are stored as file attributes. For
41    /// "mapped-file" these attributes are stored in the hidden
42    /// .virtfs\_metadata directory. Directories exported by this
43    /// security model cannot interact with other unix tools. "none"
44    /// security model is same as passthrough except the sever won't
45    /// report failures if it fails to set file attributes like
46    /// ownership. Security model is mandatory only for local fsdriver.
47    security_model: SecurityModel,
48
49    /// This is an optional argument. The only supported value is
50    /// "immediate". This means that host page cache will be used to
51    /// read and write data but write notification will be sent to the
52    /// guest only when the data has been reported as written by the
53    /// storage subsystem.
54    writeout: Option<()>,
55
56    /// Enables exporting 9p share as a readonly mount for guests. By
57    /// default read-write access is given.
58    readonly: Option<()>,
59
60    /// Specifies the default mode for newly created files on the host.
61    /// Works only with security models "mapped-xattr" and
62    /// "mapped-file".
63    fmode: Option<String>,
64
65    /// Specifies the default mode for newly created directories on the
66    /// host. Works only with security models "mapped-xattr" and
67    /// "mapped-file".
68    dmode: Option<String>,
69
70    /// Specify bandwidth throttling limits in bytes per second, either
71    /// for all request types or for reads or writes only.
72    throttling_bps_total: Option<usize>,
73    throttling_bps_read: Option<usize>,
74    throttling_bps_write: Option<usize>,
75
76    /// Specify bursts in bytes per second, either for all request types
77    /// or for reads or writes only. Bursts allow the guest I/O to spike
78    /// above the limit temporarily.
79    throttling_bps_total_max: Option<usize>,
80    bps_read_max: Option<usize>,
81    bps_write_max: Option<usize>,
82
83    /// Specify request rate limits in requests per second, either for
84    /// all request types or for reads or writes only.
85    throttling_iops_total: Option<usize>,
86    throttling_iops_read: Option<usize>,
87    throttling_iops_write: Option<usize>,
88
89    /// Specify bursts in requests per second, either for all request
90    /// types or for reads or writes only. Bursts allow the guest I/O to
91    /// spike above the limit temporarily.
92    throttling_iops_total_max: Option<usize>,
93    throttling_iops_read_max: Option<usize>,
94    throttling_iops_write_max: Option<usize>,
95
96    /// Let every is bytes of a request count as a new request for iops
97    /// throttling purposes.
98    throttling_iops_size: Option<usize>,
99}
100
101/// Synthetic filesystem, only used by QTests.
102#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
103pub struct FsDevSynth {
104    /// Specifies identifier for this device.
105    id: String,
106}
107
108/// Define a new file system device
109///
110/// TODO
111/// - device virtio-9p-type integration
112#[derive(Debug, Clone, Hash, Ord, PartialOrd, Eq, PartialEq)]
113pub enum FsDev {
114    Local(FsDevLocal),
115    Synth(FsDevSynth),
116}
117
118impl ToCommand for FsDev {
119    fn to_command(&self) -> Vec<String> {
120        let mut cmd = vec![];
121
122        cmd.push("-fsdev".to_string());
123
124        match self {
125            FsDev::Local(local) => {
126                let mut arg = vec![];
127
128                arg.push(format!("local,id={}", local.id));
129
130                arg.push(format!(",path={}", local.path.display()));
131
132                arg.push(format!(",security-model={}", local.security_model.to_arg()));
133
134                if local.writeout.is_some() {
135                    arg.push("writeout=immediate".to_string());
136                }
137
138                if local.readonly.is_some() {
139                    arg.push("readonly=on".to_string());
140                }
141
142                if let Some(fmode) = &local.fmode {
143                    arg.push(format!("fmode={}", fmode));
144                }
145
146                if let Some(dmode) = &local.dmode {
147                    arg.push(format!("dmode={}", dmode));
148                }
149
150                if let Some(throttling_bps_total) = local.throttling_bps_total {
151                    arg.push(format!("throttling.bps-total={}", throttling_bps_total));
152                }
153                if let Some(throttling_bps_read) = local.throttling_bps_read {
154                    arg.push(format!("throttling.bps-read={}", throttling_bps_read));
155                }
156                if let Some(throttling_bps_write) = local.throttling_bps_write {
157                    arg.push(format!("throttling.bps-write={}", throttling_bps_write));
158                }
159
160                if let Some(throttling_bps_total_max) = local.throttling_bps_total_max {
161                    arg.push(format!(
162                        "throttling.bps-total-max={}",
163                        throttling_bps_total_max
164                    ));
165                }
166                if let Some(bps_read_max) = local.bps_read_max {
167                    arg.push(format!("bps-read-max={}", bps_read_max));
168                }
169                if let Some(bps_write_max) = local.bps_write_max {
170                    arg.push(format!("bps-write-max={}", bps_write_max));
171                }
172
173                if let Some(throttling_iops_total) = local.throttling_iops_total {
174                    arg.push(format!("throttling.iops-total={}", throttling_iops_total));
175                }
176                if let Some(throttling_iops_read) = local.throttling_iops_read {
177                    arg.push(format!("throttling.iops-read={}", throttling_iops_read));
178                }
179                if let Some(throttling_iops_write) = local.throttling_iops_write {
180                    arg.push(format!("throttling.iops-write={}", throttling_iops_write));
181                }
182
183                if let Some(throttling_ios_total_max) = local.throttling_iops_total_max {
184                    arg.push(format!(
185                        "throttling.ios-total-max={}",
186                        throttling_ios_total_max
187                    ));
188                }
189                if let Some(throttling_iops_read_max) = local.throttling_iops_read_max {
190                    arg.push(format!(
191                        "throttling.iops-read-max={}",
192                        throttling_iops_read_max
193                    ));
194                }
195                if let Some(throttling_iops_write_max) = local.throttling_iops_write_max {
196                    arg.push(format!(
197                        "throttling.iops-write-max={}",
198                        throttling_iops_write_max
199                    ));
200                }
201
202                if let Some(throttling_iops_size) = local.throttling_iops_size {
203                    arg.push(format!("throttling.iops-size={}", throttling_iops_size));
204                }
205                cmd.push(arg.join(","));
206            }
207            FsDev::Synth(synth) => {
208                let mut arg = String::new();
209                arg.push_str("synth,id=");
210                arg.push_str(synth.id.to_string().as_str());
211                cmd.push(arg);
212            }
213        }
214
215        cmd
216    }
217}