aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Paris <eparis@redhat.com>2009-05-21 17:01:47 -0400
committerEric Paris <eparis@redhat.com>2009-06-11 14:57:54 -0400
commit47882c6f51e8ef41fbbe2bbb746a1ea3228dd7ca (patch)
treed3dd3e8d0e4d3e3793f32107077839f787e35fcd
parent62ffe5dfba056f7ba81d710fee9f28c58a42fdd6 (diff)
fsnotify: add correlations between events
As part of the standard inotify events it includes a correlation cookie between two dentry move operations. This patch includes the same behaviour in fsnotify events. It is needed so that inotify userspace can be implemented on top of fsnotify. Signed-off-by: Eric Paris <eparis@redhat.com> Acked-by: Al Viro <viro@zeniv.linux.org.uk> Cc: Christoph Hellwig <hch@lst.de>
-rw-r--r--fs/notify/fsnotify.c6
-rw-r--r--fs/notify/notification.c20
-rw-r--r--include/linux/fsnotify.h35
-rw-r--r--include/linux/fsnotify_backend.h15
4 files changed, 51 insertions, 25 deletions
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 675129fa9fdd..f11d75f02368 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -115,7 +115,7 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
115 mask |= FS_EVENT_ON_CHILD; 115 mask |= FS_EVENT_ON_CHILD;
116 116
117 fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE, 117 fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
118 dentry->d_name.name); 118 dentry->d_name.name, 0);
119 dput(parent); 119 dput(parent);
120 } 120 }
121 121
@@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(__fsnotify_parent);
132 * out to all of the registered fsnotify_group. Those groups can then use the 132 * out to all of the registered fsnotify_group. Those groups can then use the
133 * notification event in whatever means they feel necessary. 133 * notification event in whatever means they feel necessary.
134 */ 134 */
135void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name) 135void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie)
136{ 136{
137 struct fsnotify_group *group; 137 struct fsnotify_group *group;
138 struct fsnotify_event *event = NULL; 138 struct fsnotify_event *event = NULL;
@@ -157,7 +157,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
157 if (!group->ops->should_send_event(group, to_tell, mask)) 157 if (!group->ops->should_send_event(group, to_tell, mask))
158 continue; 158 continue;
159 if (!event) { 159 if (!event) {
160 event = fsnotify_create_event(to_tell, mask, data, data_is, file_name); 160 event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie);
161 /* shit, we OOM'd and now we can't tell, maybe 161 /* shit, we OOM'd and now we can't tell, maybe
162 * someday someone else will want to do something 162 * someday someone else will want to do something
163 * here */ 163 * here */
diff --git a/fs/notify/notification.c b/fs/notify/notification.c
index c69b18b9aba5..346f6e5c3553 100644
--- a/fs/notify/notification.c
+++ b/fs/notify/notification.c
@@ -35,6 +35,7 @@
35#include <linux/init.h> 35#include <linux/init.h>
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <linux/list.h> 37#include <linux/list.h>
38#include <linux/module.h>
38#include <linux/mount.h> 39#include <linux/mount.h>
39#include <linux/mutex.h> 40#include <linux/mutex.h>
40#include <linux/namei.h> 41#include <linux/namei.h>
@@ -56,6 +57,17 @@ static struct kmem_cache *fsnotify_event_holder_cachep;
56 * get set to 0 so it will never get 'freed' 57 * get set to 0 so it will never get 'freed'
57 */ 58 */
58static struct fsnotify_event q_overflow_event; 59static struct fsnotify_event q_overflow_event;
60static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);
61
62/**
63 * fsnotify_get_cookie - return a unique cookie for use in synchronizing events.
64 * Called from fsnotify_move, which is inlined into filesystem modules.
65 */
66u32 fsnotify_get_cookie(void)
67{
68 return atomic_inc_return(&fsnotify_sync_cookie);
69}
70EXPORT_SYMBOL_GPL(fsnotify_get_cookie);
59 71
60/* return true if the notify queue is empty, false otherwise */ 72/* return true if the notify queue is empty, false otherwise */
61bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group) 73bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
@@ -266,6 +278,8 @@ static void initialize_event(struct fsnotify_event *event)
266 278
267 event->file_name = NULL; 279 event->file_name = NULL;
268 event->name_len = 0; 280 event->name_len = 0;
281
282 event->sync_cookie = 0;
269} 283}
270 284
271/* 285/*
@@ -280,8 +294,8 @@ static void initialize_event(struct fsnotify_event *event)
280 * @data_type flag indication if the data is a file, path, inode, nothing... 294 * @data_type flag indication if the data is a file, path, inode, nothing...
281 * @name the filename, if available 295 * @name the filename, if available
282 */ 296 */
283struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, 297struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
284 void *data, int data_type, const char *name) 298 int data_type, const char *name, u32 cookie)
285{ 299{
286 struct fsnotify_event *event; 300 struct fsnotify_event *event;
287 301
@@ -299,6 +313,8 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
299 } 313 }
300 event->name_len = strlen(event->file_name); 314 event->name_len = strlen(event->file_name);
301 } 315 }
316
317 event->sync_cookie = cookie;
302 event->to_tell = to_tell; 318 event->to_tell = to_tell;
303 319
304 switch (data_type) { 320 switch (data_type) {
diff --git a/include/linux/fsnotify.h b/include/linux/fsnotify.h
index 180740e9ec82..c25b39ddd62a 100644
--- a/include/linux/fsnotify.h
+++ b/include/linux/fsnotify.h
@@ -58,7 +58,7 @@ static inline void fsnotify_link_count(struct inode *inode)
58{ 58{
59 inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL); 59 inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);
60 60
61 fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL); 61 fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
62} 62}
63 63
64/* 64/*
@@ -69,7 +69,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
69 int isdir, struct inode *target, struct dentry *moved) 69 int isdir, struct inode *target, struct dentry *moved)
70{ 70{
71 struct inode *source = moved->d_inode; 71 struct inode *source = moved->d_inode;
72 u32 cookie = inotify_get_cookie(); 72 u32 in_cookie = inotify_get_cookie();
73 u32 fs_cookie = fsnotify_get_cookie();
73 __u32 old_dir_mask = 0; 74 __u32 old_dir_mask = 0;
74 __u32 new_dir_mask = 0; 75 __u32 new_dir_mask = 0;
75 76
@@ -86,13 +87,13 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
86 old_dir_mask |= FS_MOVED_FROM; 87 old_dir_mask |= FS_MOVED_FROM;
87 new_dir_mask |= FS_MOVED_TO; 88 new_dir_mask |= FS_MOVED_TO;
88 89
89 inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name, 90 inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, in_cookie, old_name,
90 source); 91 source);
91 inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name, 92 inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, in_cookie, new_name,
92 source); 93 source);
93 94
94 fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name); 95 fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
95 fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name); 96 fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name, fs_cookie);
96 97
97 if (target) { 98 if (target) {
98 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL); 99 inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
@@ -104,7 +105,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
104 105
105 if (source) { 106 if (source) {
106 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); 107 inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
107 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL); 108 fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
108 } 109 }
109 audit_inode_child(new_name, moved, new_dir); 110 audit_inode_child(new_name, moved, new_dir);
110} 111}
@@ -138,7 +139,7 @@ static inline void fsnotify_inoderemove(struct inode *inode)
138 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL); 139 inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
139 inotify_inode_is_dead(inode); 140 inotify_inode_is_dead(inode);
140 141
141 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL); 142 fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
142 __fsnotify_inode_delete(inode); 143 __fsnotify_inode_delete(inode);
143} 144}
144 145
@@ -151,7 +152,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
151 dentry->d_inode); 152 dentry->d_inode);
152 audit_inode_child(dentry->d_name.name, dentry, inode); 153 audit_inode_child(dentry->d_name.name, dentry, inode);
153 154
154 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name); 155 fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
155} 156}
156 157
157/* 158/*
@@ -166,7 +167,7 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
166 fsnotify_link_count(inode); 167 fsnotify_link_count(inode);
167 audit_inode_child(new_dentry->d_name.name, new_dentry, dir); 168 audit_inode_child(new_dentry->d_name.name, new_dentry, dir);
168 169
169 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name); 170 fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
170} 171}
171 172
172/* 173/*
@@ -180,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
180 inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode); 181 inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
181 audit_inode_child(dentry->d_name.name, dentry, inode); 182 audit_inode_child(dentry->d_name.name, dentry, inode);
182 183
183 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name); 184 fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
184} 185}
185 186
186/* 187/*
@@ -197,7 +198,7 @@ static inline void fsnotify_access(struct dentry *dentry)
197 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 198 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
198 199
199 fsnotify_parent(dentry, mask); 200 fsnotify_parent(dentry, mask);
200 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL); 201 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
201} 202}
202 203
203/* 204/*
@@ -214,7 +215,7 @@ static inline void fsnotify_modify(struct dentry *dentry)
214 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 215 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
215 216
216 fsnotify_parent(dentry, mask); 217 fsnotify_parent(dentry, mask);
217 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL); 218 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
218} 219}
219 220
220/* 221/*
@@ -231,7 +232,7 @@ static inline void fsnotify_open(struct dentry *dentry)
231 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 232 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
232 233
233 fsnotify_parent(dentry, mask); 234 fsnotify_parent(dentry, mask);
234 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL); 235 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
235} 236}
236 237
237/* 238/*
@@ -250,7 +251,7 @@ static inline void fsnotify_close(struct file *file)
250 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 251 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
251 252
252 fsnotify_parent(dentry, mask); 253 fsnotify_parent(dentry, mask);
253 fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL); 254 fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
254} 255}
255 256
256/* 257/*
@@ -267,7 +268,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
267 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 268 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
268 269
269 fsnotify_parent(dentry, mask); 270 fsnotify_parent(dentry, mask);
270 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL); 271 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
271} 272}
272 273
273/* 274/*
@@ -303,7 +304,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
303 inotify_inode_queue_event(inode, mask, 0, NULL, NULL); 304 inotify_inode_queue_event(inode, mask, 0, NULL, NULL);
304 305
305 fsnotify_parent(dentry, mask); 306 fsnotify_parent(dentry, mask);
306 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL); 307 fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
307 } 308 }
308} 309}
309 310
diff --git a/include/linux/fsnotify_backend.h b/include/linux/fsnotify_backend.h
index 52692f405890..b78b5573d227 100644
--- a/include/linux/fsnotify_backend.h
+++ b/include/linux/fsnotify_backend.h
@@ -193,6 +193,7 @@ struct fsnotify_event {
193 atomic_t refcnt; /* how many groups still are using/need to send this event */ 193 atomic_t refcnt; /* how many groups still are using/need to send this event */
194 __u32 mask; /* the type of access, bitwise OR for FS_* event types */ 194 __u32 mask; /* the type of access, bitwise OR for FS_* event types */
195 195
196 u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
196 char *file_name; 197 char *file_name;
197 size_t name_len; 198 size_t name_len;
198}; 199};
@@ -227,9 +228,11 @@ struct fsnotify_mark_entry {
227/* called from the vfs helpers */ 228/* called from the vfs helpers */
228 229
229/* main fsnotify call to send events */ 230/* main fsnotify call to send events */
230extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *name); 231extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
232 const char *name, u32 cookie);
231extern void __fsnotify_parent(struct dentry *dentry, __u32 mask); 233extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
232extern void __fsnotify_inode_delete(struct inode *inode); 234extern void __fsnotify_inode_delete(struct inode *inode);
235extern u32 fsnotify_get_cookie(void);
233 236
234static inline int fsnotify_inode_watches_children(struct inode *inode) 237static inline int fsnotify_inode_watches_children(struct inode *inode)
235{ 238{
@@ -322,12 +325,13 @@ extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);
322 325
323/* put here because inotify does some weird stuff when destroying watches */ 326/* put here because inotify does some weird stuff when destroying watches */
324extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, 327extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
325 void *data, int data_is, const char *name); 328 void *data, int data_is, const char *name,
329 u32 cookie);
326 330
327#else 331#else
328 332
329static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 333static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
330 const char *name); 334 const char *name, u32 cookie)
331{} 335{}
332 336
333static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask) 337static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
@@ -342,6 +346,11 @@ static inline void __fsnotify_update_dcache_flags(struct dentry *dentry)
342static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode) 346static inline void __fsnotify_d_instantiate(struct dentry *dentry, struct inode *inode)
343{} 347{}
344 348
349static inline u32 fsnotify_get_cookie(void)
350{
351 return 0;
352}
353
345#endif /* CONFIG_FSNOTIFY */ 354#endif /* CONFIG_FSNOTIFY */
346 355
347#endif /* __KERNEL __ */ 356#endif /* __KERNEL __ */