Skip to content

Commit 5af9d1c

Browse files
committed
Merge tag 'fsnotify_for_v6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: - reduce overhead of fsnotify infrastructure when no permission events are in use - a few small cleanups * tag 'fsnotify_for_v6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: fix UAF from FS_ERROR event on a shutting down filesystem fsnotify: optimize the case of no permission event watchers fsnotify: use an enum for group priority constants fsnotify: move s_fsnotify_connectors into fsnotify_sb_info fsnotify: lazy attach fsnotify_sb_info state to sb fsnotify: create helper fsnotify_update_sb_watchers() fsnotify: pass object pointer and type to fsnotify mark helpers fanotify: merge two checks regarding add of ignore mark fsnotify: create a wrapper fsnotify_find_inode_mark() fsnotify: create helpers to get sb and connp from object fsnotify: rename fsnotify_{get,put}_sb_connectors() fsnotify: Avoid -Wflex-array-member-not-at-end warning fanotify: remove unneeded sub-zero check for unsigned value
2 parents daa1211 + 795bb82 commit 5af9d1c

File tree

14 files changed

+334
-216
lines changed

14 files changed

+334
-216
lines changed

fs/nfsd/filecache.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ nfsd_file_mark_find_or_create(struct nfsd_file *nf, struct inode *inode)
159159

