fuse_backend_rs/api/filesystem/sync_io.rs
1// Copyright (C) 2021-2022 Alibaba Cloud. All rights reserved.
2// Copyright 2019 The Chromium OS Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE-BSD-3-Clause file.
5
6use std::ffi::CStr;
7use std::io;
8use std::mem;
9use std::ops::Deref;
10use std::sync::Arc;
11use std::time::Duration;
12
13use super::{
14 Context, DirEntry, Entry, FileLock, GetxattrReply, IoctlData, ListxattrReply, ZeroCopyReader,
15 ZeroCopyWriter,
16};
17use crate::abi::fuse_abi::{stat64, statvfs64, CreateIn, FsOptions, OpenOptions, SetattrValid};
18#[cfg(feature = "virtiofs")]
19pub use crate::abi::virtio_fs::RemovemappingOne;
20#[cfg(feature = "virtiofs")]
21use crate::transport::FsCacheReqHandler;
22
23/// The main trait that connects a file system with a transport.
24#[allow(unused_variables)]
25pub trait FileSystem {
26 /// Represents a location in the filesystem tree and can be used to perform operations that act
27 /// on the metadata of a file/directory (e.g., `getattr` and `setattr`). Can also be used as the
28 /// starting point for looking up paths in the filesystem tree. An `Inode` may support operating
29 /// directly on the content of the path that to which it points. `FileSystem` implementations
30 /// that support this should set the `FsOptions::ZERO_MESSAGE_OPEN` option in the return value
31 /// of the `init` function. On linux based systems, an `Inode` is equivalent to opening a file
32 /// or directory with the `libc::O_PATH` flag.
33 ///
34 /// # Lookup Count
35 ///
36 /// The `FileSystem` implementation is required to keep a "lookup count" for every `Inode`.
37 /// Every time an `Entry` is returned by a `FileSystem` trait method, this lookup count should
38 /// increase by 1. The lookup count for an `Inode` decreases when the kernel sends a `forget`
39 /// request. `Inode`s with a non-zero lookup count may receive requests from the kernel even
40 /// after calls to `unlink`, `rmdir` or (when overwriting an existing file) `rename`.
41 /// `FileSystem` implementations must handle such requests properly and it is recommended to
42 /// defer removal of the `Inode` until the lookup count reaches zero. Calls to `unlink`, `rmdir`
43 /// or `rename` will be followed closely by `forget` unless the file or directory is open, in
44 /// which case the kernel issues `forget` only after the `release` or `releasedir` calls.
45 ///
46 /// Note that if a file system will be exported over NFS the `Inode`'s lifetime must extend even
47 /// beyond `forget`. See the `generation` field in `Entry`.
48 type Inode: From<u64> + Into<u64>;
49
50 /// Represents a file or directory that is open for reading/writing.
51 type Handle: From<u64> + Into<u64>;
52
53 /// Initialize the file system.
54 ///
55 /// This method is called when a connection to the FUSE kernel module is first established. The
56 /// `capable` parameter indicates the features that are supported by the kernel module. The
57 /// implementation should return the options that it supports. Any options set in the returned
58 /// `FsOptions` that are not also set in `capable` are silently dropped.
59 fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {
60 Ok(FsOptions::empty())
61 }
62
63 /// Clean up the file system.
64 ///
65 /// Called when the filesystem exits. All open `Handle`s should be closed and the lookup count
66 /// for all open `Inode`s implicitly goes to zero. At this point the connection to the FUSE
67 /// kernel module may already be gone so implementations should not rely on being able to
68 /// communicate with the kernel.
69 fn destroy(&self) {}
70
71 /// Look up a directory entry by name and get its attributes.
72 ///
73 /// If this call is successful then the lookup count of the `Inode` associated with the returned
74 /// `Entry` must be increased by 1.
75 fn lookup(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {
76 Err(io::Error::from_raw_os_error(libc::ENOSYS))
77 }
78
79 /// Forget about an inode.
80 ///
81 /// Called when the kernel removes an inode from its internal caches. `count` indicates the
82 /// amount by which the lookup count for the inode should be decreased. If reducing the lookup
83 /// count by `count` causes it to go to zero, then the implementation may delete the `Inode`.
84 fn forget(&self, ctx: &Context, inode: Self::Inode, count: u64) {}
85
86 /// Forget about multiple inodes.
87 ///
88 /// `requests` is a vector of `(inode, count)` pairs. See the documentation for `forget` for
89 /// more information.
90 fn batch_forget(&self, ctx: &Context, requests: Vec<(Self::Inode, u64)>) {
91 for (inode, count) in requests {
92 self.forget(ctx, inode, count)
93 }
94 }
95
96 /// Get attributes for a file / directory.
97 ///
98 /// If `handle` is not `None`, then it contains the handle previously returned by the
99 /// implementation after a call to `open` or `opendir`. However, implementations should still
100 /// take care to verify the handle if they do not trust the client (e.g., virtio-fs).
101 ///
102 /// If writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`), then the kernel module
103 /// likely has a better idea of the length of the file than the file system (for
104 /// example, if there was a write that extended the size of the file but has not yet been
105 /// flushed). In this case, the `st_size` field of the returned struct is ignored.
106 ///
107 /// The returned `Duration` indicates how long the returned attributes should be considered
108 /// valid by the client. If the attributes are only changed via the FUSE kernel module (i.e.,
109 /// the kernel module has exclusive access), then this should be a very large value.
110 fn getattr(
111 &self,
112 ctx: &Context,
113 inode: Self::Inode,
114 handle: Option<Self::Handle>,
115 ) -> io::Result<(stat64, Duration)> {
116 Err(io::Error::from_raw_os_error(libc::ENOSYS))
117 }
118
119 /// Set attributes for a file / directory.
120 ///
121 /// If `handle` is not `None`, then it contains the handle previously returned by the
122 /// implementation after a call to `open` or `opendir`. However, implementations should still
123 /// take care to verify the handle if they do not trust the client (e.g., virtio-fs).
124 ///
125 /// The `valid` parameter indicates the fields of `attr` that may be considered valid and should
126 /// be set by the file system. The content of all other fields in `attr` is undefined.
127 ///
128 /// If the `FsOptions::HANDLE_KILLPRIV` was set during `init`, then the implementation is
129 /// expected to reset the setuid and setgid bits if the file size or owner is being changed.
130 ///
131 /// This method returns the new attributes after making the modifications requested by the
132 /// client. The returned `Duration` indicates how long the returned attributes should be
133 /// considered valid by the client. If the attributes are only changed via the FUSE kernel
134 /// module (i.e., the kernel module has exclusive access), then this should be a very large
135 /// value.
136 fn setattr(
137 &self,
138 ctx: &Context,
139 inode: Self::Inode,
140 attr: stat64,
141 handle: Option<Self::Handle>,
142 valid: SetattrValid,
143 ) -> io::Result<(stat64, Duration)> {
144 Err(io::Error::from_raw_os_error(libc::ENOSYS))
145 }
146
147 /// Read a symbolic link.
148 fn readlink(&self, ctx: &Context, inode: Self::Inode) -> io::Result<Vec<u8>> {
149 Err(io::Error::from_raw_os_error(libc::ENOSYS))
150 }
151
152 /// Create a symbolic link.
153 ///
154 /// The file system must create a symbolic link named `name` in the directory represented by
155 /// `parent`, which contains the string `linkname`. Returns an `Entry` for the newly created
156 /// symlink.
157 ///
158 /// If this call is successful then the lookup count of the `Inode` associated with the returned
159 /// `Entry` must be increased by 1.
160 fn symlink(
161 &self,
162 ctx: &Context,
163 linkname: &CStr,
164 parent: Self::Inode,
165 name: &CStr,
166 ) -> io::Result<Entry> {
167 Err(io::Error::from_raw_os_error(libc::ENOSYS))
168 }
169
170 /// Create a file node.
171 ///
172 /// Create a regular file, character device, block device, fifo, or socket node named `name` in
173 /// the directory represented by `inode`. Valid values for `mode` and `rdev` are the same as
174 /// those accepted by the `mknod(2)` system call. Returns an `Entry` for the newly created node.
175 ///
176 /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting
177 /// the permissions of the created node to `mode & !umask`.
178 ///
179 /// If this call is successful then the lookup count of the `Inode` associated with the returned
180 /// `Entry` must be increased by 1.
181 fn mknod(
182 &self,
183 ctx: &Context,
184 inode: Self::Inode,
185 name: &CStr,
186 mode: u32,
187 rdev: u32,
188 umask: u32,
189 ) -> io::Result<Entry> {
190 Err(io::Error::from_raw_os_error(libc::ENOSYS))
191 }
192
193 /// Create a directory.
194 ///
195 /// When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for setting
196 /// the permissions of the created directory to `mode & !umask`. Returns an `Entry` for the
197 /// newly created directory.
198 ///
199 /// If this call is successful then the lookup count of the `Inode` associated with the returned
200 /// `Entry` must be increased by 1.
201 fn mkdir(
202 &self,
203 ctx: &Context,
204 parent: Self::Inode,
205 name: &CStr,
206 mode: u32,
207 umask: u32,
208 ) -> io::Result<Entry> {
209 Err(io::Error::from_raw_os_error(libc::ENOSYS))
210 }
211
212 /// Remove a file.
213 ///
214 /// If the file's inode lookup count is non-zero, then the file system is expected to delay
215 /// removal of the inode until the lookup count goes to zero. See the documentation of the
216 /// `forget` function for more information.
217 fn unlink(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
218 Err(io::Error::from_raw_os_error(libc::ENOSYS))
219 }
220
221 /// Remove a directory.
222 ///
223 /// If the directory's inode lookup count is non-zero, then the file system is expected to delay
224 /// removal of the inode until the lookup count goes to zero. See the documentation of the
225 /// `forget` function for more information.
226 fn rmdir(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
227 Err(io::Error::from_raw_os_error(libc::ENOSYS))
228 }
229
230 /// Rename a file / directory.
231 ///
232 /// If the destination exists, it should be atomically replaced. If the destination's inode
233 /// lookup count is non-zero, then the file system is expected to delay removal of the inode
234 /// until the lookup count goes to zero. See the documentation of the `forget` function for more
235 /// information.
236 ///
237 /// `flags` may be `libc::RENAME_EXCHANGE` or `libc::RENAME_NOREPLACE`. If
238 /// `libc::RENAME_NOREPLACE` is specified, the implementation must not overwrite `newname` if it
239 /// exists and must return an error instead. If `libc::RENAME_EXCHANGE` is specified, the
240 /// implementation must atomically exchange the two files, i.e., both must exist and neither may
241 /// be deleted.
242 fn rename(
243 &self,
244 ctx: &Context,
245 olddir: Self::Inode,
246 oldname: &CStr,
247 newdir: Self::Inode,
248 newname: &CStr,
249 flags: u32,
250 ) -> io::Result<()> {
251 Err(io::Error::from_raw_os_error(libc::ENOSYS))
252 }
253
254 /// Create a hard link.
255 ///
256 /// Create a hard link from `inode` to `newname` in the directory represented by `newparent`.
257 ///
258 /// If this call is successful then the lookup count of the `Inode` associated with the returned
259 /// `Entry` must be increased by 1.
260 fn link(
261 &self,
262 ctx: &Context,
263 inode: Self::Inode,
264 newparent: Self::Inode,
265 newname: &CStr,
266 ) -> io::Result<Entry> {
267 Err(io::Error::from_raw_os_error(libc::ENOSYS))
268 }
269
270 /// Open a file.
271 ///
272 /// Open the file associated with `inode` for reading / writing. All values accepted by the
273 /// `open(2)` system call are valid values for `flags` and must be handled by the file system.
274 /// However, there are some additional rules:
275 ///
276 /// * Creation flags (`libc::O_CREAT`, `libc::O_EXCL`, `libc::O_NOCTTY`) will be filtered out
277 /// and handled by the kernel.
278 ///
279 /// * The file system should check the access modes (`libc::O_RDONLY`, `libc::O_WRONLY`,
280 /// `libc::O_RDWR`) to determine if the operation is permitted. If the file system was mounted
281 /// with the `-o default_permissions` mount option, then this check will also be carried out
282 /// by the kernel before sending the open request.
283 ///
284 /// * When writeback caching is enabled (`FsOptions::WRITEBACK_CACHE`) the kernel may send read
285 /// requests even for files opened with `libc::O_WRONLY`. The file system should be prepared
286 /// to handle this.
287 ///
288 /// * When writeback caching is enabled, the kernel will handle the `libc::O_APPEND` flag.
289 /// However, this will not work reliably unless the kernel has exclusive access to the file.
290 /// In this case the file system may either ignore the `libc::O_APPEND` flag or return an
291 /// error to indicate that reliable `libc::O_APPEND` handling is not available.
292 ///
293 /// * When writeback caching is disabled, the file system is expected to properly handle
294 /// `libc::O_APPEND` and ensure that each write is appended to the end of the file.
295 ///
296 /// The file system may choose to return a `Handle` to refer to the newly opened file. The
297 /// kernel will then use this `Handle` for all operations on the content of the file (`read`,
298 /// `write`, `flush`, `release`, `fsync`). If the file system does not return a
299 /// `Handle` then the kernel will use the `Inode` for the file to operate on its contents. In
300 /// this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPEN` feature if
301 /// it is supported by the kernel (see below).
302 ///
303 /// The returned `OpenOptions` allow the file system to change the way the opened file is
304 /// handled by the kernel. See the documentation of `OpenOptions` for more information.
305 ///
306 /// If the `FsOptions::ZERO_MESSAGE_OPEN` feature is enabled by both the file system
307 /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This
308 /// will be interpreted by the kernel as success and future calls to `open` and `release` will
309 /// be handled by the kernel without being passed on to the file system.
310 fn open(
311 &self,
312 ctx: &Context,
313 inode: Self::Inode,
314 flags: u32,
315 fuse_flags: u32,
316 ) -> io::Result<(Option<Self::Handle>, OpenOptions, Option<u32>)> {
317 // Matches the behavior of libfuse.
318 Ok((None, OpenOptions::empty(), None))
319 }
320
321 /// Create and open a file.
322 ///
323 /// If the file does not already exist, the file system should create it with the specified
324 /// `mode`. When the `FsOptions::DONT_MASK` feature is set, the file system is responsible for
325 /// setting the permissions of the created file to `mode & !umask`.
326 ///
327 /// If the file system returns an `ENOSYS` error, then the kernel will treat this method as
328 /// unimplemented and all future calls to `create` will be handled by calling the `mknod` and
329 /// `open` methods instead.
330 ///
331 /// See the documentation for the `open` method for more information about opening the file. In
332 /// addition to the optional `Handle` and the `OpenOptions`, the file system must also return an
333 /// `Entry` for the file. This increases the lookup count for the `Inode` associated with the
334 /// file by 1.
335 #[allow(clippy::type_complexity)]
336 fn create(
337 &self,
338 ctx: &Context,
339 parent: Self::Inode,
340 name: &CStr,
341 args: CreateIn,
342 ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions, Option<u32>)> {
343 Err(io::Error::from_raw_os_error(libc::ENOSYS))
344 }
345
346 /// Read data from a file.
347 ///
348 /// Returns `size` bytes of data starting from offset `off` from the file associated with
349 /// `inode` or `handle`.
350 ///
351 /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`
352 /// returned by the file system from the `open` method, if any. If the file system
353 /// implementation did not return a `Handle` from `open` then the contents of `handle` are
354 /// undefined.
355 ///
356 /// This method should return exactly the number of bytes requested by the kernel, except in the
357 /// case of error or EOF. Otherwise, the kernel will substitute the rest of the data with
358 /// zeroes. An exception to this rule is if the file was opened with the "direct I/O" option
359 /// (`libc::O_DIRECT`), in which case the kernel will forward the return code from this method
360 /// to the userspace application that made the system call.
361 #[allow(clippy::too_many_arguments)]
362 fn read(
363 &self,
364 ctx: &Context,
365 inode: Self::Inode,
366 handle: Self::Handle,
367 w: &mut dyn ZeroCopyWriter,
368 size: u32,
369 offset: u64,
370 lock_owner: Option<u64>,
371 flags: u32,
372 ) -> io::Result<usize> {
373 Err(io::Error::from_raw_os_error(libc::ENOSYS))
374 }
375
376 /// Write data to a file.
377 ///
378 /// Writes `size` bytes of data starting from offset `off` to the file associated with `inode`
379 /// or `handle`.
380 ///
381 /// `flags` contains the flags used to open the file. Similarly, `handle` is the `Handle`
382 /// returned by the file system from the `open` method, if any. If the file system
383 /// implementation did not return a `Handle` from `open` then the contents of `handle` are
384 /// undefined.
385 ///
386 /// If the `FsOptions::HANDLE_KILLPRIV` feature is not enabled then then the file system is
387 /// expected to clear the setuid and setgid bits.
388 ///
389 /// If `delayed_write` is true then it indicates that this is a write for buffered data.
390 ///
391 /// This method should return exactly the number of bytes requested by the kernel, except in the
392 /// case of error. An exception to this rule is if the file was opened with the "direct I/O"
393 /// option (`libc::O_DIRECT`), in which case the kernel will forward the return code from this
394 /// method to the userspace application that made the system call.
395 #[allow(clippy::too_many_arguments)]
396 fn write(
397 &self,
398 ctx: &Context,
399 inode: Self::Inode,
400 handle: Self::Handle,
401 r: &mut dyn ZeroCopyReader,
402 size: u32,
403 offset: u64,
404 lock_owner: Option<u64>,
405 delayed_write: bool,
406 flags: u32,
407 fuse_flags: u32,
408 ) -> io::Result<usize> {
409 Err(io::Error::from_raw_os_error(libc::ENOSYS))
410 }
411
412 /// Flush the contents of a file.
413 ///
414 /// This method is called on every `close()` of a file descriptor. Since it is possible to
415 /// duplicate file descriptors there may be many `flush` calls for one call to `open`.
416 ///
417 /// File systems should not make any assumptions about when `flush` will be
418 /// called or even if it will be called at all.
419 ///
420 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
421 /// file system did not return a `Handle` from `open` then the contents of `handle` are
422 /// undefined.
423 ///
424 /// Unlike `fsync`, the file system is not required to flush pending writes. One reason to flush
425 /// data is if the file system wants to return write errors during close. However, this is not
426 /// portable because POSIX does not require `close` to wait for delayed I/O to complete.
427 ///
428 /// If the `FsOptions::POSIX_LOCKS` feature is enabled, then the file system must remove all
429 /// locks belonging to `lock_owner`.
430 ///
431 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
432 /// subsequent calls to `flush` will be handled by the kernel without being forwarded to the
433 /// file system.
434 fn flush(
435 &self,
436 ctx: &Context,
437 inode: Self::Inode,
438 handle: Self::Handle,
439 lock_owner: u64,
440 ) -> io::Result<()> {
441 Err(io::Error::from_raw_os_error(libc::ENOSYS))
442 }
443
444 /// Synchronize file contents.
445 ///
446 /// File systems must ensure that the file contents have been flushed to disk before returning
447 /// from this method. If `datasync` is true then only the file data (but not the metadata) needs
448 /// to be flushed.
449 ///
450 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
451 /// file system did not return a `Handle` from `open` then the contents of
452 /// `handle` are undefined.
453 ///
454 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
455 /// subsequent calls to `fsync` will be handled by the kernel without being forwarded to the
456 /// file system.
457 fn fsync(
458 &self,
459 ctx: &Context,
460 inode: Self::Inode,
461 datasync: bool,
462 handle: Self::Handle,
463 ) -> io::Result<()> {
464 Err(io::Error::from_raw_os_error(libc::ENOSYS))
465 }
466
467 /// Allocate requested space for file data.
468 ///
469 /// If this function returns success, then the file sytem must guarantee that it is possible to
470 /// write up to `length` bytes of data starting at `offset` without failing due to a lack of
471 /// free space on the disk.
472 ///
473 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
474 /// file system did not return a `Handle` from `open` then the contents of `handle` are
475 /// undefined.
476 ///
477 /// If this method returns an `ENOSYS` error then the kernel will treat that as a permanent
478 /// failure: all future calls to `fallocate` will fail with `EOPNOTSUPP` without being forwarded
479 /// to the file system.
480 fn fallocate(
481 &self,
482 ctx: &Context,
483 inode: Self::Inode,
484 handle: Self::Handle,
485 mode: u32,
486 offset: u64,
487 length: u64,
488 ) -> io::Result<()> {
489 Err(io::Error::from_raw_os_error(libc::ENOSYS))
490 }
491
492 /// Release an open file.
493 ///
494 /// This method is called when there are no more references to an open file: all file
495 /// descriptors are closed and all memory mappings are unmapped.
496 ///
497 /// For every `open` call there will be exactly one `release` call (unless the file system is
498 /// force-unmounted).
499 ///
500 /// The file system may reply with an error, but error values are not returned to the `close()`
501 /// or `munmap()` which triggered the release.
502 ///
503 /// `handle` is the `Handle` returned by the file system from the `open` method, if any. If the
504 /// file system did not return a `Handle` from `open` then the contents of
505 /// `handle` are undefined.
506 ///
507 /// If `flush` is `true` then the contents of the file should also be flushed to disk.
508 #[allow(clippy::too_many_arguments)]
509 fn release(
510 &self,
511 ctx: &Context,
512 inode: Self::Inode,
513 flags: u32,
514 handle: Self::Handle,
515 flush: bool,
516 flock_release: bool,
517 lock_owner: Option<u64>,
518 ) -> io::Result<()> {
519 Err(io::Error::from_raw_os_error(libc::ENOSYS))
520 }
521
522 /// Get information about the file system.
523 fn statfs(&self, ctx: &Context, inode: Self::Inode) -> io::Result<statvfs64> {
524 // Safe because we are zero-initializing a struct with only POD fields.
525 let mut st: statvfs64 = unsafe { mem::zeroed() };
526
527 // This matches the behavior of libfuse as it returns these values if the
528 // filesystem doesn't implement this method.
529 st.f_namemax = 255;
530 st.f_bsize = 512;
531
532 Ok(st)
533 }
534
535 /// Set an extended attribute.
536 ///
537 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
538 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `setxattr` without
539 /// forwarding them to the file system.
540 ///
541 /// Valid values for flags are the same as those accepted by the `setxattr(2)` system call and
542 /// have the same behavior.
543 fn setxattr(
544 &self,
545 ctx: &Context,
546 inode: Self::Inode,
547 name: &CStr,
548 value: &[u8],
549 flags: u32,
550 ) -> io::Result<()> {
551 Err(io::Error::from_raw_os_error(libc::ENOSYS))
552 }
553
554 /// Get an extended attribute.
555 ///
556 /// If `size` is 0, then the file system should respond with `GetxattrReply::Count` and the
557 /// number of bytes needed to hold the value. If `size` is large enough to hold the value, then
558 /// the file system should reply with `GetxattrReply::Value` and the value of the extended
559 /// attribute. If `size` is not 0 but is also not large enough to hold the value, then the file
560 /// system should reply with an `ERANGE` error.
561 ///
562 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
563 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `getxattr` without
564 /// forwarding them to the file system.
565 fn getxattr(
566 &self,
567 ctx: &Context,
568 inode: Self::Inode,
569 name: &CStr,
570 size: u32,
571 ) -> io::Result<GetxattrReply> {
572 Err(io::Error::from_raw_os_error(libc::ENOSYS))
573 }
574
575 /// List extended attribute names.
576 ///
577 /// If `size` is 0, then the file system should respond with `ListxattrReply::Count` and the
578 /// number of bytes needed to hold a `\0` byte separated list of the names of all the extended
579 /// attributes. If `size` is large enough to hold the `\0` byte separated list of the attribute
580 /// names, then the file system should reply with `ListxattrReply::Names` and the list. If
581 /// `size` is not 0 but is also not large enough to hold the list, then the file system should
582 /// reply with an `ERANGE` error.
583 ///
584 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
585 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `listxattr` without
586 /// forwarding them to the file system.
587 fn listxattr(
588 &self,
589 ctx: &Context,
590 inode: Self::Inode,
591 size: u32,
592 ) -> io::Result<ListxattrReply> {
593 Err(io::Error::from_raw_os_error(libc::ENOSYS))
594 }
595
596 /// Remove an extended attribute.
597 ///
598 /// If this method fails with an `ENOSYS` error, then the kernel will treat that as a permanent
599 /// failure. The kernel will return `EOPNOTSUPP` for all future calls to `removexattr` without
600 /// forwarding them to the file system.
601 fn removexattr(&self, ctx: &Context, inode: Self::Inode, name: &CStr) -> io::Result<()> {
602 Err(io::Error::from_raw_os_error(libc::ENOSYS))
603 }
604
605 /// Open a directory for reading.
606 ///
607 /// The file system may choose to return a `Handle` to refer to the newly opened directory. The
608 /// kernel will then use this `Handle` for all operations on the content of the directory
609 /// (`readdir`, `readdirplus`, `fsyncdir`, `releasedir`). If the file system does not return a
610 /// `Handle` then the kernel will use the `Inode` for the directory to operate on its contents.
611 /// In this case the file system may wish to enable the `FsOptions::ZERO_MESSAGE_OPENDIR`
612 /// feature if it is supported by the kernel (see below).
613 ///
614 /// The returned `OpenOptions` allow the file system to change the way the opened directory is
615 /// handled by the kernel. See the documentation of `OpenOptions` for more information.
616 ///
617 /// If the `FsOptions::ZERO_MESSAGE_OPENDIR` feature is enabled by both the file system
618 /// implementation and the kernel, then the file system may return an error of `ENOSYS`. This
619 /// will be interpreted by the kernel as success and future calls to `opendir` and `releasedir`
620 /// will be handled by the kernel without being passed on to the file system.
621 fn opendir(
622 &self,
623 ctx: &Context,
624 inode: Self::Inode,
625 flags: u32,
626 ) -> io::Result<(Option<Self::Handle>, OpenOptions)> {
627 // Matches the behavior of libfuse.
628 Ok((None, OpenOptions::empty()))
629 }
630
631 /// Read a directory.
632 ///
633 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
634 /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are
635 /// undefined.
636 ///
637 /// `size` indicates the maximum number of bytes that should be returned by this method.
638 ///
639 /// If `offset` is non-zero then it corresponds to one of the `offset` values from a `DirEntry`
640 /// that was previously returned by a call to `readdir` for the same handle. In this case the
641 /// file system should skip over the entries before the position defined by the `offset` value.
642 /// If entries were added or removed while the `Handle` is open then the file system may still
643 /// include removed entries or skip newly created entries. However, adding or removing entries
644 /// should never cause the file system to skip over unrelated entries or include an entry more
645 /// than once. This means that `offset` cannot be a simple index and must include sufficient
646 /// information to uniquely determine the next entry in the list even when the set of entries is
647 /// being changed.
648 ///
649 /// The file system may return entries for the current directory (".") and parent directory
650 /// ("..") but is not required to do so. If the file system does not return these entries, then
651 /// they are implicitly added by the kernel.
652 ///
653 /// The lookup count for `Inode`s associated with the returned directory entries is **NOT**
654 /// affected by this method.
655 ///
656 // TODO(chirantan): Change method signature to return `Iterator<DirEntry>` rather than using an
657 // `FnMut` for adding entries.
658 fn readdir(
659 &self,
660 ctx: &Context,
661 inode: Self::Inode,
662 handle: Self::Handle,
663 size: u32,
664 offset: u64,
665 add_entry: &mut dyn FnMut(DirEntry) -> io::Result<usize>,
666 ) -> io::Result<()> {
667 Err(io::Error::from_raw_os_error(libc::ENOSYS))
668 }
669
670 /// Read a directory with entry attributes.
671 ///
672 /// Like `readdir` but also includes the attributes for each directory entry.
673 ///
674 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
675 /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are
676 /// undefined.
677 ///
678 /// `size` indicates the maximum number of bytes that should be returned by this method.
679 ///
680 /// Unlike `readdir`, the lookup count for `Inode`s associated with the returned directory
681 /// entries **IS** affected by this method (since it returns an `Entry` for each `DirEntry`).
682 /// The count for each `Inode` should be increased by 1.
683 ///
684 /// File systems that implement this method should enable the `FsOptions::DO_READDIRPLUS`
685 /// feature when supported by the kernel. The kernel will not call this method unless that
686 /// feature is enabled.
687 ///
688 /// Additionally, file systems that implement both `readdir` and `readdirplus` should enable the
689 /// `FsOptions::READDIRPLUS_AUTO` feature to allow the kernel to issue both `readdir` and
690 /// `readdirplus` requests, depending on how much information is expected to be required.
691 ///
692 /// TODO(chirantan): Change method signature to return `Iterator<(DirEntry, Entry)>` rather than
693 /// using an `FnMut` for adding entries.
694 fn readdirplus(
695 &self,
696 ctx: &Context,
697 inode: Self::Inode,
698 handle: Self::Handle,
699 size: u32,
700 offset: u64,
701 add_entry: &mut dyn FnMut(DirEntry, Entry) -> io::Result<usize>,
702 ) -> io::Result<()> {
703 Err(io::Error::from_raw_os_error(libc::ENOSYS))
704 }
705
706 /// Synchronize the contents of a directory.
707 ///
708 /// File systems must ensure that the directory contents have been flushed to disk before
709 /// returning from this method. If `datasync` is true then only the directory data (but not the
710 /// metadata) needs to be flushed.
711 ///
712 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
713 /// the file system did not return a `Handle` from `opendir` then the contents of
714 /// `handle` are undefined.
715 ///
716 /// If this method returns an `ENOSYS` error then the kernel will treat it as success and all
717 /// subsequent calls to `fsyncdir` will be handled by the kernel without being forwarded to the
718 /// file system.
719 fn fsyncdir(
720 &self,
721 ctx: &Context,
722 inode: Self::Inode,
723 datasync: bool,
724 handle: Self::Handle,
725 ) -> io::Result<()> {
726 Err(io::Error::from_raw_os_error(libc::ENOSYS))
727 }
728
729 /// Release an open directory.
730 ///
731 /// For every `opendir` call there will be exactly one `releasedir` call (unless the file system
732 /// is force-unmounted).
733 ///
734 /// `handle` is the `Handle` returned by the file system from the `opendir` method, if any. If
735 /// the file system did not return a `Handle` from `opendir` then the contents of `handle` are
736 /// undefined.
737 ///
738 /// `flags` contains used the flags used to open the directory in `opendir`.
739 fn releasedir(
740 &self,
741 ctx: &Context,
742 inode: Self::Inode,
743 flags: u32,
744 handle: Self::Handle,
745 ) -> io::Result<()> {
746 Err(io::Error::from_raw_os_error(libc::ENOSYS))
747 }
748
749 #[cfg(feature = "virtiofs")]
750 /// Setup a mapping so that guest can access files in DAX style.
751 ///
752 /// The virtio-fs DAX Window allows bypassing guest page cache and allows mapping host
753 /// page cache directly in guest address space.
754 ///
755 /// When a page of file is needed, guest sends a request to map that page (in host page cache)
756 /// in VMM address space. Inside guest this is a physical memory range controlled by virtiofs
757 /// device. And guest directly maps this physical address range using DAX and hence gets
758 /// access to file data on host.
759 ///
760 /// This can speed up things considerably in many situations. Also this can result in
761 /// substantial memory savings as file data does not have to be copied in guest and it is
762 /// directly accessed from host page cache.
763 #[allow(clippy::too_many_arguments)]
764 fn setupmapping(
765 &self,
766 _ctx: &Context,
767 inode: Self::Inode,
768 handle: Self::Handle,
769 foffset: u64,
770 len: u64,
771 flags: u64,
772 moffset: u64,
773 vu_req: &mut dyn FsCacheReqHandler,
774 ) -> io::Result<()> {
775 Err(io::Error::from_raw_os_error(libc::ENOSYS))
776 }
777
778 #[cfg(feature = "virtiofs")]
779 /// Teardown a mapping which was setup for guest DAX style access.
780 fn removemapping(
781 &self,
782 _ctx: &Context,
783 _inode: Self::Inode,
784 requests: Vec<RemovemappingOne>,
785 vu_req: &mut dyn FsCacheReqHandler,
786 ) -> io::Result<()> {
787 Err(io::Error::from_raw_os_error(libc::ENOSYS))
788 }
789
790 /// Check file access permissions.
791 ///
792 /// This method is called when a userspace process in the client makes an `access()` or
793 /// `chdir()` system call. If the file system was mounted with the `-o default_permissions`
794 /// mount option, then the kernel will perform these checks itself and this method will not be
795 /// called.
796 ///
797 /// If this method returns an `ENOSYS` error, then the kernel will treat it as a permanent
798 /// success: all future calls to `access` will return success without being forwarded to the
799 /// file system.
800 fn access(&self, ctx: &Context, inode: Self::Inode, mask: u32) -> io::Result<()> {
801 Err(io::Error::from_raw_os_error(libc::ENOSYS))
802 }
803
804 /// Reposition read/write file offset.
805 fn lseek(
806 &self,
807 ctx: &Context,
808 inode: Self::Inode,
809 handle: Self::Handle,
810 offset: u64,
811 whence: u32,
812 ) -> io::Result<u64> {
813 Err(io::Error::from_raw_os_error(libc::ENOSYS))
814 }
815
816 /// Query file lock status
817 fn getlk(
818 &self,
819 ctx: &Context,
820 inode: Self::Inode,
821 handle: Self::Handle,
822 owner: u64,
823 lock: FileLock,
824 flags: u32,
825 ) -> io::Result<FileLock> {
826 Err(io::Error::from_raw_os_error(libc::ENOSYS))
827 }
828
829 /// Grab a file read lock
830 fn setlk(
831 &self,
832 ctx: &Context,
833 inode: Self::Inode,
834 handle: Self::Handle,
835 owner: u64,
836 lock: FileLock,
837 flags: u32,
838 ) -> io::Result<()> {
839 Err(io::Error::from_raw_os_error(libc::ENOSYS))
840 }
841
842 /// Grab a file write lock
843 fn setlkw(
844 &self,
845 ctx: &Context,
846 inode: Self::Inode,
847 handle: Self::Handle,
848 owner: u64,
849 lock: FileLock,
850 flags: u32,
851 ) -> io::Result<()> {
852 Err(io::Error::from_raw_os_error(libc::ENOSYS))
853 }
854
855 /// send ioctl to the file
856 #[allow(clippy::too_many_arguments)]
857 fn ioctl(
858 &self,
859 ctx: &Context,
860 inode: Self::Inode,
861 handle: Self::Handle,
862 flags: u32,
863 cmd: u32,
864 data: IoctlData,
865 out_size: u32,
866 ) -> io::Result<IoctlData> {
867 // Rather than ENOSYS, let's return ENOTTY so simulate that the ioctl call is implemented
868 // but no ioctl number is supported.
869 Err(io::Error::from_raw_os_error(libc::ENOTTY))
870 }
871
872 /// Query a file's block mapping info
873 fn bmap(
874 &self,
875 ctx: &Context,
876 inode: Self::Inode,
877 block: u64,
878 blocksize: u32,
879 ) -> io::Result<u64> {
880 Err(io::Error::from_raw_os_error(libc::ENOSYS))
881 }
882
883 /// Poll a file's events
884 fn poll(
885 &self,
886 ctx: &Context,
887 inode: Self::Inode,
888 handle: Self::Handle,
889 khandle: Self::Handle,
890 flags: u32,
891 events: u32,
892 ) -> io::Result<u32> {
893 Err(io::Error::from_raw_os_error(libc::ENOSYS))
894 }
895
896 /// TODO: support this
897 fn notify_reply(&self) -> io::Result<()> {
898 Err(io::Error::from_raw_os_error(libc::ENOSYS))
899 }
900
901 /// Remap the external IDs in context to internal IDs.
902 fn id_remap(&self, ctx: &mut Context) -> io::Result<()> {
903 Ok(())
904 }
905}
906
907impl<FS: FileSystem> FileSystem for Arc<FS> {
908 type Inode = FS::Inode;
909 type Handle = FS::Handle;
910
911 fn init(&self, capable: FsOptions) -> io::Result<FsOptions> {
912 self.deref().init(capable)
913 }
914
915 fn destroy(&self) {
916 self.deref().destroy()
917 }
918
919 fn lookup(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<Entry> {
920 self.deref().lookup(ctx, parent, name)
921 }
922
923 fn forget(&self, ctx: &Context, inode: Self::Inode, count: u64) {
924 self.deref().forget(ctx, inode, count)
925 }
926
927 fn batch_forget(&self, ctx: &Context, requests: Vec<(Self::Inode, u64)>) {
928 self.deref().batch_forget(ctx, requests)
929 }
930
931 fn getattr(
932 &self,
933 ctx: &Context,
934 inode: Self::Inode,
935 handle: Option<Self::Handle>,
936 ) -> io::Result<(stat64, Duration)> {
937 self.deref().getattr(ctx, inode, handle)
938 }
939
940 fn setattr(
941 &self,
942 ctx: &Context,
943 inode: Self::Inode,
944 attr: stat64,
945 handle: Option<Self::Handle>,
946 valid: SetattrValid,
947 ) -> io::Result<(stat64, Duration)> {
948 self.deref().setattr(ctx, inode, attr, handle, valid)
949 }
950
951 fn readlink(&self, ctx: &Context, inode: Self::Inode) -> io::Result<Vec<u8>> {
952 self.deref().readlink(ctx, inode)
953 }
954
955 fn symlink(
956 &self,
957 ctx: &Context,
958 linkname: &CStr,
959 parent: Self::Inode,
960 name: &CStr,
961 ) -> io::Result<Entry> {
962 self.deref().symlink(ctx, linkname, parent, name)
963 }
964
965 fn mknod(
966 &self,
967 ctx: &Context,
968 inode: Self::Inode,
969 name: &CStr,
970 mode: u32,
971 rdev: u32,
972 umask: u32,
973 ) -> io::Result<Entry> {
974 self.deref().mknod(ctx, inode, name, mode, rdev, umask)
975 }
976
977 fn mkdir(
978 &self,
979 ctx: &Context,
980 parent: Self::Inode,
981 name: &CStr,
982 mode: u32,
983 umask: u32,
984 ) -> io::Result<Entry> {
985 self.deref().mkdir(ctx, parent, name, mode, umask)
986 }
987
988 fn unlink(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
989 self.deref().unlink(ctx, parent, name)
990 }
991
992 fn rmdir(&self, ctx: &Context, parent: Self::Inode, name: &CStr) -> io::Result<()> {
993 self.deref().rmdir(ctx, parent, name)
994 }
995
996 fn rename(
997 &self,
998 ctx: &Context,
999 olddir: Self::Inode,
1000 oldname: &CStr,
1001 newdir: Self::Inode,
1002 newname: &CStr,
1003 flags: u32,
1004 ) -> io::Result<()> {
1005 self.deref()
1006 .rename(ctx, olddir, oldname, newdir, newname, flags)
1007 }
1008
1009 fn link(
1010 &self,
1011 ctx: &Context,
1012 inode: Self::Inode,
1013 newparent: Self::Inode,
1014 newname: &CStr,
1015 ) -> io::Result<Entry> {
1016 self.deref().link(ctx, inode, newparent, newname)
1017 }
1018
1019 fn open(
1020 &self,
1021 ctx: &Context,
1022 inode: Self::Inode,
1023 flags: u32,
1024 fuse_flags: u32,
1025 ) -> io::Result<(Option<Self::Handle>, OpenOptions, Option<u32>)> {
1026 self.deref().open(ctx, inode, flags, fuse_flags)
1027 }
1028
1029 fn create(
1030 &self,
1031 ctx: &Context,
1032 parent: Self::Inode,
1033 name: &CStr,
1034 args: CreateIn,
1035 ) -> io::Result<(Entry, Option<Self::Handle>, OpenOptions, Option<u32>)> {
1036 self.deref().create(ctx, parent, name, args)
1037 }
1038
1039 fn read(
1040 &self,
1041 ctx: &Context,
1042 inode: Self::Inode,
1043 handle: Self::Handle,
1044 w: &mut dyn ZeroCopyWriter,
1045 size: u32,
1046 offset: u64,
1047 lock_owner: Option<u64>,
1048 flags: u32,
1049 ) -> io::Result<usize> {
1050 self.deref()
1051 .read(ctx, inode, handle, w, size, offset, lock_owner, flags)
1052 }
1053
1054 #[allow(clippy::too_many_arguments)]
1055 fn write(
1056 &self,
1057 ctx: &Context,
1058 inode: Self::Inode,
1059 handle: Self::Handle,
1060 r: &mut dyn ZeroCopyReader,
1061 size: u32,
1062 offset: u64,
1063 lock_owner: Option<u64>,
1064 delayed_write: bool,
1065 flags: u32,
1066 fuse_flags: u32,
1067 ) -> io::Result<usize> {
1068 self.deref().write(
1069 ctx,
1070 inode,
1071 handle,
1072 r,
1073 size,
1074 offset,
1075 lock_owner,
1076 delayed_write,
1077 flags,
1078 fuse_flags,
1079 )
1080 }
1081
1082 fn flush(
1083 &self,
1084 ctx: &Context,
1085 inode: Self::Inode,
1086 handle: Self::Handle,
1087 lock_owner: u64,
1088 ) -> io::Result<()> {
1089 self.deref().flush(ctx, inode, handle, lock_owner)
1090 }
1091
1092 fn fsync(
1093 &self,
1094 ctx: &Context,
1095 inode: Self::Inode,
1096 datasync: bool,
1097 handle: Self::Handle,
1098 ) -> io::Result<()> {
1099 self.deref().fsync(ctx, inode, datasync, handle)
1100 }
1101
1102 fn fallocate(
1103 &self,
1104 ctx: &Context,
1105 inode: Self::Inode,
1106 handle: Self::Handle,
1107 mode: u32,
1108 offset: u64,
1109 length: u64,
1110 ) -> io::Result<()> {
1111 self.deref()
1112 .fallocate(ctx, inode, handle, mode, offset, length)
1113 }
1114
1115 #[allow(clippy::too_many_arguments)]
1116 fn release(
1117 &self,
1118 ctx: &Context,
1119 inode: Self::Inode,
1120 flags: u32,
1121 handle: Self::Handle,
1122 flush: bool,
1123 flock_release: bool,
1124 lock_owner: Option<u64>,
1125 ) -> io::Result<()> {
1126 self.deref()
1127 .release(ctx, inode, flags, handle, flush, flock_release, lock_owner)
1128 }
1129
1130 fn statfs(&self, ctx: &Context, inode: Self::Inode) -> io::Result<statvfs64> {
1131 self.deref().statfs(ctx, inode)
1132 }
1133
1134 fn setxattr(
1135 &self,
1136 ctx: &Context,
1137 inode: Self::Inode,
1138 name: &CStr,
1139 value: &[u8],
1140 flags: u32,
1141 ) -> io::Result<()> {
1142 self.deref().setxattr(ctx, inode, name, value, flags)
1143 }
1144
1145 fn getxattr(
1146 &self,
1147 ctx: &Context,
1148 inode: Self::Inode,
1149 name: &CStr,
1150 size: u32,
1151 ) -> io::Result<GetxattrReply> {
1152 self.deref().getxattr(ctx, inode, name, size)
1153 }
1154
1155 fn listxattr(
1156 &self,
1157 ctx: &Context,
1158 inode: Self::Inode,
1159 size: u32,
1160 ) -> io::Result<ListxattrReply> {
1161 self.deref().listxattr(ctx, inode, size)
1162 }
1163
1164 fn removexattr(&self, ctx: &Context, inode: Self::Inode, name: &CStr) -> io::Result<()> {
1165 self.deref().removexattr(ctx, inode, name)
1166 }
1167
1168 fn opendir(
1169 &self,
1170 ctx: &Context,
1171 inode: Self::Inode,
1172 flags: u32,
1173 ) -> io::Result<(Option<Self::Handle>, OpenOptions)> {
1174 self.deref().opendir(ctx, inode, flags)
1175 }
1176
1177 fn readdir(
1178 &self,
1179 ctx: &Context,
1180 inode: Self::Inode,
1181 handle: Self::Handle,
1182 size: u32,
1183 offset: u64,
1184 add_entry: &mut dyn FnMut(DirEntry) -> io::Result<usize>,
1185 ) -> io::Result<()> {
1186 self.deref()
1187 .readdir(ctx, inode, handle, size, offset, add_entry)
1188 }
1189
1190 fn readdirplus(
1191 &self,
1192 ctx: &Context,
1193 inode: Self::Inode,
1194 handle: Self::Handle,
1195 size: u32,
1196 offset: u64,
1197 add_entry: &mut dyn FnMut(DirEntry, Entry) -> io::Result<usize>,
1198 ) -> io::Result<()> {
1199 self.deref()
1200 .readdirplus(ctx, inode, handle, size, offset, add_entry)
1201 }
1202
1203 fn fsyncdir(
1204 &self,
1205 ctx: &Context,
1206 inode: Self::Inode,
1207 datasync: bool,
1208 handle: Self::Handle,
1209 ) -> io::Result<()> {
1210 self.deref().fsyncdir(ctx, inode, datasync, handle)
1211 }
1212
1213 fn releasedir(
1214 &self,
1215 ctx: &Context,
1216 inode: Self::Inode,
1217 flags: u32,
1218 handle: Self::Handle,
1219 ) -> io::Result<()> {
1220 self.deref().releasedir(ctx, inode, flags, handle)
1221 }
1222
1223 #[cfg(feature = "virtiofs")]
1224 #[allow(clippy::too_many_arguments)]
1225 fn setupmapping(
1226 &self,
1227 ctx: &Context,
1228 inode: Self::Inode,
1229 handle: Self::Handle,
1230 foffset: u64,
1231 len: u64,
1232 flags: u64,
1233 moffset: u64,
1234 vu_req: &mut dyn FsCacheReqHandler,
1235 ) -> io::Result<()> {
1236 self.deref()
1237 .setupmapping(ctx, inode, handle, foffset, len, flags, moffset, vu_req)
1238 }
1239
1240 #[cfg(feature = "virtiofs")]
1241 fn removemapping(
1242 &self,
1243 ctx: &Context,
1244 inode: Self::Inode,
1245 requests: Vec<RemovemappingOne>,
1246 vu_req: &mut dyn FsCacheReqHandler,
1247 ) -> io::Result<()> {
1248 self.deref().removemapping(ctx, inode, requests, vu_req)
1249 }
1250
1251 fn access(&self, ctx: &Context, inode: Self::Inode, mask: u32) -> io::Result<()> {
1252 self.deref().access(ctx, inode, mask)
1253 }
1254
1255 fn lseek(
1256 &self,
1257 ctx: &Context,
1258 inode: Self::Inode,
1259 handle: Self::Handle,
1260 offset: u64,
1261 whence: u32,
1262 ) -> io::Result<u64> {
1263 self.deref().lseek(ctx, inode, handle, offset, whence)
1264 }
1265
1266 /// Query file lock status
1267 fn getlk(
1268 &self,
1269 ctx: &Context,
1270 inode: Self::Inode,
1271 handle: Self::Handle,
1272 owner: u64,
1273 lock: FileLock,
1274 flags: u32,
1275 ) -> io::Result<FileLock> {
1276 self.deref().getlk(ctx, inode, handle, owner, lock, flags)
1277 }
1278
1279 /// Grab a file read lock
1280 fn setlk(
1281 &self,
1282 ctx: &Context,
1283 inode: Self::Inode,
1284 handle: Self::Handle,
1285 owner: u64,
1286 lock: FileLock,
1287 flags: u32,
1288 ) -> io::Result<()> {
1289 self.deref().setlk(ctx, inode, handle, owner, lock, flags)
1290 }
1291
1292 /// Grab a file write lock
1293 fn setlkw(
1294 &self,
1295 ctx: &Context,
1296 inode: Self::Inode,
1297 handle: Self::Handle,
1298 owner: u64,
1299 lock: FileLock,
1300 flags: u32,
1301 ) -> io::Result<()> {
1302 self.deref().setlkw(ctx, inode, handle, owner, lock, flags)
1303 }
1304
1305 /// send ioctl to the file
1306 #[allow(clippy::too_many_arguments)]
1307 fn ioctl(
1308 &self,
1309 ctx: &Context,
1310 inode: Self::Inode,
1311 handle: Self::Handle,
1312 flags: u32,
1313 cmd: u32,
1314 data: IoctlData,
1315 out_size: u32,
1316 ) -> io::Result<IoctlData> {
1317 self.deref()
1318 .ioctl(ctx, inode, handle, flags, cmd, data, out_size)
1319 }
1320
1321 /// Query a file's block mapping info
1322 fn bmap(
1323 &self,
1324 ctx: &Context,
1325 inode: Self::Inode,
1326 block: u64,
1327 blocksize: u32,
1328 ) -> io::Result<u64> {
1329 self.deref().bmap(ctx, inode, block, blocksize)
1330 }
1331
1332 /// Poll a file's events
1333 fn poll(
1334 &self,
1335 ctx: &Context,
1336 inode: Self::Inode,
1337 handle: Self::Handle,
1338 khandle: Self::Handle,
1339 flags: u32,
1340 events: u32,
1341 ) -> io::Result<u32> {
1342 self.deref()
1343 .poll(ctx, inode, handle, khandle, flags, events)
1344 }
1345
1346 /// Send notify reply.
1347 fn notify_reply(&self) -> io::Result<()> {
1348 self.deref().notify_reply()
1349 }
1350
1351 #[inline]
1352 fn id_remap(&self, ctx: &mut Context) -> io::Result<()> {
1353 self.deref().id_remap(ctx)
1354 }
1355}