11use crate :: * ;
2+ use nix:: errno:: Errno ;
23use nix:: sys:: fanotify:: {
34 EventFFlags , Fanotify , FanotifyResponse , InitFlags , MarkFlags , MaskFlags ,
45 Response ,
56} ;
6- use std:: fs:: { read_link, File , OpenOptions } ;
7+ use std:: fs:: { read_link, read_to_string , File , OpenOptions } ;
78use std:: io:: ErrorKind ;
89use std:: io:: { Read , Write } ;
910use std:: os:: fd:: AsRawFd ;
@@ -16,6 +17,7 @@ pub fn test_fanotify() {
1617
1718 test_fanotify_notifications ( ) ;
1819 test_fanotify_responses ( ) ;
20+ test_fanotify_overflow ( ) ;
1921}
2022
2123fn test_fanotify_notifications ( ) {
@@ -147,3 +149,71 @@ fn test_fanotify_responses() {
147149
148150 file_thread. join ( ) . unwrap ( ) ;
149151}
152+
153+ fn test_fanotify_overflow ( ) {
154+ let max_events: usize =
155+ read_to_string ( "/proc/sys/fs/fanotify/max_queued_events" )
156+ . unwrap ( )
157+ . trim ( )
158+ . parse ( )
159+ . unwrap ( ) ;
160+
161+ // make sure the kernel is configured with the default value,
162+ // just so this test doesn't run forever
163+ assert_eq ! ( max_events, 16384 ) ;
164+
165+ let group = Fanotify :: init (
166+ InitFlags :: FAN_CLASS_NOTIF
167+ | InitFlags :: FAN_REPORT_TID
168+ | InitFlags :: FAN_NONBLOCK ,
169+ EventFFlags :: O_RDONLY ,
170+ )
171+ . unwrap ( ) ;
172+ let tempdir = tempfile:: tempdir ( ) . unwrap ( ) ;
173+ let tempfile = tempdir. path ( ) . join ( "test" ) ;
174+
175+ OpenOptions :: new ( )
176+ . write ( true )
177+ . create_new ( true )
178+ . open ( & tempfile)
179+ . unwrap ( ) ;
180+
181+ group
182+ . mark (
183+ MarkFlags :: FAN_MARK_ADD ,
184+ MaskFlags :: FAN_OPEN ,
185+ None ,
186+ Some ( & tempfile) ,
187+ )
188+ . unwrap ( ) ;
189+
190+ thread:: scope ( |s| {
191+ // perform 10 more events to demonstrate some will be dropped
192+ for _ in 0 ..( max_events + 10 ) {
193+ s. spawn ( || {
194+ File :: open ( & tempfile) . unwrap ( ) ;
195+ } ) ;
196+ }
197+ } ) ;
198+
199+ // flush the queue until it's empty
200+ let mut n = 0 ;
201+ let mut last_event = None ;
202+ loop {
203+ match group. read_events ( ) {
204+ Ok ( events) => {
205+ n += events. len ( ) ;
206+ if let Some ( event) = events. last ( ) {
207+ last_event = Some ( event. mask ( ) ) ;
208+ }
209+ }
210+ Err ( e) if e == Errno :: EWOULDBLOCK => break ,
211+ Err ( e) => panic ! ( "{e:?}" ) ,
212+ }
213+ }
214+
215+ // make sure we read all we expected.
216+ // the +1 is for the overflow event.
217+ assert_eq ! ( n, max_events + 1 ) ;
218+ assert_eq ! ( last_event, Some ( MaskFlags :: FAN_Q_OVERFLOW ) ) ;
219+ }
0 commit comments