160160
do {
161161
fsnotify_group_lock(nfsd_file_fsnotify_group);
162-
mark = fsnotify_find_mark(&inode->i_fsnotify_marks,
163-
nfsd_file_fsnotify_group);
162+
mark = fsnotify_find_inode_mark(inode,
163+
nfsd_file_fsnotify_group);
164164
if (mark) {
165165
nfm = nfsd_file_mark_get(container_of(mark,
166166
struct nfsd_file_mark,

fs/notify/dnotify/dnotify.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ void dnotify_flush(struct file *filp, fl_owner_t id)
162162
if (!S_ISDIR(inode->i_mode))
163163
return;
164164

165-
fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group);
165+
fsn_mark = fsnotify_find_inode_mark(inode, dnotify_group);
166166
if (!fsn_mark)
167167
return;
168168
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
@@ -326,7 +326,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned int arg)
326326
fsnotify_group_lock(dnotify_group);
327327

328328
/* add the new_fsn_mark or find an old one. */
329-
fsn_mark = fsnotify_find_mark(&inode->i_fsnotify_marks, dnotify_group);
329+
fsn_mark = fsnotify_find_inode_mark(inode, dnotify_group);
330330
if (fsn_mark) {
331331
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
332332
spin_lock(&fsn_mark->lock);

fs/notify/fanotify/fanotify_user.c

Lines changed: 43 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -502,7 +502,7 @@ static int copy_fid_info_to_user(__kernel_fsid_t *fsid, struct fanotify_fh *fh,
502502
}
503503

504504
/* Pad with 0's */
505-
WARN_ON_ONCE(len < 0 || len >= FANOTIFY_EVENT_ALIGN);
505+
WARN_ON_ONCE(len >= FANOTIFY_EVENT_ALIGN);
506506
if (len > 0 && clear_user(buf, len))
507507
return -EFAULT;
508508

@@ -1076,15 +1076,15 @@ static __u32 fanotify_mark_remove_from_mask(struct fsnotify_mark *fsn_mark,
10761076
}
10771077

10781078
static int fanotify_remove_mark(struct fsnotify_group *group,
1079-
fsnotify_connp_t *connp, __u32 mask,
1079+
void *obj, unsigned int obj_type, __u32 mask,
10801080
unsigned int flags, __u32 umask)
10811081
{
10821082
struct fsnotify_mark *fsn_mark = NULL;
10831083
__u32 removed;
10841084
int destroy_mark;
10851085

10861086
fsnotify_group_lock(group);
1087-
fsn_mark = fsnotify_find_mark(connp, group);
1087+
fsn_mark = fsnotify_find_mark(obj, obj_type, group);
10881088
if (!fsn_mark) {
10891089
fsnotify_group_unlock(group);
10901090
return -ENOENT;
@@ -1105,30 +1105,6 @@ static int fanotify_remove_mark(struct fsnotify_group *group,
11051105
return 0;
11061106
}
11071107

1108-
static int fanotify_remove_vfsmount_mark(struct fsnotify_group *group,
1109-
struct vfsmount *mnt, __u32 mask,
1110-
unsigned int flags, __u32 umask)
1111-
{
1112-
return fanotify_remove_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
1113-
mask, flags, umask);
1114-
}
1115-
1116-
static int fanotify_remove_sb_mark(struct fsnotify_group *group,
1117-
struct super_block *sb, __u32 mask,
1118-
unsigned int flags, __u32 umask)
1119-
{
1120-
return fanotify_remove_mark(group, &sb->s_fsnotify_marks, mask,
1121-
flags, umask);
1122-
}
1123-
1124-
static int fanotify_remove_inode_mark(struct fsnotify_group *group,
1125-
struct inode *inode, __u32 mask,
1126-
unsigned int flags, __u32 umask)
1127-
{
1128-
return fanotify_remove_mark(group, &inode->i_fsnotify_marks, mask,
1129-
flags, umask);
1130-
}
1131-
11321108
static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,
11331109
unsigned int fan_flags)
11341110
{
@@ -1249,7 +1225,7 @@ static int fanotify_set_mark_fsid(struct fsnotify_group *group,
12491225
}
12501226

12511227
static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
1252-
fsnotify_connp_t *connp,
1228+
void *obj,
12531229
unsigned int obj_type,
12541230
unsigned int fan_flags,
12551231
struct fan_fsid *fsid)
@@ -1288,7 +1264,7 @@ static struct fsnotify_mark *fanotify_add_new_mark(struct fsnotify_group *group,
12881264
fan_mark->fsid.val[0] = fan_mark->fsid.val[1] = 0;
12891265
}
12901266

1291-
ret = fsnotify_add_mark_locked(mark, connp, obj_type, 0);
1267+
ret = fsnotify_add_mark_locked(mark, obj, obj_type, 0);
12921268
if (ret)
12931269
goto out_put_mark;
12941270

@@ -1344,7 +1320,7 @@ static int fanotify_may_update_existing_mark(struct fsnotify_mark *fsn_mark,
13441320
}
13451321

13461322
static int fanotify_add_mark(struct fsnotify_group *group,
1347-
fsnotify_connp_t *connp, unsigned int obj_type,
1323+
void *obj, unsigned int obj_type,
13481324
__u32 mask, unsigned int fan_flags,
13491325
struct fan_fsid *fsid)
13501326
{
@@ -1353,9 +1329,9 @@ static int fanotify_add_mark(struct fsnotify_group *group,
13531329
int ret = 0;
13541330

13551331
fsnotify_group_lock(group);
1356-
fsn_mark = fsnotify_find_mark(connp, group);
1332+
fsn_mark = fsnotify_find_mark(obj, obj_type, group);
13571333
if (!fsn_mark) {
1358-
fsn_mark = fanotify_add_new_mark(group, connp, obj_type,
1334+
fsn_mark = fanotify_add_new_mark(group, obj, obj_type,
13591335
fan_flags, fsid);
13601336
if (IS_ERR(fsn_mark)) {
13611337
fsnotify_group_unlock(group);
@@ -1392,42 +1368,6 @@ static int fanotify_add_mark(struct fsnotify_group *group,
13921368
return ret;
13931369
}
13941370

1395-
static int fanotify_add_vfsmount_mark(struct fsnotify_group *group,
1396-
struct vfsmount *mnt, __u32 mask,
1397-
unsigned int flags, struct fan_fsid *fsid)
1398-
{
1399-
return fanotify_add_mark(group, &real_mount(mnt)->mnt_fsnotify_marks,
1400-
FSNOTIFY_OBJ_TYPE_VFSMOUNT, mask, flags, fsid);
1401-
}
1402-
1403-
static int fanotify_add_sb_mark(struct fsnotify_group *group,
1404-
struct super_block *sb, __u32 mask,
1405-
unsigned int flags, struct fan_fsid *fsid)
1406-
{
1407-
return fanotify_add_mark(group, &sb->s_fsnotify_marks,
1408-
FSNOTIFY_OBJ_TYPE_SB, mask, flags, fsid);
1409-
}
1410-
1411-
static int fanotify_add_inode_mark(struct fsnotify_group *group,
1412-
struct inode *inode, __u32 mask,
1413-
unsigned int flags, struct fan_fsid *fsid)
1414-
{
1415-
pr_debug("%s: group=%p inode=%p\n", __func__, group, inode);
1416-
1417-
/*
1418-
* If some other task has this inode open for write we should not add
1419-
* an ignore mask, unless that ignore mask is supposed to survive
1420-
* modification changes anyway.
1421-
*/
1422-
if ((flags & FANOTIFY_MARK_IGNORE_BITS) &&
1423-
!(flags & FAN_MARK_IGNORED_SURV_MODIFY) &&
1424-
inode_is_open_for_write(inode))
1425-
return 0;
1426-
1427-
return fanotify_add_mark(group, &inode->i_fsnotify_marks,
1428-
FSNOTIFY_OBJ_TYPE_INODE, mask, flags, fsid);
1429-
}
1430-
14311371
static struct fsnotify_event *fanotify_alloc_overflow_event(void)
14321372
{
14331373
struct fanotify_event *oevent;
@@ -1576,13 +1516,13 @@ SYSCALL_DEFINE2(fanotify_init, unsigned int, flags, unsigned int, event_f_flags)
15761516
INIT_LIST_HEAD(&group->fanotify_data.access_list);
15771517
switch (class) {
15781518
case FAN_CLASS_NOTIF:
1579-
group->priority = FS_PRIO_0;
1519+
group->priority = FSNOTIFY_PRIO_NORMAL;
15801520
break;
15811521
case FAN_CLASS_CONTENT:
1582-
group->priority = FS_PRIO_1;
1522+
group->priority = FSNOTIFY_PRIO_CONTENT;
15831523
break;
15841524
case FAN_CLASS_PRE_CONTENT:
1585-
group->priority = FS_PRIO_2;
1525+
group->priority = FSNOTIFY_PRIO_PRE_CONTENT;
15861526
break;
15871527
default:
15881528
fd = -EINVAL;
@@ -1750,6 +1690,7 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
17501690
unsigned int mark_cmd = flags & FANOTIFY_MARK_CMD_BITS;
17511691
unsigned int ignore = flags & FANOTIFY_MARK_IGNORE_BITS;
17521692
unsigned int obj_type, fid_mode;
1693+
void *obj;
17531694
u32 umask = 0;
17541695
int ret;
17551696

@@ -1833,12 +1774,11 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
18331774
goto fput_and_out;
18341775

18351776
/*
1836-
* group->priority == FS_PRIO_0 == FAN_CLASS_NOTIF. These are not
1837-
* allowed to set permissions events.
1777+
* Permission events require minimum priority FAN_CLASS_CONTENT.
18381778
*/
18391779
ret = -EINVAL;
18401780
if (mask & FANOTIFY_PERM_EVENTS &&
1841-
group->priority == FS_PRIO_0)
1781+
group->priority < FSNOTIFY_PRIO_CONTENT)
18421782
goto fput_and_out;
18431783

18441784
if (mask & FAN_FS_ERROR &&
@@ -1908,17 +1848,34 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
19081848
}
19091849

19101850
/* inode held in place by reference to path; group by fget on fd */
1911-
if (mark_type == FAN_MARK_INODE)
1851+
if (mark_type == FAN_MARK_INODE) {
19121852
inode = path.dentry->d_inode;
1913-
else
1853+
obj = inode;
1854+
} else {
19141855
mnt = path.mnt;
1856+
if (mark_type == FAN_MARK_MOUNT)
1857+
obj = mnt;
1858+
else
1859+
obj = mnt->mnt_sb;
1860+
}
19151861

1916-
ret = mnt ? -EINVAL : -EISDIR;
1917-
/* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
1918-
if (mark_cmd == FAN_MARK_ADD && ignore == FAN_MARK_IGNORE &&
1919-
(mnt || S_ISDIR(inode->i_mode)) &&
1920-
!(flags & FAN_MARK_IGNORED_SURV_MODIFY))
1921-
goto path_put_and_out;
1862+
/*
1863+
* If some other task has this inode open for write we should not add
1864+
* an ignore mask, unless that ignore mask is supposed to survive
1865+
* modification changes anyway.
1866+
*/
1867+
if (mark_cmd == FAN_MARK_ADD && (flags & FANOTIFY_MARK_IGNORE_BITS) &&
1868+
!(flags & FAN_MARK_IGNORED_SURV_MODIFY)) {
1869+
ret = mnt ? -EINVAL : -EISDIR;
1870+
/* FAN_MARK_IGNORE requires SURV_MODIFY for sb/mount/dir marks */
1871+
if (ignore == FAN_MARK_IGNORE &&
1872+
(mnt || S_ISDIR(inode->i_mode)))
1873+
goto path_put_and_out;
1874+
1875+
ret = 0;
1876+
if (inode && inode_is_open_for_write(inode))
1877+
goto path_put_and_out;
1878+
}
19221879

19231880
/* Mask out FAN_EVENT_ON_CHILD flag for sb/mount/non-dir marks */
19241881
if (mnt || !S_ISDIR(inode->i_mode)) {
@@ -1936,26 +1893,12 @@ static int do_fanotify_mark(int fanotify_fd, unsigned int flags, __u64 mask,
19361893
/* create/update an inode mark */
19371894
switch (mark_cmd) {
19381895
case FAN_MARK_ADD:
1939-
if (mark_type == FAN_MARK_MOUNT)
1940-
ret = fanotify_add_vfsmount_mark(group, mnt, mask,
1941-
flags, fsid);
1942-
else if (mark_type == FAN_MARK_FILESYSTEM)
1943-
ret = fanotify_add_sb_mark(group, mnt->mnt_sb, mask,
1944-
flags, fsid);
1945-
else
1946-
ret = fanotify_add_inode_mark(group, inode, mask,
1947-
flags, fsid);
1896+
ret = fanotify_add_mark(group, obj, obj_type, mask, flags,
1897+
fsid);
19481898
break;
19491899
case FAN_MARK_REMOVE:
1950-
if (mark_type == FAN_MARK_MOUNT)
1951-
ret = fanotify_remove_vfsmount_mark(group, mnt, mask,
1952-
flags, umask);
1953-
else if (mark_type == FAN_MARK_FILESYSTEM)
1954-
ret = fanotify_remove_sb_mark(group, mnt->mnt_sb, mask,
1955-
flags, umask);
1956-
else
1957-
ret = fanotify_remove_inode_mark(group, inode, mask,
1958-
flags, umask);
1900+
ret = fanotify_remove_mark(group, obj, obj_type, mask, flags,
1901+
umask);
19591902
break;
19601903
default:
19611904
ret = -EINVAL;

fs/notify/fdinfo.c

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -41,29 +41,25 @@ static void show_fdinfo(struct seq_file *m, struct file *f,
4141
#if defined(CONFIG_EXPORTFS)
4242
static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
4343
{
44-
struct {
45-
struct file_handle handle;
46-
u8 pad[MAX_HANDLE_SZ];
47-
} f;
44+
DEFINE_FLEX(struct file_handle, f, f_handle, handle_bytes, MAX_HANDLE_SZ);
4845
int size, ret, i;
4946

50-
f.handle.handle_bytes = sizeof(f.pad);
51-
size = f.handle.handle_bytes >> 2;
47+
size = f->handle_bytes >> 2;
5248

53-
ret = exportfs_encode_fid(inode, (struct fid *)f.handle.f_handle, &size);
49+
ret = exportfs_encode_fid(inode, (struct fid *)f->f_handle, &size);
5450
if ((ret == FILEID_INVALID) || (ret < 0)) {
5551
WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret);
5652
return;
5753
}
5854

59-
f.handle.handle_type = ret;
60-
f.handle.handle_bytes = size * sizeof(u32);
55+
f->handle_type = ret;
56+
f->handle_bytes = size * sizeof(u32);
6157

6258
seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:",
63-
f.handle.handle_bytes, f.handle.handle_type);
59+
f->handle_bytes, f->handle_type);
6460

65-
for (i = 0; i < f.handle.handle_bytes; i++)
66-
seq_printf(m, "%02x", (int)f.handle.f_handle[i]);
61+
for (i = 0; i < f->handle_bytes; i++)
62+
seq_printf(m, "%02x", (int)f->f_handle[i]);
6763
}
6864
#else
6965
static void show_mark_fhandle(struct seq_file *m, struct inode *inode)

fs/notify/fsnotify.c

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,11 +89,25 @@ static void fsnotify_unmount_inodes(struct super_block *sb)
8989

9090
void fsnotify_sb_delete(struct super_block *sb)
9191
{
92+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
93+
94+
/* Were any marks ever added to any object on this sb? */
95+
if (!sbinfo)
96+
return;
97+
9298
fsnotify_unmount_inodes(sb);
9399
fsnotify_clear_marks_by_sb(sb);
94100
/* Wait for outstanding object references from connectors */
95-
wait_var_event(&sb->s_fsnotify_connectors,
96-
!atomic_long_read(&sb->s_fsnotify_connectors));
101+
wait_var_event(fsnotify_sb_watched_objects(sb),
102+
!atomic_long_read(fsnotify_sb_watched_objects(sb)));
103+
WARN_ON(fsnotify_sb_has_priority_watchers(sb, FSNOTIFY_PRIO_CONTENT));
104+
WARN_ON(fsnotify_sb_has_priority_watchers(sb,
105+
FSNOTIFY_PRIO_PRE_CONTENT));
106+
}
107+
108+
void fsnotify_sb_free(struct super_block *sb)
109+
{
110+
kfree(sb->s_fsnotify_info);
97111
}
98112

99113
/*
@@ -489,6 +503,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
489503
{
490504
const struct path *path = fsnotify_data_path(data, data_type);
491505
struct super_block *sb = fsnotify_data_sb(data, data_type);
506+
struct fsnotify_sb_info *sbinfo = fsnotify_sb_info(sb);
492507
struct fsnotify_iter_info iter_info = {};
493508
struct mount *mnt = NULL;
494509
struct inode *inode2 = NULL;
@@ -525,7 +540,7 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
525540
* SRCU because we have no references to any objects and do not
526541
* need SRCU to keep them "alive".
527542
*/
528-
if (!sb->s_fsnotify_marks &&
543+
if ((!sbinfo || !sbinfo->sb_marks) &&
529544
(!mnt || !mnt->mnt_fsnotify_marks) &&
530545
(!inode || !inode->i_fsnotify_marks) &&
531546
(!inode2 || !inode2->i_fsnotify_marks))
@@ -552,8 +567,10 @@ int fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir,
552567

553568
iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu);
554569

555-
iter_info.marks[FSNOTIFY_ITER_TYPE_SB] =
556-
fsnotify_first_mark(&sb->s_fsnotify_marks);
570+
if (sbinfo) {
571+
iter_info.marks[FSNOTIFY_ITER_TYPE_SB] =
572+
fsnotify_first_mark(&sbinfo->sb_marks);
573+
}
557574
if (mnt) {
558575
iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] =
559576
fsnotify_first_mark(&mnt->mnt_fsnotify_marks);

0 commit comments

Comments
 (0)