1
1
use crate :: * ;
2
+ use nix:: errno:: Errno ;
2
3
use nix:: sys:: fanotify:: {
3
4
EventFFlags , Fanotify , FanotifyResponse , InitFlags , MarkFlags , MaskFlags ,
4
5
Response ,
5
6
} ;
6
- use std:: fs:: { read_link, File , OpenOptions } ;
7
+ use std:: fs:: { read_link, read_to_string , File , OpenOptions } ;
7
8
use std:: io:: ErrorKind ;
8
9
use std:: io:: { Read , Write } ;
9
10
use std:: os:: fd:: AsRawFd ;
@@ -16,6 +17,7 @@ pub fn test_fanotify() {
16
17
17
18
test_fanotify_notifications ( ) ;
18
19
test_fanotify_responses ( ) ;
20
+ test_fanotify_overflow ( ) ;
19
21
}
20
22
21
23
fn test_fanotify_notifications ( ) {
@@ -147,3 +149,71 @@ fn test_fanotify_responses() {
147
149
148
150
file_thread. join ( ) . unwrap ( ) ;
149
151
}
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