1 // Copyright 2023 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 std::time::Duration;
6
7 #[cfg(feature = "arc_quota")]
8 use serde::de::Error;
9 use serde::Deserialize;
10 use serde::Deserializer;
11 use serde::Serialize;
12 use serde_keyvalue::FromKeyValues;
13
14 /// The caching policy that the file system should report to the FUSE client. By default the FUSE
15 /// protocol uses close-to-open consistency. This means that any cached contents of the file are
16 /// invalidated the next time that file is opened.
17 #[derive(Debug, Clone, Default, Eq, PartialEq, Serialize, Deserialize, FromKeyValues)]
18 #[serde(rename_all = "kebab-case")]
19 pub enum CachePolicy {
20 /// The client should never cache file data and all I/O should be directly forwarded to the
21 /// server. This policy must be selected when file contents may change without the knowledge of
22 /// the FUSE client (i.e., the file system does not have exclusive access to the directory).
23 Never,
24
25 /// The client is free to choose when and how to cache file data. This is the default policy
26 /// and uses close-to-open consistency as described in the enum documentation.
27 #[default]
28 Auto,
29
30 /// The client should always cache file data. This means that the FUSE client will not
31 /// invalidate any cached data that was returned by the file system the last time the file was
32 /// opened. This policy should only be selected when the file system has exclusive access to
33 /// the directory.
34 Always,
35 }
36
config_default_timeout() -> Duration37 const fn config_default_timeout() -> Duration {
38 Duration::from_secs(5)
39 }
40
config_default_negative_timeout() -> Duration41 const fn config_default_negative_timeout() -> Duration {
42 Duration::ZERO
43 }
44
config_default_posix_acl() -> bool45 const fn config_default_posix_acl() -> bool {
46 true
47 }
48
deserialize_timeout<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Duration, D::Error>49 fn deserialize_timeout<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Duration, D::Error> {
50 let secs = u64::deserialize(deserializer)?;
51
52 Ok(Duration::from_secs(secs))
53 }
54
55 #[cfg(feature = "arc_quota")]
deserialize_privileged_quota_uids<'de, D: Deserializer<'de>>( deserializer: D, ) -> Result<Vec<libc::uid_t>, D::Error>56 fn deserialize_privileged_quota_uids<'de, D: Deserializer<'de>>(
57 deserializer: D,
58 ) -> Result<Vec<libc::uid_t>, D::Error> {
59 // space-separated list
60 let s: &str = serde::Deserialize::deserialize(deserializer)?;
61 s.split(" ")
62 .map(|s| {
63 s.parse::<libc::uid_t>().map_err(|e| {
64 <D as Deserializer>::Error::custom(format!(
65 "failed to parse priviledged quota uid {s}: {e}"
66 ))
67 })
68 })
69 .collect()
70 }
71
72 /// Options that configure the behavior of the file system.
73 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, FromKeyValues)]
74 #[serde(deny_unknown_fields, rename_all = "snake_case")]
75 pub struct Config {
76 /// How long the FUSE client should consider directory entries and file/directory attributes to
77 /// be valid.
78 /// This value corresponds to `entry_timeout` and `attr_timeout` in
79 /// [libfuse's `fuse_config`](https://libfuse.github.io/doxygen/structfuse__config.html), but
80 /// we use the same value for the two.
81 ///
82 /// If the contents of a directory or the attributes of a file or directory can only be
83 /// modified by the FUSE client (i.e., the file system has exclusive access), then this should
84 /// be a large value.
85 /// The default value for this option is 5 seconds.
86 #[serde(
87 default = "config_default_timeout",
88 deserialize_with = "deserialize_timeout"
89 )]
90 pub timeout: Duration,
91
92 /// How long the FUSE client can cache negative lookup results.
93 /// If a file lookup fails, the client can assume the file doesn't exist until the timeout and
94 /// won't send lookup.
95 /// The value 0 means that negative lookup shouldn't be cached.
96 ///
97 /// If the contents of a directory can only be modified by the FUSE client (i.e., the file
98 /// system has exclusive access), then this should be a large value.
99 /// The default value for this option is 0 seconds (= no negative cache).
100 #[serde(
101 default = "config_default_negative_timeout",
102 deserialize_with = "deserialize_timeout"
103 )]
104 pub negative_timeout: Duration,
105
106 /// The caching policy the file system should use. See the documentation of `CachePolicy` for
107 /// more details.
108 #[serde(default, alias = "cache")]
109 pub cache_policy: CachePolicy,
110
111 /// Whether the file system should enabled writeback caching. This can improve performance as
112 /// it allows the FUSE client to cache and coalesce multiple writes before sending them to
113 /// the file system. However, enabling this option can increase the risk of data corruption
114 /// if the file contents can change without the knowledge of the FUSE client (i.e., the
115 /// server does **NOT** have exclusive access). Additionally, the file system should have
116 /// read access to all files in the directory it is serving as the FUSE client may send
117 /// read requests even for files opened with `O_WRONLY`.
118 ///
119 /// Therefore callers should only enable this option when they can guarantee that: 1) the file
120 /// system has exclusive access to the directory and 2) the file system has read permissions
121 /// for all files in that directory.
122 ///
123 /// The default value for this option is `false`.
124 #[serde(default)]
125 pub writeback: bool,
126
127 /// Controls whether security.* xattrs (except for security.selinux) are re-written. When this
128 /// is set to true, the server will add a "user.virtiofs" prefix to xattrs in the security
129 /// namespace. Setting these xattrs requires CAP_SYS_ADMIN in the namespace where the file
130 /// system was mounted and since the server usually runs in an unprivileged user namespace,
131 /// it's unlikely to have that capability.
132 ///
133 /// The default value for this option is `false`.
134 #[serde(default, alias = "rewrite-security-xattrs")]
135 pub rewrite_security_xattrs: bool,
136
137 /// Use case-insensitive lookups for directory entries (ASCII only).
138 ///
139 /// The default value for this option is `false`.
140 #[serde(default)]
141 pub ascii_casefold: bool,
142
143 // UIDs which are privileged to perform quota-related operations. We cannot perform a
144 // CAP_FOWNER check so we consult this list when the VM tries to set the project quota and
145 // the process uid doesn't match the owner uid. In that case, all uids in this list are
146 // treated as if they have CAP_FOWNER.
147 #[cfg(feature = "arc_quota")]
148 #[serde(default, deserialize_with = "deserialize_privileged_quota_uids")]
149 pub privileged_quota_uids: Vec<libc::uid_t>,
150
151 /// Use DAX for shared files.
152 ///
153 /// Enabling DAX can improve performance for frequently accessed files by mapping regions of
154 /// the file directly into the VM's memory region, allowing direct access with the cost of
155 /// slightly increased latency the first time the file is accessed. Additionally, since the
156 /// mapping is shared directly from the host kernel's file cache, enabling DAX can improve
157 /// performance even when the cache policy is `Never`.
158 ///
159 /// The default value for this option is `false`.
160 #[serde(default, alias = "dax")]
161 pub use_dax: bool,
162
163 /// Enable support for POSIX acls.
164 ///
165 /// Enable POSIX acl support for the shared directory. This requires that the underlying file
166 /// system also supports POSIX acls.
167 ///
168 /// The default value for this option is `true`.
169 #[serde(default = "config_default_posix_acl")]
170 pub posix_acl: bool,
171 }
172
173 impl Default for Config {
default() -> Self174 fn default() -> Self {
175 Config {
176 timeout: config_default_timeout(),
177 negative_timeout: config_default_negative_timeout(),
178 cache_policy: Default::default(),
179 writeback: false,
180 rewrite_security_xattrs: false,
181 ascii_casefold: false,
182 #[cfg(feature = "arc_quota")]
183 privileged_quota_uids: Default::default(),
184 use_dax: false,
185 posix_acl: config_default_posix_acl(),
186 }
187 }
188 }
189