Skip to content

Commit e375780

Browse files
committed
Merge tag 'fsnotify_for_v5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "The biggest part of this is support for fsnotify inode marks that don't pin inodes in memory but rather get evicted together with the inode (they are useful if userspace needs to exclude receipt of events from potentially large subtrees using fanotify ignore marks). There is also a fix for more consistent handling of events sent to parent and a fix of sparse(1) complaints" * tag 'fsnotify_for_v5.19-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fanotify: fix incorrect fmode_t casts fsnotify: consistent behavior for parent not watching children fsnotify: introduce mark type iterator fanotify: enable "evictable" inode marks fanotify: use fsnotify group lock helpers fanotify: implement "evictable" inode marks fanotify: factor out helper fanotify_mark_update_flags() fanotify: create helper fanotify_mark_user_flags() fsnotify: allow adding an inode mark without pinning inode dnotify: use fsnotify group lock helpers nfsd: use fsnotify group lock helpers audit: use fsnotify group lock helpers inotify: use fsnotify group lock helpers fsnotify: create helpers for group mark_mutex lock fsnotify: make allow_dups a property of the group fsnotify: pass flags argument to fsnotify_alloc_group() fsnotify: fix wrong lockdep annotations inotify: move control flags from mask to mark flags inotify: show inotify mask flags in proc fdinfo
2 parents 8b728ed + dccd855 commit e375780

18 files changed

Lines changed: 396 additions & 234 deletions

File tree

fs/nfsd/filecache.c

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -119,23 +119,24 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf)
119119
struct inode *inode = nf->nf_inode;
120120

121121
do {
122-
mutex_lock(&nfsd_file_fsnotify_group->mark_mutex);
122+
fsnotify_group_lock(nfsd_file_fsnotify_group);
123123
mark = fsnotify_find_mark(&inode->i_fsnotify_marks,
124-
nfsd_file_fsnotify_group);
124+
nfsd_file_fsnotify_group);
125125
if (mark) {
126126
nfm = nfsd_file_mark_get(container_of(mark,
127127
struct nfsd_file_mark,
128128
nfm_mark));
129-
mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex);
129+
fsnotify_group_unlock(nfsd_file_fsnotify_group);
130130
if (nfm) {
131131
fsnotify_put_mark(mark);
132132
break;
133133
}
134134
/* Avoid soft lockup race with nfsd_file_mark_put() */
135135
fsnotify_destroy_mark(mark, nfsd_file_fsnotify_group);
136136
fsnotify_put_mark(mark);
137-
} else
138-
mutex_unlock(&nfsd_file_fsnotify_group->mark_mutex);
137+
} else {
138+
fsnotify_group_unlock(nfsd_file_fsnotify_group);
139+
}
139140

140141
/* allocate a new nfm */
141142
new = kmem_cache_alloc(nfsd_file_mark_slab, GFP_KERNEL);
@@ -678,7 +679,8 @@ nfsd_file_cache_init(void)
678679
goto out_shrinker;
679680
}
680681

681-
nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops);
682+
nfsd_file_fsnotify_group = fsnotify_alloc_group(&nfsd_file_fsnotify_ops,
683+
FSNOTIFY_GROUP_NOFS);
682684
if (IS_ERR(nfsd_file_fsnotify_group)) {
683685
pr_err("nfsd: unable to create fsnotify group: %ld\n",
684686
PTR_ERR(nfsd_file_fsnotify_group));

fs/notify/dnotify/dnotify.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
168168
return;
169169
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
170170

171-
mutex_lock(&dnotify_group->mark_mutex);
171+
fsnotify_group_lock(dnotify_group);
172172

173173
spin_lock(&fsn_mark->lock);
174174
prev = &dn_mark->dn;
@@ -191,7 +191,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
191191
free = true;
192192
}
193193

194-
mutex_unlock(&dnotify_group->mark_mutex);
194+
fsnotify_group_unlock(dnotify_group);
195195

196196
if (free)
197197
fsnotify_free_mark(fsn_mark);
@@ -324,7 +324,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
324324
new_dn_mark->dn = NULL;
325325

326326
/* this is needed to prevent the fcntl/close race described below */
327-
mutex_lock(&dnotify_group->mark_mutex);
327+
fsnotify_group_lock(dnotify_group);
328328

