fsnotify: clone existing events
authorEric Paris <eparis@redhat.com>
Fri, 18 Dec 2009 02:24:21 +0000 (21:24 -0500)
committerEric Paris <eparis@redhat.com>
Wed, 28 Jul 2010 13:58:49 +0000 (09:58 -0400)
fsnotify_clone_event will take an event, clone it, and return the cloned
event to the caller.  Since events may be in use by multiple fsnotify
groups simultaneously certain event entries (such as the mask) cannot be
changed after the event was created.  Since fanotify would like to merge
events happening on the same file it needs a new clean event to work with
so it can change any fields it wishes.

Signed-off-by: Eric Paris <eparis@redhat.com>
fs/notify/notification.c
include/linux/fsnotify_backend.h

index 6dc96b35e4a75ea993171aba683beb463daed62b..bc9470c7ece7f3c1f808876585171ac7547362e6 100644 (file)
@@ -284,11 +284,33 @@ static void initialize_event(struct fsnotify_event *event)
 
        spin_lock_init(&event->lock);
 
-       event->data_type = FSNOTIFY_EVENT_NONE;
-
        INIT_LIST_HEAD(&event->private_data_list);
 }
 
+struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
+{
+       struct fsnotify_event *event;
+
+       event = kmem_cache_alloc(fsnotify_event_cachep, GFP_KERNEL);
+       if (!event)
+               return NULL;
+
+       memcpy(event, old_event, sizeof(*event));
+       initialize_event(event);
+
+       if (event->name_len) {
+               event->file_name = kstrdup(old_event->file_name, GFP_KERNEL);
+               if (!event->file_name) {
+                       kmem_cache_free(fsnotify_event_cachep, event);
+                       return NULL;
+               }
+       }
+       if (event->data_type == FSNOTIFY_EVENT_PATH)
+               path_get(&event->path);
+
+       return event;
+}
+
 /*
  * fsnotify_create_event - Allocate a new event which will be sent to each
  * group's handle_event function if the group was interested in this
@@ -324,6 +346,7 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
 
        event->sync_cookie = cookie;
        event->to_tell = to_tell;
+       event->data_type = data_type;
 
        switch (data_type) {
        case FSNOTIFY_EVENT_FILE: {
@@ -340,12 +363,10 @@ struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32 mask,
                event->path.dentry = path->dentry;
                event->path.mnt = path->mnt;
                path_get(&event->path);
-               event->data_type = FSNOTIFY_EVENT_PATH;
                break;
        }
        case FSNOTIFY_EVENT_INODE:
                event->inode = data;
-               event->data_type = FSNOTIFY_EVENT_INODE;
                break;
        case FSNOTIFY_EVENT_NONE:
                event->inode = NULL;
index 25789d45fad8d75396c4e32acc0b86d6c9178621..3a7fff235539f2514f397f646e44372c8a77e6cf 100644 (file)
@@ -363,6 +363,9 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32
                                                    void *data, int data_is, const char *name,
                                                    u32 cookie, gfp_t gfp);
 
+/* fanotify likes to change events after they are on lists... */
+extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
+
 #else
 
 static inline void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,