1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
|
/*
* Filesystem access notification for Linux
*
* Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
*/
#ifndef __LINUX_FSNOTIFY_BACKEND_H
#define __LINUX_FSNOTIFY_BACKEND_H
#ifdef __KERNEL__
#include <linux/idr.h>
#include <linux/fs.h>
#include <linux/list.h>
#include <linux/path.h>
#include <linux/spinlock.h>
#include <linux/types.h>
#include <linux/atomic.h>
#define FS_ACCESS 0x00000001
#define FS_MODIFY 0x00000002
#define FS_ATTRIB 0x00000004
#define FS_CLOSE_WRITE 0x00000008
#define FS_CLOSE_NOWRITE 0x00000010
#define FS_OPEN 0x00000020
#define FS_MOVED_FROM 0x00000040
#define FS_MOVED_TO 0x00000080
#define FS_CREATE 0x00000100
#define FS_DELETE 0x00000200
#define FS_DELETE_SELF 0x00000400
#define FS_MOVE_SELF 0x00000800
#define FS_UNMOUNT 0x00002000
#define FS_Q_OVERFLOW 0x00004000
#define FS_IN_IGNORED 0x00008000
#define FS_OPEN_PERM 0x00010000
#define FS_ACCESS_PERM 0x00020000
#define FS_EXCL_UNLINK 0x04000000
#define FS_ISDIR 0x40000000
#define FS_IN_ONESHOT 0x80000000
#define FS_DN_RENAME 0x10000000
#define FS_DN_MULTISHOT 0x20000000
#define FS_EVENT_ON_CHILD 0x08000000
#define FS_EVENTS_POSS_ON_CHILD (FS_ACCESS | FS_MODIFY | FS_ATTRIB |\
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN |\
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE |\
FS_DELETE)
#define FS_MOVE (FS_MOVED_FROM | FS_MOVED_TO)
#define ALL_FSNOTIFY_PERM_EVENTS (FS_OPEN_PERM | FS_ACCESS_PERM)
#define ALL_FSNOTIFY_EVENTS (FS_ACCESS | FS_MODIFY | FS_ATTRIB | \
FS_CLOSE_WRITE | FS_CLOSE_NOWRITE | FS_OPEN | \
FS_MOVED_FROM | FS_MOVED_TO | FS_CREATE | \
FS_DELETE | FS_DELETE_SELF | FS_MOVE_SELF | \
FS_UNMOUNT | FS_Q_OVERFLOW | FS_IN_IGNORED | \
FS_OPEN_PERM | FS_ACCESS_PERM | FS_EXCL_UNLINK | \
FS_ISDIR | FS_IN_ONESHOT | FS_DN_RENAME | \
FS_DN_MULTISHOT | FS_EVENT_ON_CHILD)
struct fsnotify_group;
struct fsnotify_event;
struct fsnotify_mark;
struct fsnotify_event_private_data;
struct fsnotify_ops {
bool (*should_send_event)(struct fsnotify_group *group, struct inode *inode,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
__u32 mask, void *data, int data_type);
int (*handle_event)(struct fsnotify_group *group,
struct fsnotify_mark *inode_mark,
struct fsnotify_mark *vfsmount_mark,
struct fsnotify_event *event);
void (*free_group_priv)(struct fsnotify_group *group);
void (*freeing_mark)(struct fsnotify_mark *mark, struct fsnotify_group *group);
void (*free_event_priv)(struct fsnotify_event_private_data *priv);
};
struct fsnotify_group {
atomic_t refcnt;
const struct fsnotify_ops *ops;
struct mutex notification_mutex;
struct list_head notification_list;
wait_queue_head_t notification_waitq;
unsigned int q_len;
unsigned int max_events;
#define FS_PRIO_0 0
#define FS_PRIO_1 1
#define FS_PRIO_2 2
unsigned int priority;
spinlock_t mark_lock;
atomic_t num_marks;
struct list_head marks_list;
union {
void *private;
#ifdef CONFIG_INOTIFY_USER
struct inotify_group_private_data {
spinlock_t idr_lock;
struct idr idr;
u32 last_wd;
struct fasync_struct *fa;
struct user_struct *user;
} inotify_data;
#endif
#ifdef CONFIG_FANOTIFY
struct fanotify_group_private_data {
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
struct mutex access_mutex;
struct list_head access_list;
wait_queue_head_t access_waitq;
atomic_t bypass_perm;
#endif
int f_flags;
unsigned int max_marks;
struct user_struct *user;
} fanotify_data;
#endif
};
};
struct fsnotify_event_holder {
struct fsnotify_event *event;
struct list_head event_list;
};
struct fsnotify_event_private_data {
struct fsnotify_group *group;
struct list_head event_list;
};
struct fsnotify_event {
struct fsnotify_event_holder holder;
spinlock_t lock;
struct inode *to_tell;
union {
struct path path;
struct inode *inode;
};
#define FSNOTIFY_EVENT_NONE 0
#define FSNOTIFY_EVENT_PATH 1
#define FSNOTIFY_EVENT_INODE 2
int data_type;
atomic_t refcnt;
__u32 mask;
u32 sync_cookie;
const unsigned char *file_name;
size_t name_len;
struct pid *tgid;
#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
__u32 response;
#endif
struct list_head private_data_list;
};
struct fsnotify_inode_mark {
struct inode *inode;
struct hlist_node i_list;
struct list_head free_i_list;
};
struct fsnotify_vfsmount_mark {
struct vfsmount *mnt;
struct hlist_node m_list;
struct list_head free_m_list;
};
struct fsnotify_mark {
__u32 mask;
atomic_t refcnt;
struct fsnotify_group *group;
struct list_head g_list;
spinlock_t lock;
union {
struct fsnotify_inode_mark i;
struct fsnotify_vfsmount_mark m;
};
struct list_head free_g_list;
__u32 ignored_mask;
#define FSNOTIFY_MARK_FLAG_INODE 0x01
#define FSNOTIFY_MARK_FLAG_VFSMOUNT 0x02
#define FSNOTIFY_MARK_FLAG_OBJECT_PINNED 0x04
#define FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY 0x08
#define FSNOTIFY_MARK_FLAG_ALIVE 0x10
unsigned int flags;
struct list_head destroy_list;
void (*free_mark)(struct fsnotify_mark *mark);
};
#ifdef CONFIG_FSNOTIFY
extern int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const unsigned char *name, u32 cookie);
extern int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
extern void __fsnotify_vfsmount_delete(struct vfsmount *mnt);
extern u32 fsnotify_get_cookie(void);
static inline int fsnotify_inode_watches_children(struct inode *inode)
{
if (!(inode->i_fsnotify_mask & FS_EVENT_ON_CHILD))
return 0;
return inode->i_fsnotify_mask & FS_EVENTS_POSS_ON_CHILD;
}
static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
{
struct dentry *parent;
assert_spin_locked(&dentry->d_lock);
parent = dentry->d_parent;
if (parent->d_inode && fsnotify_inode_watches_children(parent->d_inode))
dentry->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
else
dentry->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
}
static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode)
{
if (!inode)
return;
spin_lock(&dentry->d_lock);
__fsnotify_update_dcache_flags(dentry);
spin_unlock(&dentry->d_lock);
}
extern struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops);
extern void fsnotify_put_group(struct fsnotify_group *group);
extern void fsnotify_get_event(struct fsnotify_event *event);
extern void fsnotify_put_event(struct fsnotify_event *event);
extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnotify_group *group,
struct fsnotify_event *event);
extern struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
struct fsnotify_event *event,
struct fsnotify_event_private_data *priv,
struct fsnotify_event *(*merge)(struct list_head *,
struct fsnotify_event *));
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
extern struct fsnotify_event *fsnotify_peek_notify_event(struct fsnotify_group *group);
extern struct fsnotify_event *fsnotify_remove_notify_event(struct fsnotify_group *group);
extern void fsnotify_recalc_vfsmount_mask(struct vfsmount *mnt);
extern void fsnotify_recalc_inode_mask(struct inode *inode);
extern void fsnotify_init_mark(struct fsnotify_mark *mark, void (*free_mark)(struct fsnotify_mark *mark));
extern struct fsnotify_mark *fsnotify_find_inode_mark(struct fsnotify_group *group, struct inode *inode);
extern struct fsnotify_mark *fsnotify_find_vfsmount_mark(struct fsnotify_group *group, struct vfsmount *mnt);
extern void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *old);
extern void fsnotify_set_mark_ignored_mask_locked(struct fsnotify_mark *mark, __u32 mask);
extern void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask);
extern int fsnotify_add_mark(struct fsnotify_mark *mark, struct fsnotify_group *group,
struct inode *inode, struct vfsmount *mnt, int allow_dups);
extern void fsnotify_destroy_mark(struct fsnotify_mark *mark);
extern void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group);
extern void fsnotify_clear_inode_marks_by_group(struct fsnotify_group *group);
extern void fsnotify_clear_marks_by_group_flags(struct fsnotify_group *group, unsigned int flags);
extern void fsnotify_clear_marks_by_group(struct fsnotify_group *group);
extern void fsnotify_get_mark(struct fsnotify_mark *mark);
extern void fsnotify_put_mark(struct fsnotify_mark *mark);
extern void fsnotify_unmount_inodes(struct list_head *list);
extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
void *data, int data_is,
const unsigned char *name,
u32 cookie, gfp_t gfp);
extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
struct fsnotify_event *new_event);
#else
static inline int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const unsigned char *name, u32 cookie)
{
return 0;
}
static inline int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
{
return 0;
}
static inline void __fsnotify_inode_delete(struct inode *inode)
{}
static inline void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
{}
static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
{}
static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode)
{}
static inline u32 fsnotify_get_cookie(void)
{
return 0;
}
static inline void fsnotify_unmount_inodes(struct list_head *list)
{}
#endif
#endif
#endif
|