@@ -14,6 +14,9 @@ use std::path::{Path, PathBuf};
1414use std:: sync:: { Arc , Mutex } ;
1515use std:: thread:: { self , JoinHandle } ;
1616
17+ use std:: sync:: mpsc;
18+
19+ use super :: deferred_notify:: { DeferredNotifier , NotifyOp } ;
1720use super :: ll:: fuse_abi as abi;
1821use super :: request:: Request ;
1922use super :: Filesystem ;
@@ -64,6 +67,10 @@ pub struct Session<FS: Filesystem> {
6467 pub ( crate ) initialized : bool ,
6568 /// True if the filesystem was destroyed (destroy operation done)
6669 pub ( crate ) destroyed : bool ,
70+ /// Sender half of the deferred notification queue
71+ notify_tx : Option < mpsc:: Sender < NotifyOp > > ,
72+ /// Receiver half — moved to the notify thread in run()
73+ notify_rx : Option < mpsc:: Receiver < NotifyOp > > ,
6774}
6875
6976impl < FS : Filesystem > AsFd for Session < FS > {
@@ -109,6 +116,8 @@ impl<FS: Filesystem> Session<FS> {
109116 SessionACL :: Owner
110117 } ;
111118
119+ let ( notify_tx, notify_rx) = mpsc:: channel ( ) ;
120+
112121 Ok ( Session {
113122 filesystem,
114123 ch,
@@ -119,13 +128,16 @@ impl<FS: Filesystem> Session<FS> {
119128 proto_minor : 0 ,
120129 initialized : false ,
121130 destroyed : false ,
131+ notify_tx : Some ( notify_tx) ,
132+ notify_rx : Some ( notify_rx) ,
122133 } )
123134 }
124135
125136 /// Wrap an existing /dev/fuse file descriptor. This doesn't mount the
126137 /// filesystem anywhere; that must be done separately.
127138 pub fn from_fd ( filesystem : FS , fd : OwnedFd , acl : SessionACL ) -> Self {
128139 let ch = Channel :: new ( Arc :: new ( fd. into ( ) ) ) ;
140+ let ( notify_tx, notify_rx) = mpsc:: channel ( ) ;
129141 Session {
130142 filesystem,
131143 ch,
@@ -136,6 +148,8 @@ impl<FS: Filesystem> Session<FS> {
136148 proto_minor : 0 ,
137149 initialized : false ,
138150 destroyed : false ,
151+ notify_tx : Some ( notify_tx) ,
152+ notify_rx : Some ( notify_rx) ,
139153 }
140154 }
141155
@@ -146,20 +160,43 @@ impl<FS: Filesystem> Session<FS> {
146160 /// # Errors
147161 /// Returns any final error when the session comes to an end.
148162 pub fn run ( & mut self ) -> io:: Result < ( ) > {
163+ let notify_rx = self . notify_rx . take ( ) . expect ( "run() called more than once" ) ;
164+ let notifier = self . notifier ( ) ;
165+ let notify_handle = thread:: spawn ( move || {
166+ for op in notify_rx {
167+ let res = match op {
168+ NotifyOp :: InvalEntry { parent, ref name } => {
169+ notifier. inval_entry ( parent, name. as_os_str ( ) )
170+ }
171+ } ;
172+ if let Err ( e) = res {
173+ debug ! ( "FUSE notify failed: {e}" ) ;
174+ }
175+ }
176+ } ) ;
177+
178+ // A single DeferredNotifier shared by all requests in this session,
179+ // avoiding a Sender clone on every FUSE request dispatch.
180+ let deferred =
181+ DeferredNotifier :: new ( self . notify_tx . as_ref ( ) . expect ( "notify_tx missing" ) . clone ( ) ) ;
182+
149183 // Buffer for receiving requests from the kernel. Only one is allocated and
150184 // it is reused immediately after dispatching to conserve memory and allocations.
151185 let mut buffer = vec ! [ 0 ; BUFFER_SIZE ] ;
152186 let buf = aligned_sub_buf ( & mut buffer, std:: mem:: align_of :: < abi:: fuse_in_header > ( ) ) ;
187+ let mut result = Ok ( ( ) ) ;
153188 loop {
154189 // Read the next request from the given channel to kernel driver
155190 // The kernel driver makes sure that we get exactly one request per read
156191 match self . ch . receive ( buf) {
157- Ok ( size) => match Request :: new ( self . ch . sender ( ) , & buf[ ..size] ) {
158- // Dispatch request
159- Some ( req) => req. dispatch ( self ) ,
160- // Quit loop on illegal request
161- None => break ,
162- } ,
192+ Ok ( size) => {
193+ match Request :: new ( self . ch . sender ( ) , & deferred, & buf[ ..size] ) {
194+ // Dispatch request
195+ Some ( req) => req. dispatch ( self ) ,
196+ // Quit loop on illegal request
197+ None => break ,
198+ }
199+ }
163200 Err ( err) => match err. raw_os_error ( ) {
164201 Some (
165202 ENOENT // Operation interrupted. Accordingly to FUSE, this is safe to retry
@@ -168,11 +205,23 @@ impl<FS: Filesystem> Session<FS> {
168205 ) => continue ,
169206 Some ( ENODEV ) => break ,
170207 // Unhandled error
171- _ => return Err ( err) ,
208+ _ => {
209+ result = Err ( err) ;
210+ break ;
211+ }
172212 } ,
173213 }
174214 }
175- Ok ( ( ) )
215+
216+ // Drop all senders to close the channel, then join the notify thread
217+ // to ensure in-flight invalidations are flushed before returning.
218+ drop ( deferred) ;
219+ self . notify_tx . take ( ) ;
220+ if let Err ( e) = notify_handle. join ( ) {
221+ warn ! ( "notify thread panicked: {e:?}" ) ;
222+ }
223+
224+ result
176225 }
177226
178227 /// Unmount the filesystem
0 commit comments