Skip to content

Commit dbb2816

Browse files
committed
Merge tag 'fsnotify_for_v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs
Pull fsnotify updates from Jan Kara: "fsnotify cleanups unifying handling of different watch types. This is the shortened fsnotify series from Amir with the last five patches pulled out. Amir has modified those patches to not change struct inode but obviously it's too late for those to go into this merge window" * tag 'fsnotify_for_v4.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/jack/linux-fs: fsnotify: add fsnotify_add_inode_mark() wrappers fanotify: generalize fanotify_should_send_event() fsnotify: generalize send_to_group() fsnotify: generalize iteration of marks by object type fsnotify: introduce marks iteration helpers fsnotify: remove redundant arguments to handle_event() fsnotify: use type id to identify connector object type
2 parents 644f263 + b249f5b commit dbb2816

File tree

14 files changed

+230
-147
lines changed

14 files changed

+230
-147
lines changed

fs/notify/dnotify/dnotify.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,11 @@ static void dnotify_recalc_inode_mask(struct fsnotify_mark *fsn_mark)
7979
*/
8080
static int dnotify_handle_event(struct fsnotify_group *group,
8181
struct inode *inode,
82-
struct fsnotify_mark *inode_mark,
83-
struct fsnotify_mark *vfsmount_mark,
8482
u32 mask, const void *data, int data_type,
8583
const unsigned char *file_name, u32 cookie,
8684
struct fsnotify_iter_info *iter_info)
8785
{
86+
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
8887
struct dnotify_mark *dn_mark;
8988
struct dnotify_struct *dn;
9089
struct dnotify_struct **prev;
@@ -95,7 +94,8 @@ static int dnotify_handle_event(struct fsnotify_group *group,
9594
if (!S_ISDIR(inode->i_mode))
9695
return 0;
9796

98-
BUG_ON(vfsmount_mark);
97+
if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info)))
98+
return 0;
9999

100100
dn_mark = container_of(inode_mark, struct dnotify_mark, fsn_mark);
101101

