arcbox_virtio_fs/device/
mod.rs1mod queue;
4mod virtio_device;
5
6#[cfg(test)]
7mod tests;
8
9use std::sync::Arc;
10
11use arcbox_virtio_core::error::{Result, VirtioError};
12use arcbox_virtio_core::queue::VirtQueue;
13use arcbox_virtio_core::virtio_bindings;
14
15use crate::handler::FuseRequestHandler;
16use crate::request::FuseResponse;
17use crate::session::FuseSession;
18
19#[derive(Debug, Clone)]
21pub struct FsConfig {
22 pub tag: String,
24 pub num_queues: u32,
26 pub queue_size: u16,
28 pub shared_dir: String,
30}
31
32impl Default for FsConfig {
33 fn default() -> Self {
34 Self {
35 tag: "arcbox".to_string(),
36 num_queues: 1,
37 queue_size: 1024,
38 shared_dir: String::new(),
39 }
40 }
41}
42
43pub struct VirtioFs {
48 config: FsConfig,
49 features: u64,
50 acked_features: u64,
51 session: FuseSession,
53 handler: Option<Arc<dyn FuseRequestHandler>>,
55 request_queues: Vec<VirtQueue>,
57 activated: bool,
59 last_avail_idx_q1: u16,
61}
62
63impl VirtioFs {
64 pub const FEATURE_NOTIFICATION: u64 = 1 << 0;
66 pub const FEATURE_VERSION_1: u64 = 1 << virtio_bindings::virtio_config::VIRTIO_F_VERSION_1;
68
69 pub(crate) const FUSE_INIT: u32 = 26;
71
72 const FUSE_DESTROY: u32 = 38;
74
75 #[must_use]
77 pub fn new(config: FsConfig) -> Self {
78 Self {
79 config,
80 features: Self::FEATURE_VERSION_1,
81 acked_features: 0,
82 session: FuseSession::new(),
83 handler: None,
84 request_queues: Vec::new(),
85 activated: false,
86 last_avail_idx_q1: 0,
87 }
88 }
89
90 #[must_use]
92 pub fn with_handler(config: FsConfig, handler: Arc<dyn FuseRequestHandler>) -> Self {
93 Self {
94 config,
95 features: Self::FEATURE_VERSION_1,
96 acked_features: 0,
97 session: FuseSession::new(),
98 handler: Some(handler),
99 request_queues: Vec::new(),
100 activated: false,
101 last_avail_idx_q1: 0,
102 }
103 }
104
105 pub fn set_handler(&mut self, handler: Arc<dyn FuseRequestHandler>) {
107 self.handler = Some(handler);
108 }
109
110 #[must_use]
112 pub fn handler(&self) -> Option<&Arc<dyn FuseRequestHandler>> {
113 self.handler.as_ref()
114 }
115
116 #[must_use]
118 pub const fn session(&self) -> &FuseSession {
119 &self.session
120 }
121
122 #[must_use]
124 pub const fn is_activated(&self) -> bool {
125 self.activated
126 }
127
128 #[must_use]
130 pub fn tag(&self) -> &str {
131 &self.config.tag
132 }
133
134 #[must_use]
136 pub fn shared_dir(&self) -> &str {
137 &self.config.shared_dir
138 }
139
140 #[must_use]
142 pub const fn num_queues(&self) -> u32 {
143 self.config.num_queues
144 }
145
146 #[must_use]
148 pub const fn queue_size(&self) -> u16 {
149 self.config.queue_size
150 }
151
152 pub fn process_request(&mut self, request: &[u8]) -> Result<Vec<u8>> {
168 if request.len() < 40 {
169 return Err(VirtioError::DeviceError {
170 device: "fs".to_string(),
171 message: "FUSE request too small".to_string(),
172 });
173 }
174
175 let opcode = u32::from_le_bytes([request[4], request[5], request[6], request[7]]);
177
178 let unique = u64::from_le_bytes([
180 request[8],
181 request[9],
182 request[10],
183 request[11],
184 request[12],
185 request[13],
186 request[14],
187 request[15],
188 ]);
189
190 match opcode {
191 Self::FUSE_INIT => {
192 let response = self.session.handle_init(request)?;
193
194 if let Some(handler) = &self.handler {
195 handler.on_init(&self.session);
196 }
197
198 Ok(response)
199 }
200 Self::FUSE_DESTROY => {
201 self.session.reset();
202
203 if let Some(handler) = &self.handler {
204 handler.on_destroy();
205 }
206
207 Ok(FuseResponse::new(unique, vec![]).into_data())
208 }
209 _ => {
210 if !self.session.is_initialized() {
211 tracing::warn!("FUSE request before INIT: opcode={}", opcode);
212 return Ok(FuseResponse::error(unique, libc::EINVAL).into_data());
213 }
214
215 if let Some(handler) = &self.handler {
216 handler.handle_request(request)
217 } else {
218 Ok(FuseResponse::error(unique, libc::ENOSYS).into_data())
220 }
221 }
222 }
223 }
224}