Skip to content

Commit

Permalink
fsnotify: add correlations between events
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Paris committed Jun 11, 2009
1 parent 62ffe5d commit 47882c6
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 25 deletions.
6 changes: 3 additions & 3 deletions fs/notify/fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ void __fsnotify_parent(struct dentry *dentry, __u32 mask)
mask |= FS_EVENT_ON_CHILD;

fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
dentry->d_name.name);
dentry->d_name.name, 0);
dput(parent);
}

Expand All @@ -132,7 +132,7 @@ EXPORT_SYMBOL_GPL(__fsnotify_parent);
* out to all of the registered fsnotify_group. Those groups can then use the
* notification event in whatever means they feel necessary.
*/
void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name)
void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie)
{
struct fsnotify_group *group;
struct fsnotify_event *event = NULL;
Expand All @@ -157,7 +157,7 @@ void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const
if (!group->ops->should_send_event(group, to_tell, mask))
continue;
if (!event) {
event = fsnotify_create_event(to_tell, mask, data, data_is, file_name);
event = fsnotify_create_event(to_tell, mask, data, data_is, file_name, cookie);
/* shit, we OOM'd and now we can't tell, maybe
* someday someone else will want to do something
* here */
Expand Down
20 changes: 18 additions & 2 deletions fs/notify/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/mount.h>
#include <linux/mutex.h>
#include <linux/namei.h>
Expand All @@ -56,6 +57,17 @@ static struct kmem_cache *fsnotify_event_holder_cachep;
* get set to 0 so it will never get 'freed'
*/
static struct fsnotify_event q_overflow_event;
static atomic_t fsnotify_sync_cookie = ATOMIC_INIT(0);

/**
* fsnotify_get_cookie - return a unique cookie for use in synchronizing events.
* Called from fsnotify_move, which is inlined into filesystem modules.
*/
u32 fsnotify_get_cookie(void)
{
return atomic_inc_return(&fsnotify_sync_cookie);
}
EXPORT_SYMBOL_GPL(fsnotify_get_cookie);

/* return true if the notify queue is empty, false otherwise */
bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group)
Expand Down Expand Up @@ -266,6 +278,8 @@ static void initialize_event(struct fsnotify_event *event)

event->file_name = NULL;
event->name_len = 0;

event->sync_cookie = 0;
}

/*
Expand All @@ -280,8 +294,8 @@ static void initialize_event(struct fsnotify_event *event)
* @data_type flag indication if the data is a file, path, inode, nothing...
* @name the filename, if available
*/
struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
void *data, int data_type, const char *name)
struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask, void *data,
int data_type, const char *name, u32 cookie)
{
struct fsnotify_event *event;

Expand All @@ -299,6 +313,8 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
}
event->name_len = strlen(event->file_name);
}

event->sync_cookie = cookie;
event->to_tell = to_tell;

