@@ -111,6 +111,16 @@ static bool fanotify_name_event_equal(struct fanotify_name_event *fne1,
111
111
return fanotify_info_equal (info1 , info2 );
112
112
}
113
113
114
+ static bool fanotify_error_event_equal (struct fanotify_error_event * fee1 ,
115
+ struct fanotify_error_event * fee2 )
116
+ {
117
+ /* Error events against the same file system are always merged. */
118
+ if (!fanotify_fsid_equal (& fee1 -> fsid , & fee2 -> fsid ))
119
+ return false;
120
+
121
+ return true;
122
+ }
123
+
114
124
static bool fanotify_should_merge (struct fanotify_event * old ,
115
125
struct fanotify_event * new )
116
126
{
@@ -141,6 +151,9 @@ static bool fanotify_should_merge(struct fanotify_event *old,
141
151
case FANOTIFY_EVENT_TYPE_FID_NAME :
142
152
return fanotify_name_event_equal (FANOTIFY_NE (old ),
143
153
FANOTIFY_NE (new ));
154
+ case FANOTIFY_EVENT_TYPE_FS_ERROR :
155
+ return fanotify_error_event_equal (FANOTIFY_EE (old ),
156
+ FANOTIFY_EE (new ));
144
157
default :
145
158
WARN_ON_ONCE (1 );
146
159
}
@@ -176,6 +189,10 @@ static int fanotify_merge(struct fsnotify_group *group,
176
189
break ;
177
190
if (fanotify_should_merge (old , new )) {
178
191
old -> mask |= new -> mask ;
192
+
193
+ if (fanotify_is_error_event (old -> mask ))
194
+ FANOTIFY_EE (old )-> err_count ++ ;
195
+
179
196
return 1 ;
180
197
}
181
198
}
@@ -343,13 +360,23 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
343
360
static int fanotify_encode_fh_len (struct inode * inode )
344
361
{
345
362
int dwords = 0 ;
363
+ int fh_len ;
346
364
347
365
if (!inode )
348
366
return 0 ;
349
367
350
368
exportfs_encode_inode_fh (inode , NULL , & dwords , NULL );
369
+ fh_len = dwords << 2 ;
370
+
371
+ /*
372
+ * struct fanotify_error_event might be preallocated and is
373
+ * limited to MAX_HANDLE_SZ. This should never happen, but
374
+ * safeguard by forcing an invalid file handle.
375
+ */
376
+ if (WARN_ON_ONCE (fh_len > MAX_HANDLE_SZ ))
377
+ return 0 ;
351
378
352
- return dwords << 2 ;
379
+ return fh_len ;
353
380
}
354
381
355
382
/*
@@ -370,8 +397,14 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
370
397
fh -> type = FILEID_ROOT ;
371
398
fh -> len = 0 ;
372
399
fh -> flags = 0 ;
400
+
401
+ /*
402
+ * Invalid FHs are used by FAN_FS_ERROR for errors not
403
+ * linked to any inode. The f_handle won't be reported
404
+ * back to userspace.
405
+ */
373
406
if (!inode )
374
- return 0 ;
407
+ goto out ;
375
408
376
409
/*
377
410
* !gpf means preallocated variable size fh, but fh_len could
@@ -403,8 +436,13 @@ static int fanotify_encode_fh(struct fanotify_fh *fh, struct inode *inode,
403
436
fh -> type = type ;
404
437
fh -> len = fh_len ;
405
438
406
- /* Mix fh into event merge key */
407
- * hash ^= fanotify_hash_fh (fh );
439
+ out :
440
+ /*
441
+ * Mix fh into event merge key. Hash might be NULL in case of
442
+ * unhashed FID events (i.e. FAN_FS_ERROR).
443
+ */
444
+ if (hash )
445
+ * hash ^= fanotify_hash_fh (fh );
408
446
409
447
return FANOTIFY_FH_HDR_LEN + fh_len ;
410
448
@@ -452,7 +490,7 @@ static struct inode *fanotify_dfid_inode(u32 event_mask, const void *data,
452
490
if (event_mask & ALL_FSNOTIFY_DIRENT_EVENTS )
453
491
return dir ;
454
492
455
- if (S_ISDIR (inode -> i_mode ))
493
+ if (inode && S_ISDIR (inode -> i_mode ))
456
494
return inode ;
457
495
458
496
return dir ;
@@ -563,6 +601,44 @@ static struct fanotify_event *fanotify_alloc_name_event(struct inode *id,
563
601
return & fne -> fae ;
564
602
}
565
603
604
+ static struct fanotify_event * fanotify_alloc_error_event (
605
+ struct fsnotify_group * group ,
606
+ __kernel_fsid_t * fsid ,
607
+ const void * data , int data_type ,
608
+ unsigned int * hash )
609
+ {
610
+ struct fs_error_report * report =
611
+ fsnotify_data_error_report (data , data_type );
612
+ struct inode * inode ;
613
+ struct fanotify_error_event * fee ;
614
+ int fh_len ;
615
+
616
+ if (WARN_ON_ONCE (!report ))
617
+ return NULL ;
618
+
619
+ fee = mempool_alloc (& group -> fanotify_data .error_events_pool , GFP_NOFS );
620
+ if (!fee )
621
+ return NULL ;
622
+
623
+ fee -> fae .type = FANOTIFY_EVENT_TYPE_FS_ERROR ;
624
+ fee -> error = report -> error ;
625
+ fee -> err_count = 1 ;
626
+ fee -> fsid = * fsid ;
627
+
628
+ inode = report -> inode ;
629
+ fh_len = fanotify_encode_fh_len (inode );
630
+
631
+ /* Bad fh_len. Fallback to using an invalid fh. Should never happen. */
632
+ if (!fh_len && inode )
633
+ inode = NULL ;
634
+
635
+ fanotify_encode_fh (& fee -> object_fh , inode , fh_len , NULL , 0 );
636
+
637
+ * hash ^= fanotify_hash_fsid (fsid );
638
+
639
+ return & fee -> fae ;
640
+ }
641
+
566
642
static struct fanotify_event * fanotify_alloc_event (struct fsnotify_group * group ,
567
643
u32 mask , const void * data ,
568
644
int data_type , struct inode * dir ,
@@ -630,6 +706,9 @@ static struct fanotify_event *fanotify_alloc_event(struct fsnotify_group *group,
630
706
631
707
if (fanotify_is_perm_event (mask )) {
632
708
event = fanotify_alloc_perm_event (path , gfp );
709
+ } else if (fanotify_is_error_event (mask )) {
710
+ event = fanotify_alloc_error_event (group , fsid , data ,
711
+ data_type , & hash );
633
712
} else if (name_event && (file_name || child )) {
634
713
event = fanotify_alloc_name_event (id , fsid , file_name , child ,
635
714
& hash , gfp );
@@ -702,6 +781,9 @@ static void fanotify_insert_event(struct fsnotify_group *group,
702
781
703
782
assert_spin_locked (& group -> notification_lock );
704
783
784
+ if (!fanotify_is_hashed_event (event -> mask ))
785
+ return ;
786
+
705
787
pr_debug ("%s: group=%p event=%p bucket=%u\n" , __func__ ,
706
788
group , event , bucket );
707
789
@@ -738,8 +820,9 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
738
820
BUILD_BUG_ON (FAN_ONDIR != FS_ISDIR );
739
821
BUILD_BUG_ON (FAN_OPEN_EXEC != FS_OPEN_EXEC );
740
822
BUILD_BUG_ON (FAN_OPEN_EXEC_PERM != FS_OPEN_EXEC_PERM );
823
+ BUILD_BUG_ON (FAN_FS_ERROR != FS_ERROR );
741
824
742
- BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 19 );
825
+ BUILD_BUG_ON (HWEIGHT32 (ALL_FANOTIFY_EVENT_BITS ) != 20 );
743
826
744
827
mask = fanotify_group_event_mask (group , iter_info , mask , data ,
745
828
data_type , dir );
@@ -778,9 +861,8 @@ static int fanotify_handle_event(struct fsnotify_group *group, u32 mask,
778
861
}
779
862
780
863
fsn_event = & event -> fse ;
781
- ret = fsnotify_add_event (group , fsn_event , fanotify_merge ,
782
- fanotify_is_hashed_event (mask ) ?
783
- fanotify_insert_event : NULL );
864
+ ret = fsnotify_insert_event (group , fsn_event , fanotify_merge ,
865
+ fanotify_insert_event );
784
866
if (ret ) {
785
867
/* Permission events shouldn't be merged */
786
868
BUG_ON (ret == 1 && mask & FANOTIFY_PERM_EVENTS );
@@ -805,6 +887,9 @@ static void fanotify_free_group_priv(struct fsnotify_group *group)
805
887
if (group -> fanotify_data .ucounts )
806
888
dec_ucount (group -> fanotify_data .ucounts ,
807
889
UCOUNT_FANOTIFY_GROUPS );
890
+
891
+ if (mempool_initialized (& group -> fanotify_data .error_events_pool ))
892
+ mempool_exit (& group -> fanotify_data .error_events_pool );
808
893
}
809
894
810
895
static void fanotify_free_path_event (struct fanotify_event * event )
@@ -833,7 +918,16 @@ static void fanotify_free_name_event(struct fanotify_event *event)
833
918
kfree (FANOTIFY_NE (event ));
834
919
}
835
920
836
- static void fanotify_free_event (struct fsnotify_event * fsn_event )
921
+ static void fanotify_free_error_event (struct fsnotify_group * group ,
922
+ struct fanotify_event * event )
923
+ {
924
+ struct fanotify_error_event * fee = FANOTIFY_EE (event );
925
+
926
+ mempool_free (fee , & group -> fanotify_data .error_events_pool );
927
+ }
928
+
929
+ static void fanotify_free_event (struct fsnotify_group * group ,
930
+ struct fsnotify_event * fsn_event )
837
931
{
838
932
struct fanotify_event * event ;
839
933
@@ -855,6 +949,9 @@ static void fanotify_free_event(struct fsnotify_event *fsn_event)
855
949
case FANOTIFY_EVENT_TYPE_OVERFLOW :
856
950
kfree (event );
857
951
break ;
952
+ case FANOTIFY_EVENT_TYPE_FS_ERROR :
953
+ fanotify_free_error_event (group , event );
954
+ break ;
858
955
default :
859
956
WARN_ON_ONCE (1 );
860
957
}
0 commit comments