@@ -264,7 +264,7 @@ static int create_fd(struct fsnotify_group *group, struct path *path,
264264 * originally opened O_WRONLY.
265265 */
266266 new_file = dentry_open (path ,
267- group -> fanotify_data .f_flags | FMODE_NONOTIFY ,
267+ group -> fanotify_data .f_flags | __FMODE_NONOTIFY ,
268268 current_cred ());
269269 if (IS_ERR (new_file )) {
270270 /*
@@ -1035,10 +1035,10 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
10351035 __u32 removed ;
10361036 int destroy_mark ;
10371037
1038- mutex_lock ( & group -> mark_mutex );
1038+ fsnotify_group_lock ( group );
10391039 fsn_mark = fsnotify_find_mark (connp , group );
10401040 if (!fsn_mark ) {
1041- mutex_unlock ( & group -> mark_mutex );
1041+ fsnotify_group_unlock ( group );
10421042 return - ENOENT ;
10431043 }
10441044
@@ -1048,7 +1048,7 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
10481048 fsnotify_recalc_mask (fsn_mark -> connector );
10491049 if (destroy_mark )
10501050 fsnotify_detach_mark (fsn_mark );
1051- mutex_unlock ( & group -> mark_mutex );
1051+ fsnotify_group_unlock ( group );
10521052 if (destroy_mark )
10531053 fsnotify_free_mark (fsn_mark );
10541054
@@ -1081,47 +1081,63 @@ static int fanotify_remove_inode_mark(struct fsnotify_group *group,
10811081 flags , umask );
10821082}
10831083
1084- static void fanotify_mark_add_ignored_mask (struct fsnotify_mark * fsn_mark ,
1085- __u32 mask , unsigned int flags ,
1086- __u32 * removed )
1084+ static bool fanotify_mark_update_flags (struct fsnotify_mark * fsn_mark ,
1085+ unsigned int fan_flags )
10871086{
1088- fsn_mark -> ignored_mask |= mask ;
1087+ bool want_iref = !(fan_flags & FAN_MARK_EVICTABLE );
1088+ bool recalc = false;
10891089
10901090 /*
10911091 * Setting FAN_MARK_IGNORED_SURV_MODIFY for the first time may lead to
10921092 * the removal of the FS_MODIFY bit in calculated mask if it was set
10931093 * because of an ignored mask that is now going to survive FS_MODIFY.
10941094 */
1095- if ((flags & FAN_MARK_IGNORED_SURV_MODIFY ) &&
1095+ if ((fan_flags & FAN_MARK_IGNORED_MASK ) &&
1096+ (fan_flags & FAN_MARK_IGNORED_SURV_MODIFY ) &&
10961097 !(fsn_mark -> flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY )) {
10971098 fsn_mark -> flags |= FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY ;
10981099 if (!(fsn_mark -> mask & FS_MODIFY ))
1099- * removed = FS_MODIFY ;
1100+ recalc = true ;
11001101 }
1102+
1103+ if (fsn_mark -> connector -> type != FSNOTIFY_OBJ_TYPE_INODE ||
1104+ want_iref == !(fsn_mark -> flags & FSNOTIFY_MARK_FLAG_NO_IREF ))
1105+ return recalc ;
1106+
1107+ /*
1108+ * NO_IREF may be removed from a mark, but not added.
1109+ * When removed, fsnotify_recalc_mask() will take the inode ref.
1110+ */
1111+ WARN_ON_ONCE (!want_iref );
1112+ fsn_mark -> flags &= ~FSNOTIFY_MARK_FLAG_NO_IREF ;
1113+
1114+ return true;
11011115}
11021116
1103- static __u32 fanotify_mark_add_to_mask (struct fsnotify_mark * fsn_mark ,
1104- __u32 mask , unsigned int flags ,
1105- __u32 * removed )
1117+ static bool fanotify_mark_add_to_mask (struct fsnotify_mark * fsn_mark ,
1118+ __u32 mask , unsigned int fan_flags )
11061119{
1107- __u32 oldmask , newmask ;
1120+ bool recalc ;
11081121
11091122 spin_lock (& fsn_mark -> lock );
1110- oldmask = fsnotify_calc_mask (fsn_mark );
1111- if (!(flags & FAN_MARK_IGNORED_MASK )) {
1123+ if (!(fan_flags & FAN_MARK_IGNORED_MASK ))
11121124 fsn_mark -> mask |= mask ;
1113- } else {
1114- fanotify_mark_add_ignored_mask (fsn_mark , mask , flags , removed );
1115- }
1116- newmask = fsnotify_calc_mask (fsn_mark );
1125+ else
1126+ fsn_mark -> ignored_mask |= mask ;
1127+
1128+ recalc = fsnotify_calc_mask (fsn_mark ) &
1129+ ~fsnotify_conn_mask (fsn_mark -> connector );
1130+
1131+ recalc |= fanotify_mark_update_flags (fsn_mark , fan_flags );
11171132 spin_unlock (& fsn_mark -> lock );
11181133
1119- return newmask & ~ oldmask ;
1134+ return recalc ;
11201135}
11211136
11221137static struct fsnotify_mark * fanotify_add_new_mark (struct fsnotify_group * group ,
11231138 fsnotify_connp_t * connp ,
11241139 unsigned int obj_type ,
1140+ unsigned int fan_flags ,
11251141 __kernel_fsid_t * fsid )
11261142{
11271143 struct ucounts * ucounts = group -> fanotify_data .ucounts ;
@@ -1144,6 +1160,9 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
11441160 }
11451161
11461162 fsnotify_init_mark (mark , group );
1163+ if (fan_flags & FAN_MARK_EVICTABLE )
1164+ mark -> flags |= FSNOTIFY_MARK_FLAG_NO_IREF ;
1165+
11471166 ret = fsnotify_add_mark_locked (mark , connp , obj_type , 0 , fsid );
11481167 if (ret ) {
11491168 fsnotify_put_mark (mark );
@@ -1170,39 +1189,49 @@ static int fanotify_group_init_error_pool(struct fsnotify_group *group)
11701189
11711190static int fanotify_add_mark (struct fsnotify_group * group ,
11721191 fsnotify_connp_t * connp , unsigned int obj_type ,
1173- __u32 mask , unsigned int flags ,
1192+ __u32 mask , unsigned int fan_flags ,
11741193 __kernel_fsid_t * fsid )
11751194{
11761195 struct fsnotify_mark * fsn_mark ;
1177- __u32 added , removed = 0 ;
1196+ bool recalc ;
11781197 int ret = 0 ;
11791198
1180- mutex_lock ( & group -> mark_mutex );
1199+ fsnotify_group_lock ( group );
11811200 fsn_mark = fsnotify_find_mark (connp , group );
11821201 if (!fsn_mark ) {
1183- fsn_mark = fanotify_add_new_mark (group , connp , obj_type , fsid );
1202+ fsn_mark = fanotify_add_new_mark (group , connp , obj_type ,
1203+ fan_flags , fsid );
11841204 if (IS_ERR (fsn_mark )) {
1185- mutex_unlock ( & group -> mark_mutex );
1205+ fsnotify_group_unlock ( group );
11861206 return PTR_ERR (fsn_mark );
11871207 }
11881208 }
11891209
1210+ /*
1211+ * Non evictable mark cannot be downgraded to evictable mark.
1212+ */
1213+ if (fan_flags & FAN_MARK_EVICTABLE &&
1214+ !(fsn_mark -> flags & FSNOTIFY_MARK_FLAG_NO_IREF )) {
1215+ ret = - EEXIST ;
1216+ goto out ;
1217+ }
1218+
11901219 /*
11911220 * Error events are pre-allocated per group, only if strictly
11921221 * needed (i.e. FAN_FS_ERROR was requested).
11931222 */
1194- if (!(flags & FAN_MARK_IGNORED_MASK ) && (mask & FAN_FS_ERROR )) {
1223+ if (!(fan_flags & FAN_MARK_IGNORED_MASK ) && (mask & FAN_FS_ERROR )) {
11951224 ret = fanotify_group_init_error_pool (group );
11961225 if (ret )
11971226 goto out ;
11981227 }
11991228
1200- added = fanotify_mark_add_to_mask (fsn_mark , mask , flags , & removed );
1201- if (removed || ( added & ~ fsnotify_conn_mask ( fsn_mark -> connector )) )
1229+ recalc = fanotify_mark_add_to_mask (fsn_mark , mask , fan_flags );
1230+ if (recalc )
12021231 fsnotify_recalc_mask (fsn_mark -> connector );
12031232
12041233out :
1205- mutex_unlock ( & group -> mark_mutex );
1234+ fsnotify_group_unlock ( group );
12061235
12071236 fsnotify_put_mark (fsn_mark );
12081237 return ret ;
@@ -1348,14 +1377,15 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
13481377 (!(fid_mode & FAN_REPORT_NAME ) || !(fid_mode & FAN_REPORT_FID )))
13491378 return - EINVAL ;
13501379
1351- f_flags = O_RDWR | FMODE_NONOTIFY ;
1380+ f_flags = O_RDWR | __FMODE_NONOTIFY ;
13521381 if (flags & FAN_CLOEXEC )
13531382 f_flags |= O_CLOEXEC ;
13541383 if (flags & FAN_NONBLOCK )
13551384 f_flags |= O_NONBLOCK ;
13561385
13571386 /* fsnotify_alloc_group takes a ref. Dropped in fanotify_release */
1358- group = fsnotify_alloc_user_group (& fanotify_fsnotify_ops );
1387+ group = fsnotify_alloc_group (& fanotify_fsnotify_ops ,
1388+ FSNOTIFY_GROUP_USER | FSNOTIFY_GROUP_NOFS );
13591389 if (IS_ERR (group )) {
13601390 return PTR_ERR (group );
13611391 }
@@ -1597,6 +1627,14 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
15971627 mark_type != FAN_MARK_FILESYSTEM )
15981628 goto fput_and_out ;
15991629
1630+ /*
1631+ * Evictable is only relevant for inode marks, because only inode object
1632+ * can be evicted on memory pressure.
1633+ */
1634+ if (flags & FAN_MARK_EVICTABLE &&
1635+ mark_type != FAN_MARK_INODE )
1636+ goto fput_and_out ;
1637+
16001638 /*
16011639 * Events that do not carry enough information to report
16021640 * event->fd require a group that supports reporting fid. Those
@@ -1762,7 +1800,7 @@ static int __init fanotify_user_setup(void)
17621800
17631801 BUILD_BUG_ON (FANOTIFY_INIT_FLAGS & FANOTIFY_INTERNAL_GROUP_FLAGS );
17641802 BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_INIT_FLAGS ) != 12 );
1765- BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_MARK_FLAGS ) != 9 );
1803+ BUILD_BUG_ON (HWEIGHT32 (FANOTIFY_MARK_FLAGS ) != 10 );
17661804
17671805 fanotify_mark_cache = KMEM_CACHE (fsnotify_mark ,
17681806 SLAB_PANIC |SLAB_ACCOUNT );
0 commit comments