@@ -319,7 +319,7 @@ int fcntl_dirnotify(int fd, struct file *filp, unsigned long arg)
319319
dn_mark = container_of(fsn_mark, struct dnotify_mark, fsn_mark);
320320
spin_lock(&fsn_mark->lock);
321321
} else {
322-
error = fsnotify_add_mark_locked(new_fsn_mark, inode, NULL, 0);
322+
error = fsnotify_add_inode_mark_locked(new_fsn_mark, inode, 0);
323323
if (error) {
324324
mutex_unlock(&dnotify_group->mark_mutex);
325325
goto out_err;

fs/notify/fanotify/fanotify.c

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -87,17 +87,17 @@ static int fanotify_get_response(struct fsnotify_group *group,
8787
return ret;
8888
}
8989

90-
static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
91-
struct fsnotify_mark *vfsmnt_mark,
92-
u32 event_mask,
93-
const void *data, int data_type)
90+
static bool fanotify_should_send_event(struct fsnotify_iter_info *iter_info,
91+
u32 event_mask, const void *data,
92+
int data_type)
9493
{
9594
__u32 marks_mask = 0, marks_ignored_mask = 0;
9695
const struct path *path = data;
96+
struct fsnotify_mark *mark;
97+
int type;
9798

98-
pr_debug("%s: inode_mark=%p vfsmnt_mark=%p mask=%x data=%p"
99-
" data_type=%d\n", __func__, inode_mark, vfsmnt_mark,
100-
event_mask, data, data_type);
99+
pr_debug("%s: report_mask=%x mask=%x data=%p data_type=%d\n",
100+
__func__, iter_info->report_mask, event_mask, data, data_type);
101101

102102
/* if we don't have enough info to send an event to userspace say no */
103103
if (data_type != FSNOTIFY_EVENT_PATH)
@@ -108,20 +108,21 @@ static bool fanotify_should_send_event(struct fsnotify_mark *inode_mark,
108108
!d_can_lookup(path->dentry))
109109
return false;
110110

111-
/*
112-
* if the event is for a child and this inode doesn't care about
113-
* events on the child, don't send it!
114-
*/
115-
if (inode_mark &&
116-
(!(event_mask & FS_EVENT_ON_CHILD) ||
117-
(inode_mark->mask & FS_EVENT_ON_CHILD))) {
118-
marks_mask |= inode_mark->mask;
119-
marks_ignored_mask |= inode_mark->ignored_mask;
120-
}
111+
fsnotify_foreach_obj_type(type) {
112+
if (!fsnotify_iter_should_report_type(iter_info, type))
113+
continue;
114+
mark = iter_info->marks[type];
115+
/*
116+
* if the event is for a child and this inode doesn't care about
117+
* events on the child, don't send it!
118+
*/
119+
if (type == FSNOTIFY_OBJ_TYPE_INODE &&
120+
(event_mask & FS_EVENT_ON_CHILD) &&
121+
!(mark->mask & FS_EVENT_ON_CHILD))
122+
continue;
121123

122-
if (vfsmnt_mark) {
123-
marks_mask |= vfsmnt_mark->mask;
124-
marks_ignored_mask |= vfsmnt_mark->ignored_mask;
124+
marks_mask |= mark->mask;
125+
marks_ignored_mask |= mark->ignored_mask;
125126
}
126127

127128
if (d_is_dir(path->dentry) &&
@@ -178,8 +179,6 @@ init: __maybe_unused
178179

179180
static int fanotify_handle_event(struct fsnotify_group *group,
180181
struct inode *inode,
181-
struct fsnotify_mark *inode_mark,
182-
struct fsnotify_mark *fanotify_mark,
183182
u32 mask, const void *data, int data_type,
184183
const unsigned char *file_name, u32 cookie,
185184
struct fsnotify_iter_info *iter_info)
@@ -199,8 +198,7 @@ static int fanotify_handle_event(struct fsnotify_group *group,
199198
BUILD_BUG_ON(FAN_ACCESS_PERM != FS_ACCESS_PERM);
200199
BUILD_BUG_ON(FAN_ONDIR != FS_ISDIR);
201200

202-
if (!fanotify_should_send_event(inode_mark, fanotify_mark, mask, data,
203-
data_type))
201+
if (!fanotify_should_send_event(iter_info, mask, data, data_type))
204202
return 0;
205203

206204
pr_debug("%s: group=%p inode=%p mask=%x\n", __func__, group, inode,

fs/notify/fdinfo.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
7777
struct inotify_inode_mark *inode_mark;
7878
struct inode *inode;
7979

80-
if (!(mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE))
80+
if (mark->connector->type != FSNOTIFY_OBJ_TYPE_INODE)
8181
return;
8282

8383
inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
@@ -116,7 +116,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
116116
if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
117117
mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
118118

119-
if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_INODE) {
119+
if (mark->connector->type == FSNOTIFY_OBJ_TYPE_INODE) {
120120
inode = igrab(mark->connector->inode);
121121
if (!inode)
122122
return;
@@ -126,7 +126,7 @@ static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
126126
show_mark_fhandle(m, inode);
127127
seq_putc(m, '\n');
128128
iput(inode);
129-
} else if (mark->connector->flags & FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
129+
} else if (mark->connector->type == FSNOTIFY_OBJ_TYPE_VFSMOUNT) {
130130
struct mount *mnt = real_mount(mark->connector->mnt);
131131

132132
seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",

fs/notify/fsnotify.c

Lines changed: 83 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,6 @@ int __fsnotify_parent(const struct path *path, struct dentry *dentry, __u32 mask
184184
EXPORT_SYMBOL_GPL(__fsnotify_parent);
185185

186186
static int send_to_group(struct inode *to_tell,
187-
struct fsnotify_mark *inode_mark,
188-
struct fsnotify_mark *vfsmount_mark,
189187
__u32 mask, const void *data,
190188
int data_is, u32 cookie,
191189
const unsigned char *file_name,
@@ -195,48 +193,45 @@ static int send_to_group(struct inode *to_tell,
195193
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
196194
__u32 marks_mask = 0;
197195
__u32 marks_ignored_mask = 0;
196+
struct fsnotify_mark *mark;
197+
int type;
198198

199-
if (unlikely(!inode_mark && !vfsmount_mark)) {
200-
BUG();
199+
if (WARN_ON(!iter_info->report_mask))
201200
return 0;
202-
}
203201

204202
/* clear ignored on inode modification */
205203
if (mask & FS_MODIFY) {
206-
if (inode_mark &&
207-
!(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
208-
inode_mark->ignored_mask = 0;
209-
if (vfsmount_mark &&
210-
!(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
211-
vfsmount_mark->ignored_mask = 0;
212-
}
213-
214-
/* does the inode mark tell us to do something? */
215-
if (inode_mark) {
216-
group = inode_mark->group;
217-
marks_mask |= inode_mark->mask;
218-
marks_ignored_mask |= inode_mark->ignored_mask;
204+
fsnotify_foreach_obj_type(type) {
205+
if (!fsnotify_iter_should_report_type(iter_info, type))
206+
continue;
207+
mark = iter_info->marks[type];
208+
if (mark &&
209+
!(mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
210+
mark->ignored_mask = 0;
211+
}
219212
}
220213

221-
/* does the vfsmount_mark tell us to do something? */
222-
if (vfsmount_mark) {
223-
group = vfsmount_mark->group;
224-
marks_mask |= vfsmount_mark->mask;
225-
marks_ignored_mask |= vfsmount_mark->ignored_mask;
214+
fsnotify_foreach_obj_type(type) {
215+
if (!fsnotify_iter_should_report_type(iter_info, type))
216+
continue;
217+
mark = iter_info->marks[type];
218+
/* does the object mark tell us to do something? */
219+
if (mark) {
220+
group = mark->group;
221+
marks_mask |= mark->mask;
222+
marks_ignored_mask |= mark->ignored_mask;
223+
}
226224
}
227225

228-
pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p"
229-
" vfsmount_mark=%p marks_mask=%x marks_ignored_mask=%x"
226+
pr_debug("%s: group=%p to_tell=%p mask=%x marks_mask=%x marks_ignored_mask=%x"
230227
" data=%p data_is=%d cookie=%d\n",
231-
__func__, group, to_tell, mask, inode_mark, vfsmount_mark,
232-
marks_mask, marks_ignored_mask, data,
233-
data_is, cookie);
228+
__func__, group, to_tell, mask, marks_mask, marks_ignored_mask,
229+
data, data_is, cookie);
234230

235231
if (!(test_mask & marks_mask & ~marks_ignored_mask))
236232
return 0;
237233

238-
return group->ops->handle_event(group, to_tell, inode_mark,
239-
vfsmount_mark, mask, data, data_is,
234+
return group->ops->handle_event(group, to_tell, mask, data, data_is,
240235
file_name, cookie, iter_info);
241236
}
242237

@@ -263,6 +258,57 @@ static struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark)
263258
return hlist_entry_safe(node, struct fsnotify_mark, obj_list);
264259
}
265260

261+
/*
262+
* iter_info is a multi head priority queue of marks.
263+
* Pick a subset of marks from queue heads, all with the
264+
* same group and set the report_mask for selected subset.
265+
* Returns the report_mask of the selected subset.
266+
*/
267+
static unsigned int fsnotify_iter_select_report_types(
268+
struct fsnotify_iter_info *iter_info)
269+
{
270+
struct fsnotify_group *max_prio_group = NULL;
271+
struct fsnotify_mark *mark;
272+
int type;
273+
274+
/* Choose max prio group among groups of all queue heads */
275+
fsnotify_foreach_obj_type(type) {
276+
mark = iter_info->marks[type];
277+
if (mark &&
278+
fsnotify_compare_groups(max_prio_group, mark->group) > 0)
279+
max_prio_group = mark->group;
280+
}
281+
282+
if (!max_prio_group)
283+
return 0;
284+
285+
/* Set the report mask for marks from same group as max prio group */
286+
iter_info->report_mask = 0;
287+
fsnotify_foreach_obj_type(type) {
288+
mark = iter_info->marks[type];
289+
if (mark &&
290+
fsnotify_compare_groups(max_prio_group, mark->group) == 0)
291+
fsnotify_iter_set_report_type(iter_info, type);
292+
}
293+
294+
return iter_info->report_mask;
295+
}
296+
297+
/*
298+
* Pop from iter_info multi head queue, the marks that were iterated in the
299+
* current iteration step.
300+
*/
301+
static void fsnotify_iter_next(struct fsnotify_iter_info *iter_info)
302+
{
303+
int type;
304+
305+
fsnotify_foreach_obj_type(type) {
306+
if (fsnotify_iter_should_report_type(iter_info, type))
307+
iter_info->marks[type] =
308+
fsnotify_next_mark(iter_info->marks[type]);
309+
}
310+
}
311+
266312
/*
267313
* This is the main call to fsnotify. The VFS calls into hook specific functions
268314
* in linux/fsnotify.h. Those functions then in turn call here. Here will call
@@ -307,15 +353,15 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
307353

308354
if ((mask & FS_MODIFY) ||
309355
(test_mask & to_tell->i_fsnotify_mask)) {
310-
iter_info.inode_mark =
356+
iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
311357
fsnotify_first_mark(&to_tell->i_fsnotify_marks);
312358
}
313359

314360
if (mnt && ((mask & FS_MODIFY) ||
315361
(test_mask & mnt->mnt_fsnotify_mask))) {
316-
iter_info.inode_mark =
362+
iter_info.marks[FSNOTIFY_OBJ_TYPE_INODE] =
317363
fsnotify_first_mark(&to_tell->i_fsnotify_marks);
318-
iter_info.vfsmount_mark =
364+
iter_info.marks[FSNOTIFY_OBJ_TYPE_VFSMOUNT] =
319365
fsnotify_first_mark(&mnt->mnt_fsnotify_marks);
320366
}
321367

@@ -324,32 +370,14 @@ int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
324370
* ignore masks are properly reflected for mount mark notifications.
325371
* That's why this traversal is so complicated...
326372
*/
327-
while (iter_info.inode_mark || iter_info.vfsmount_mark) {
328-
struct fsnotify_mark *inode_mark = iter_info.inode_mark;
329-
struct fsnotify_mark *vfsmount_mark = iter_info.vfsmount_mark;
330-
331-
if (inode_mark && vfsmount_mark) {
332-
int cmp = fsnotify_compare_groups(inode_mark->group,
333-
vfsmount_mark->group);
334-
if (cmp > 0)
335-
inode_mark = NULL;
336-
else if (cmp < 0)
337-
vfsmount_mark = NULL;
338-
}
339-
340-
ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
341-
data, data_is, cookie, file_name,
342-
&iter_info);
373+
while (fsnotify_iter_select_report_types(&iter_info)) {
374+
ret = send_to_group(to_tell, mask, data, data_is, cookie,
375+
file_name, &iter_info);
343376

344377
if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
345378
goto out;
346379

347-
if (inode_mark)
348-
iter_info.inode_mark =
349-
fsnotify_next_mark(iter_info.inode_mark);
350-
if (vfsmount_mark)
351-
iter_info.vfsmount_mark =
352-
fsnotify_next_mark(iter_info.vfsmount_mark);
380+
fsnotify_iter_next(&iter_info);
353381
}
354382
ret = 0;
355383
out:

fs/notify/fsnotify.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,6 @@
99

1010
#include "../mount.h"
1111

12-
struct fsnotify_iter_info {
13-
struct fsnotify_mark *inode_mark;
14-
struct fsnotify_mark *vfsmount_mark;
15-
int srcu_idx;
16-
};
17-
1812
/* destroy all events sitting in this groups notification queue */
1913
extern void fsnotify_flush_notify(struct fsnotify_group *group);
2014

fs/notify/group.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ void fsnotify_destroy_group(struct fsnotify_group *group)
6767
fsnotify_group_stop_queueing(group);
6868

6969
/* Clear all marks for this group and queue them for destruction */
70-
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES);
70+
fsnotify_clear_marks_by_group(group, FSNOTIFY_OBJ_ALL_TYPES_MASK);
7171

7272
/*
7373
* Some marks can still be pinned when waiting for response from

fs/notify/inotify/inotify.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ extern void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
2525
struct fsnotify_group *group);
2626
extern int inotify_handle_event(struct fsnotify_group *group,
2727
struct inode *inode,
28-
struct fsnotify_mark *inode_mark,
29-
struct fsnotify_mark *vfsmount_mark,
3028
u32 mask, const void *data, int data_type,
3129
const unsigned char *file_name, u32 cookie,
3230
struct fsnotify_iter_info *iter_info);

fs/notify/inotify/inotify_fsnotify.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,20 +65,20 @@ static int inotify_merge(struct list_head *list,
6565

6666
int inotify_handle_event(struct fsnotify_group *group,
6767
struct inode *inode,
68-
struct fsnotify_mark *inode_mark,
69-
struct fsnotify_mark *vfsmount_mark,
7068
u32 mask, const void *data, int data_type,
7169
const unsigned char *file_name, u32 cookie,
7270
struct fsnotify_iter_info *iter_info)
7371
{
72+
struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info);
7473
struct inotify_inode_mark *i_mark;
7574
struct inotify_event_info *event;
7675
struct fsnotify_event *fsn_event;
7776
int ret;
7877
int len = 0;
7978
int alloc_len = sizeof(struct inotify_event_info);
8079

81-
BUG_ON(vfsmount_mark);
80+
if (WARN_ON(fsnotify_iter_vfsmount_mark(iter_info)))
81+
return 0;
8282

8383
if ((inode_mark->mask & FS_EXCL_UNLINK) &&
8484
(data_type == FSNOTIFY_EVENT_PATH)) {

0 commit comments

Comments
 (0)