Skip to main content

async_fuser/
notify.rs

1#[allow(unused)]
2use std::convert::TryInto;
3#[allow(unused)]
4use std::ffi::OsStr;
5use std::io;
6
7use crate::INodeNo;
8use crate::channel::ChannelSender;
9use crate::ll::fuse_abi::fuse_notify_code as notify_code;
10use crate::ll::notify::Notification;
11
12/// A handle to a pending `poll()` request.
13#[derive(Copy, Clone, Debug)]
14pub struct PollHandle(pub u64);
15
16/// A [handle](PollHandle) to a pending `poll()` request coupled with notifier reference.
17/// Can be saved and used to notify the kernel when a poll is ready.
18#[derive(Clone)]
19pub struct PollNotifier {
20    handle: PollHandle,
21    notifier: Notifier,
22}
23
24impl PollNotifier {
25    pub(crate) fn new(cs: ChannelSender, kh: PollHandle) -> Self {
26        Self {
27            handle: kh,
28            notifier: Notifier::new(cs),
29        }
30    }
31
32    /// Handle associated with this poll notifier.
33    pub fn handle(&self) -> PollHandle {
34        self.handle
35    }
36
37    /// Notify the kernel that the associated file handle is ready to be polled.
38    /// # Errors
39    /// Returns an error if the kernel rejects the notification.
40    pub fn notify(self) -> io::Result<()> {
41        self.notifier.poll(self.handle)
42    }
43}
44
45impl std::fmt::Debug for PollNotifier {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        f.debug_tuple("PollHandle").field(&self.handle).finish()
48    }
49}
50
51/// A handle by which the application can send notifications to the server
52#[derive(Debug, Clone)]
53pub struct Notifier(ChannelSender);
54
55impl Notifier {
56    pub(crate) fn new(cs: ChannelSender) -> Self {
57        Self(cs)
58    }
59
60    /// Notify poll clients of I/O readiness
61    /// # Errors
62    /// Returns an error if the kernel rejects the notification.
63    pub fn poll(&self, kh: PollHandle) -> io::Result<()> {
64        let notif = Notification::new_poll(kh);
65        self.send(notify_code::FUSE_POLL, &notif)
66    }
67
68    /// Invalidate the kernel cache for a given directory entry
69    /// # Errors
70    /// Returns an error if the notification data is too large.
71    /// Returns an error if the kernel rejects the notification.
72    pub fn inval_entry(&self, parent: INodeNo, name: &OsStr) -> io::Result<()> {
73        let notif = Notification::new_inval_entry(parent, name).map_err(Self::too_big_err)?;
74        self.send_inval(notify_code::FUSE_NOTIFY_INVAL_ENTRY, &notif)
75    }
76
77    /// Invalidate the kernel cache for a given inode (metadata and
78    /// data in the given range)
79    /// # Errors
80    /// Returns an error if the kernel rejects the notification.
81    pub fn inval_inode(&self, ino: INodeNo, offset: i64, len: i64) -> io::Result<()> {
82        let notif = Notification::new_inval_inode(ino, offset, len);
83        self.send_inval(notify_code::FUSE_NOTIFY_INVAL_INODE, &notif)
84    }
85
86    /// Update the kernel's cached copy of a given inode's data
87    /// # Errors
88    /// Returns an error if the notification data is too large.
89    /// Returns an error if the kernel rejects the notification.
90    pub fn store(&self, ino: INodeNo, offset: u64, data: &[u8]) -> io::Result<()> {
91        let notif = Notification::new_store(ino, offset, data).map_err(Self::too_big_err)?;
92        // Not strictly an invalidate, but the inode we're operating
93        // on may have been evicted anyway, so treat is as such
94        self.send_inval(notify_code::FUSE_NOTIFY_STORE, &notif)
95    }
96
97    /// Invalidate the kernel cache for a given directory entry and inform
98    /// inotify watchers of a file deletion.
99    /// # Errors
100    /// Returns an error if the notification data is too large.
101    /// Returns an error if the kernel rejects the notification.
102    pub fn delete(&self, parent: INodeNo, child: INodeNo, name: &OsStr) -> io::Result<()> {
103        let notif = Notification::new_delete(parent, child, name).map_err(Self::too_big_err)?;
104        self.send_inval(notify_code::FUSE_NOTIFY_DELETE, &notif)
105    }
106
107    #[allow(unused)]
108    fn send_inval(&self, code: notify_code, notification: &Notification<'_>) -> io::Result<()> {
109        match self.send(code, notification) {
110            // ENOENT is harmless for an invalidation (the
111            // kernel may have already dropped the cached
112            // entry on its own anyway), so ignore it.
113            Err(e) if e.kind() == io::ErrorKind::NotFound => Ok(()),
114            x => x,
115        }
116    }
117
118    fn send(&self, code: notify_code, notification: &Notification<'_>) -> io::Result<()> {
119        notification
120            .with_iovec(code, |iov| self.0.send(iov))
121            .map_err(Self::too_big_err)?
122    }
123
124    /// Create an error for indicating when a notification message
125    /// would exceed the capacity that its length descriptor field is
126    /// capable of encoding.
127    fn too_big_err(tfie: std::num::TryFromIntError) -> io::Error {
128        io::Error::new(io::ErrorKind::Other, format!("Data too large: {tfie:?}"))
129    }
130}