329329
/* add the new_fsn_mark or find an old one. */
330330
fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group);
@@ -334,7 +334,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
334334
} else {
335335
error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0);
336336
if (error) {
337-
mutex_unlock(&dnotify_group->mark_mutex);
337+
fsnotify_group_unlock(dnotify_group);
338338
goto out_err;
339339
}
340340
spin_lock(&new_fsn_mark->lock);
@@ -383,7 +383,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
383383

384384
if (destroy)
385385
fsnotify_detach_mark(fsn_mark);
386-
mutex_unlock(&dnotify_group->mark_mutex);
386+
fsnotify_group_unlock(dnotify_group);
387387
if (destroy)
388388
fsnotify_free_mark(fsn_mark);
389389
fsnotify_put_mark(fsn_mark);
@@ -401,7 +401,8 @@ static int __init dnotify_init(void)
401401
SLAB_PANIC|SLAB_ACCOUNT);
402402
dnotify_mark_cache = KMEM_CACHE(dnotify_mark, SLAB_PANIC|SLAB_ACCOUNT);
403403

404-
dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops);
404+
dnotify_group = fsnotify_alloc_group(&dnotify_fsnotify_ops,
405+
FSNOTIFY_GROUP_NOFS);
405406
if (IS_ERR(dnotify_group))
406407
panic("unable to allocate fsnotify group for dnotify\n");
407408
dnotify_sysctl_init();

fs/notify/fanotify/fanotify.c

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -319,12 +319,8 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
319319
return 0;
320320
}
321321

322-
fsnotify_foreach_iter_type(type) {
323-
if (!fsnotify_iter_should_report_type(iter_info, type))
324-
continue;
325-
mark = iter_info->marks[type];
326-
327-
/* Apply ignore mask regardless of ISDIR and ON_CHILD flags */
322+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
323+
/* Apply ignore mask regardless of mark's ISDIR flag */
328324
marks_ignored_mask |= mark->ignored_mask;
329325

330326
/*
@@ -334,14 +330,6 @@ static u32 fanotify_group_event_mask(struct fsnotify_group *group,
334330
if (event_mask & FS_ISDIR && !(mark->mask & FS_ISDIR))
335331
continue;
336332

337-
/*
338-
* If the event is on a child and this mark is on a parent not
339-
* watching children, don't send it!
340-
*/
341-
if (type == FSNOTIFY_ITER_TYPE_PARENT &&
342-
!(mark->mask & FS_EVENT_ON_CHILD))
343-
continue;
344-
345333
marks_mask |= mark->mask;
346334

347335
/* Record the mark types of this group that matched the event */
@@ -849,16 +837,14 @@ static struct fanotify_event *fanotify_alloc_event(
849837
*/
850838
static __kernel_fsid_t fanotify_get_fsid(struct fsnotify_iter_info *iter_info)
851839
{
840+
struct fsnotify_mark *mark;
852841
int type;
853842
__kernel_fsid_t fsid = {};
854843

855-
fsnotify_foreach_iter_type(type) {
844+
fsnotify_foreach_iter_mark_type(iter_info, mark, type) {
856845
struct fsnotify_mark_connector *conn;
857846

858-
if (!fsnotify_iter_should_report_type(iter_info, type))
859-
continue;
860-
861-
conn = READ_ONCE(iter_info->marks[type]->connector);
847+
conn = READ_ONCE(mark->connector);
862848
/* Mark is just getting destroyed or created? */
863849
if (!conn)
864850
continue;

fs/notify/fanotify/fanotify.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,15 @@ static inline unsigned int fanotify_event_hash_bucket(
490490
{
491491
return event->hash & FANOTIFY_HTABLE_MASK;
492492
}
493+
494+
static inline unsigned int fanotify_mark_user_flags(struct fsnotify_mark *mark)
495+
{
496+
unsigned int mflags = 0;
497+
498+
if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
499+
mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
500+
if (mark->flags & FSNOTIFY_MARK_FLAG_NO_IREF)
501+
mflags |= FAN_MARK_EVICTABLE;
502+
503+
return mflags;
504+
}

fs/notify/fanotify/fanotify_user.c

Lines changed: 71 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -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

11221137
static 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

11711190
static 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

12041233
out:
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

Comments
 (0)