switch (data_type) {
Expand Down
35 changes: 18 additions & 17 deletions include/linux/fsnotify.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ static inline void fsnotify_link_count(struct inode *inode)
{
inotify_inode_queue_event(inode, IN_ATTRIB, 0, NULL, NULL);

fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, FS_ATTRIB, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}

/*
Expand All @@ -69,7 +69,8 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
int isdir, struct inode *target, struct dentry *moved)
{
struct inode *source = moved->d_inode;
u32 cookie = inotify_get_cookie();
u32 in_cookie = inotify_get_cookie();
u32 fs_cookie = fsnotify_get_cookie();
__u32 old_dir_mask = 0;
__u32 new_dir_mask = 0;

Expand All @@ -86,13 +87,13 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
old_dir_mask |= FS_MOVED_FROM;
new_dir_mask |= FS_MOVED_TO;

inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir,cookie,old_name,
inotify_inode_queue_event(old_dir, IN_MOVED_FROM|isdir, in_cookie, old_name,
source);
inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, cookie, new_name,
inotify_inode_queue_event(new_dir, IN_MOVED_TO|isdir, in_cookie, new_name,
source);

fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name);
fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name);
fsnotify(old_dir, old_dir_mask, old_dir, FSNOTIFY_EVENT_INODE, old_name, fs_cookie);
fsnotify(new_dir, new_dir_mask, new_dir, FSNOTIFY_EVENT_INODE, new_name, fs_cookie);

if (target) {
inotify_inode_queue_event(target, IN_DELETE_SELF, 0, NULL, NULL);
Expand All @@ -104,7 +105,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,

if (source) {
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
audit_inode_child(new_name, moved, new_dir);
}
Expand Down Expand Up @@ -138,7 +139,7 @@ static inline void fsnotify_inoderemove(struct inode *inode)
inotify_inode_queue_event(inode, IN_DELETE_SELF, 0, NULL, NULL);
inotify_inode_is_dead(inode);

fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, FS_DELETE_SELF, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
__fsnotify_inode_delete(inode);
}

Expand All @@ -151,7 +152,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry, inode);

fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}

/*
Expand All @@ -166,7 +167,7 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
fsnotify_link_count(inode);
audit_inode_child(new_dentry->d_name.name, new_dentry, dir);

fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name);
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
}

/*
Expand All @@ -180,7 +181,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
audit_inode_child(dentry->d_name.name, dentry, inode);

fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
}

/*
Expand All @@ -197,7 +198,7 @@ static inline void fsnotify_access(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}

/*
Expand All @@ -214,7 +215,7 @@ static inline void fsnotify_modify(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}

/*
Expand All @@ -231,7 +232,7 @@ static inline void fsnotify_open(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}

/*
Expand All @@ -250,7 +251,7 @@ static inline void fsnotify_close(struct file *file)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL);
fsnotify(inode, mask, file, FSNOTIFY_EVENT_FILE, NULL, 0);
}

/*
Expand All @@ -267,7 +268,7 @@ static inline void fsnotify_xattr(struct dentry *dentry)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}

/*
Expand Down Expand Up @@ -303,7 +304,7 @@ static inline void fsnotify_change(struct dentry *dentry, unsigned int ia_valid)
inotify_inode_queue_event(inode, mask, 0, NULL, NULL);

fsnotify_parent(dentry, mask);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL);
fsnotify(inode, mask, inode, FSNOTIFY_EVENT_INODE, NULL, 0);
}
}

Expand Down
15 changes: 12 additions & 3 deletions include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ struct fsnotify_event {
atomic_t refcnt; /* how many groups still are using/need to send this event */
__u32 mask; /* the type of access, bitwise OR for FS_* event types */

u32 sync_cookie; /* used to corrolate events, namely inotify mv events */
char *file_name;
size_t name_len;
};
Expand Down Expand Up @@ -227,9 +228,11 @@ struct fsnotify_mark_entry {
/* called from the vfs helpers */

/* main fsnotify call to send events */
extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *name);
extern void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const char *name, u32 cookie);
extern void __fsnotify_parent(struct dentry *dentry, __u32 mask);
extern void __fsnotify_inode_delete(struct inode *inode);
extern u32 fsnotify_get_cookie(void);

static inline int fsnotify_inode_watches_children(struct inode *inode)
{
Expand Down Expand Up @@ -322,12 +325,13 @@ extern void fsnotify_put_mark(struct fsnotify_mark_entry *entry);

/* put here because inotify does some weird stuff when destroying watches */
extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
void *data, int data_is, const char *name);
void *data, int data_is, const char *name,
u32 cookie);

#else

static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
const char *name);
const char *name, u32 cookie)
{}

static inline void __fsnotify_parent(struct dentry *dentry, __u32 mask)
Expand All @@ -342,6 +346,11 @@ 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;
}

#endif /* CONFIG_FSNOTIFY */

#endif /* __KERNEL __ */
Expand Down

0 comments on commit 47882c6

Please sign in to comment.