1 #include <linux/fdtable.h>
2 #include <linux/fsnotify_backend.h>
3 #include <linux/init.h>
4 #include <linux/kernel.h> /* UINT_MAX */
5 #include <linux/types.h>
9 static bool should_merge(struct fsnotify_event
*old
, struct fsnotify_event
*new)
11 pr_debug("%s: old=%p new=%p\n", __func__
, old
, new);
13 if ((old
->to_tell
== new->to_tell
) &&
14 (old
->data_type
== new->data_type
)) {
15 switch (old
->data_type
) {
16 case (FSNOTIFY_EVENT_PATH
):
17 if ((old
->path
.mnt
== new->path
.mnt
) &&
18 (old
->path
.dentry
== new->path
.dentry
))
20 case (FSNOTIFY_EVENT_NONE
):
29 static int fanotify_merge(struct list_head
*list
, struct fsnotify_event
*event
)
31 struct fsnotify_event_holder
*test_holder
;
32 struct fsnotify_event
*test_event
;
33 struct fsnotify_event
*new_event
;
36 pr_debug("%s: list=%p event=%p\n", __func__
, list
, event
);
38 /* and the list better be locked by something too! */
40 list_for_each_entry_reverse(test_holder
, list
, event_list
) {
41 test_event
= test_holder
->event
;
42 if (should_merge(test_event
, event
)) {
45 /* if they are exactly the same we are done */
46 if (test_event
->mask
== event
->mask
)
50 * if the refcnt == 1 this is the only queue
51 * for this event and so we can update the mask
54 if (atomic_read(&test_event
->refcnt
) == 1) {
55 test_event
->mask
|= event
->mask
;
59 /* can't allocate memory, merge was no possible */
60 new_event
= fsnotify_clone_event(test_event
);
61 if (unlikely(!new_event
)) {
66 /* build new event and replace it on the list */
67 new_event
->mask
= (test_event
->mask
| event
->mask
);
68 fsnotify_replace_event(test_holder
, new_event
);
69 /* match ref from fsnotify_clone_event() */
70 fsnotify_put_event(new_event
);
79 static int fanotify_handle_event(struct fsnotify_group
*group
, struct fsnotify_event
*event
)
84 BUILD_BUG_ON(FAN_ACCESS
!= FS_ACCESS
);
85 BUILD_BUG_ON(FAN_MODIFY
!= FS_MODIFY
);
86 BUILD_BUG_ON(FAN_CLOSE_NOWRITE
!= FS_CLOSE_NOWRITE
);
87 BUILD_BUG_ON(FAN_CLOSE_WRITE
!= FS_CLOSE_WRITE
);
88 BUILD_BUG_ON(FAN_OPEN
!= FS_OPEN
);
89 BUILD_BUG_ON(FAN_EVENT_ON_CHILD
!= FS_EVENT_ON_CHILD
);
90 BUILD_BUG_ON(FAN_Q_OVERFLOW
!= FS_Q_OVERFLOW
);
92 pr_debug("%s: group=%p event=%p\n", __func__
, group
, event
);
94 ret
= fsnotify_add_notify_event(group
, event
, NULL
, fanotify_merge
);
95 /* -EEXIST means this event was merged with another, not that it was an error */
101 static bool fanotify_should_send_event(struct fsnotify_group
*group
, struct inode
*inode
,
102 struct vfsmount
*mnt
, __u32 mask
, void *data
,
105 struct fsnotify_mark
*fsn_mark
;
108 pr_debug("%s: group=%p inode=%p mask=%x data=%p data_type=%d\n",
109 __func__
, group
, inode
, mask
, data
, data_type
);
111 /* sorry, fanotify only gives a damn about files and dirs */
112 if (!S_ISREG(inode
->i_mode
) &&
113 !S_ISDIR(inode
->i_mode
))
116 /* if we don't have enough info to send an event to userspace say no */
117 if (data_type
!= FSNOTIFY_EVENT_PATH
)
120 fsn_mark
= fsnotify_find_mark(group
, inode
);
124 /* if the event is for a child and this inode doesn't care about
125 * events on the child, don't send it! */
126 if ((mask
& FS_EVENT_ON_CHILD
) &&
127 !(fsn_mark
->mask
& FS_EVENT_ON_CHILD
)) {
131 * We care about children, but do we care about this particular
134 mask
= (mask
& ~FS_EVENT_ON_CHILD
);
135 send
= (fsn_mark
->mask
& mask
);
138 /* find took a reference */
139 fsnotify_put_mark(fsn_mark
);
144 const struct fsnotify_ops fanotify_fsnotify_ops
= {
145 .handle_event
= fanotify_handle_event
,
146 .should_send_event
= fanotify_should_send_event
,
147 .free_group_priv
= NULL
,
148 .free_event_priv
= NULL
,
149 .freeing_mark
= NULL
,