• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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