@@ -53,6 +53,23 @@ static bool fanotify_fid_event_equal(struct fanotify_fid_event *ffe1,
53
53
fanotify_fh_equal (& ffe1 -> object_fh , & ffe2 -> object_fh );
54
54
}
55
55
56
+ static bool fanotify_name_event_equal (struct fanotify_name_event * fne1 ,
57
+ struct fanotify_name_event * fne2 )
58
+ {
59
+ /*
60
+ * Do not merge name events without dir fh.
61
+ * FAN_DIR_MODIFY does not encode object fh, so it may be empty.
62
+ */
63
+ if (!fne1 -> dir_fh .len )
64
+ return false;
65
+
66
+ if (fne1 -> name_len != fne2 -> name_len ||
67
+ !fanotify_fh_equal (& fne1 -> dir_fh , & fne2 -> dir_fh ))
68
+ return false;
69
+
70
+ return !memcmp (fne1 -> name , fne2 -> name , fne1 -> name_len );
71
+ }
72
+
56
73
static bool should_merge (struct fsnotify_event * old_fsn ,
57
74
struct fsnotify_event * new_fsn )
58
75
{
@@ -84,6 +101,9 @@ static bool should_merge(struct fsnotify_event *old_fsn,
84
101
85
102
return fanotify_fid_event_equal (FANOTIFY_FE (old ),
86
103
FANOTIFY_FE (new ));
104
+ case FANOTIFY_EVENT_TYPE_FID_NAME :
105
+ return fanotify_name_event_equal (FANOTIFY_NE (old ),
106
+ FANOTIFY_NE (new ));
87
107
default :
88
108
WARN_ON_ONCE (1 );
89
109
}
@@ -262,6 +282,9 @@ static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
262
282
void * buf = fh -> buf ;
263
283
int err ;
264
284
285
+ if (!inode )
286
+ goto out ;
287
+
265
288
dwords = 0 ;
266
289
err = - ENOENT ;
267
290
type = exportfs_encode_inode_fh (inode , NULL , & dwords , NULL );
@@ -295,6 +318,7 @@ static void fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
295
318
type , bytes , err );
296
319
kfree (ext_buf );
297
320
* fanotify_fh_ext_buf_ptr (fh ) = NULL ;
321
+ out :
298
322
/* Report the event without a file identifier on encode error */
299
323
fh -> type = FILEID_INVALID ;
300
324
fh -> len = 0 ;
@@ -320,10 +344,12 @@ static struct inode *fanotify_fid_inode(struct inode *to_tell, u32 event_mask,
320
344
struct fanotify_event * fanotify_alloc_event (struct fsnotify_group * group ,
321
345
struct inode * inode , u32 mask ,
322
346
const void * data , int data_type ,
347
+ const struct qstr * file_name ,
323
348
__kernel_fsid_t * fsid )
324
349
{
325
350
struct fanotify_event * event = NULL ;
326
351
struct fanotify_fid_event * ffe = NULL ;
352
+ struct fanotify_name_event * fne = NULL ;
327
353
gfp_t gfp = GFP_KERNEL_ACCOUNT ;
328
354
struct inode * id = fanotify_fid_inode (inode , mask , data , data_type );
329
355
const struct path * path = fsnotify_data_path (data , data_type );
@@ -356,6 +382,23 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
356
382
goto init ;
357
383
}
358
384
385
+ /*
386
+ * For FAN_DIR_MODIFY event, we report the fid of the directory and
387
+ * the name of the modified entry.
388
+ * Allocate an fanotify_name_event struct and copy the name.
389
+ */
390
+ if (mask & FAN_DIR_MODIFY && !(WARN_ON_ONCE (!file_name ))) {
391
+ fne = kmalloc (sizeof (* fne ) + file_name -> len + 1 , gfp );
392
+ if (!fne )
393
+ goto out ;
394
+
395
+ event = & fne -> fae ;
396
+ event -> type = FANOTIFY_EVENT_TYPE_FID_NAME ;
397
+ fne -> name_len = file_name -> len ;
398
+ strcpy (fne -> name , file_name -> name );
399
+ goto init ;
400
+ }
401
+
359
402
if (FAN_GROUP_FLAG (group , FAN_REPORT_FID )) {
360
403
ffe = kmem_cache_alloc (fanotify_fid_event_cachep , gfp );
361
404
if (!ffe )
@@ -374,7 +417,7 @@ struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
374
417
event -> type = FANOTIFY_EVENT_TYPE_PATH ;
375
418
}
376
419
377
- init : __maybe_unused
420
+ init :
378
421
/*
379
422
* Use the victim inode instead of the watching inode as the id for
380
423
* event queue, so event reported on parent is merged with event
@@ -387,13 +430,16 @@ init: __maybe_unused
387
430
else
388
431
event -> pid = get_pid (task_tgid (current ));
389
432
390
- if (fanotify_event_object_fh (event )) {
391
- ffe -> object_fh .len = 0 ;
392
- if (fsid )
393
- ffe -> fsid = * fsid ;
394
- if (id )
395
- fanotify_encode_fh (& ffe -> object_fh , id , gfp );
396
- } else if (fanotify_event_has_path (event )) {
433
+ if (fsid && fanotify_event_fsid (event ))
434
+ * fanotify_event_fsid (event ) = * fsid ;
435
+
436
+ if (fanotify_event_object_fh (event ))
437
+ fanotify_encode_fh (fanotify_event_object_fh (event ), id , gfp );
438
+
439
+ if (fanotify_event_dir_fh (event ))
440
+ fanotify_encode_fh (fanotify_event_dir_fh (event ), id , gfp );
441
+
442
+ if (fanotify_event_has_path (event )) {
397
443
struct path * p = fanotify_event_path (event );
398
444
399
445
if (path ) {
@@ -501,7 +547,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
501
547
}
502
548
503
549
event = fanotify_alloc_event (group , inode , mask , data , data_type ,
504
- & fsid );
550
+ file_name , & fsid );
505
551
ret = - ENOMEM ;
506
552
if (unlikely (!event )) {
507
553
/*
@@ -563,6 +609,15 @@ static void fanotify_free_fid_event(struct fanotify_event *event)
563
609
kmem_cache_free (fanotify_fid_event_cachep , ffe );
564
610
}
565
611
612
+ static void fanotify_free_name_event (struct fanotify_event * event )
613
+ {
614
+ struct fanotify_name_event * fne = FANOTIFY_NE (event );
615
+
616
+ if (fanotify_fh_has_ext_buf (& fne -> dir_fh ))
617
+ kfree (fanotify_fh_ext_buf (& fne -> dir_fh ));
618
+ kfree (fne );
619
+ }
620
+
566
621
static void fanotify_free_event (struct fsnotify_event * fsn_event )
567
622
{
568
623
struct fanotify_event * event ;
@@ -579,6 +634,9 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
579
634
case FANOTIFY_EVENT_TYPE_FID :
580
635
fanotify_free_fid_event (event );
581
636
break ;
637
+ case FANOTIFY_EVENT_TYPE_FID_NAME :
638
+ fanotify_free_name_event (event );
639
+ break ;
582
640
default :
583
641
WARN_ON_ONCE (1 );
584
642
}
0 commit comments