Revert "fsnotify: store struct file not struct path"
[sfrench/cifs-2.6.git] / kernel / audit_watch.c
index ff5be849473dc1f60c104272ab2c2d5debd0946b..f0c9b2e7542dfd5b2980164a2f5ccedbcd2bb0d1 100644 (file)
@@ -55,26 +55,13 @@ struct audit_watch {
 };
 
 struct audit_parent {
-       struct list_head        ilist;  /* tmp list used to free parents */
        struct list_head        watches; /* anchor for audit_watch->wlist */
-       struct fsnotify_mark_entry mark; /* fsnotify mark on the inode */
-       unsigned                flags;  /* status flags */
+       struct fsnotify_mark mark; /* fsnotify mark on the inode */
 };
 
 /* fsnotify handle. */
 struct fsnotify_group *audit_watch_group;
 
-/*
- * audit_parent status flags:
- *
- * AUDIT_PARENT_INVALID - set anytime rules/watches are auto-removed due to
- * a filesystem event to ensure we're adding audit watches to a valid parent.
- * Technically not needed for FS_DELETE_SELF or FS_UNMOUNT events, as we cannot
- * receive them while we have nameidata, but must be used for FS_MOVE_SELF which
- * we can receive while holding nameidata.
- */
-#define AUDIT_PARENT_INVALID   0x001
-
 /* fsnotify events we care about. */
 #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
                        FS_MOVE_SELF | FS_EVENT_ON_CHILD)
@@ -85,7 +72,7 @@ static void audit_free_parent(struct audit_parent *parent)
        kfree(parent);
 }
 
-static void audit_watch_free_mark(struct fsnotify_mark_entry *entry)
+static void audit_watch_free_mark(struct fsnotify_mark *entry)
 {
        struct audit_parent *parent;
 
@@ -112,12 +99,9 @@ static void audit_put_parent(struct audit_parent *parent)
 static inline struct audit_parent *audit_find_parent(struct inode *inode)
 {
        struct audit_parent *parent = NULL;
-       struct fsnotify_mark_entry *entry;
-
-       spin_lock(&inode->i_lock);
-       entry = fsnotify_find_mark_entry(audit_watch_group, inode);
-       spin_unlock(&inode->i_lock);
+       struct fsnotify_mark *entry;
 
+       entry = fsnotify_find_inode_mark(audit_watch_group, inode);
        if (entry)
                parent = container_of(entry, struct audit_parent, mark);
 
@@ -171,13 +155,10 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp)
                return ERR_PTR(-ENOMEM);
 
        INIT_LIST_HEAD(&parent->watches);
-       parent->flags = 0;
 
        fsnotify_init_mark(&parent->mark, audit_watch_free_mark);
        parent->mark.mask = AUDIT_FS_WATCH;
-       /* grab a ref so fsnotify mark hangs around until we take audit_filter_mutex */
-       audit_get_parent(parent);
-       ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode);
+       ret = fsnotify_add_mark(&parent->mark, audit_watch_group, inode, NULL, 0);
        if (ret < 0) {
                audit_free_parent(parent);
                return ERR_PTR(ret);
@@ -355,7 +336,6 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
        struct audit_entry *e;
 
        mutex_lock(&audit_filter_mutex);
-       parent->flags |= AUDIT_PARENT_INVALID;
        list_for_each_entry_safe(w, nextw, &parent->watches, wlist) {
                list_for_each_entry_safe(r, nextr, &w->rules, rlist) {
                        e = container_of(r, struct audit_entry, rule);
@@ -369,21 +349,7 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
        }
        mutex_unlock(&audit_filter_mutex);
 
-       fsnotify_destroy_mark_by_entry(&parent->mark);
-}
-
-/* Unregister inotify watches for parents on in_list.
- * Generates an FS_IGNORED event. */
-void audit_watch_inotify_unregister(struct list_head *in_list)
-{
-       struct audit_parent *p, *n;
-
-       list_for_each_entry_safe(p, n, in_list, ilist) {
-               list_del(&p->ilist);
-               fsnotify_destroy_mark_by_entry(&p->mark);
-               /* matches the get in audit_remove_watch_rule() */
-               audit_put_parent(p);
-       }
+       fsnotify_destroy_mark(&parent->mark);
 }
 
 /* Get path information necessary for adding watches. */
@@ -487,35 +453,25 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
                goto error;
        }
 
+       mutex_lock(&audit_filter_mutex);
+
        /* update watch filter fields */
        if (ndw) {
                watch->dev = ndw->path.dentry->d_inode->i_sb->s_dev;
                watch->ino = ndw->path.dentry->d_inode->i_ino;
        }
 
-       /* The audit_filter_mutex must not be held during inotify calls because
-        * we hold it during inotify event callback processing.  If an existing
-        * inotify watch is found, inotify_find_watch() grabs a reference before
-        * returning.
-        */
+       /* either find an old parent or attach a new one */
        parent = audit_find_parent(ndp->path.dentry->d_inode);
        if (!parent) {
                parent = audit_init_parent(ndp);
                if (IS_ERR(parent)) {
-                       /* caller expects mutex locked */
-                       mutex_lock(&audit_filter_mutex);
                        ret = PTR_ERR(parent);
                        goto error;
                }
        }
 
-       mutex_lock(&audit_filter_mutex);
-
-       /* parent was moved before we took audit_filter_mutex */
-       if (parent->flags & AUDIT_PARENT_INVALID)
-               ret = -ENOENT;
-       else
-               audit_add_to_parent(krule, parent);
+       audit_add_to_parent(krule, parent);
 
        /* match get in audit_find_parent or audit_init_parent */
        audit_put_parent(parent);
@@ -528,7 +484,7 @@ error:
 
 }
 
-void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
+void audit_remove_watch_rule(struct audit_krule *krule)
 {
        struct audit_watch *watch = krule->watch;
        struct audit_parent *parent = watch->parent;
@@ -539,52 +495,35 @@ void audit_remove_watch_rule(struct audit_krule *krule, struct list_head *list)
                audit_remove_watch(watch);
 
                if (list_empty(&parent->watches)) {
-                       /* Put parent on the un-registration list.
-                        * Grab a reference before releasing
-                        * audit_filter_mutex, to be released in
-                        * audit_watch_inotify_unregister().
-                        * If filesystem is going away, just leave
-                        * the sucker alone, eviction will take
-                        * care of it. */
                        audit_get_parent(parent);
-                       list_add(&parent->ilist, list);
+                       fsnotify_destroy_mark(&parent->mark);
+                       audit_put_parent(parent);
                }
        }
 }
 
-static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
+static bool audit_watch_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)
 {
-       struct fsnotify_mark_entry *entry;
-       bool send;
-
-       spin_lock(&inode->i_lock);
-       entry = fsnotify_find_mark_entry(group, inode);
-       spin_unlock(&inode->i_lock);
-       if (!entry)
-               return false;
-
-       mask = (mask & ~FS_EVENT_ON_CHILD);
-       send = (entry->mask & mask);
-
-       /* find took a reference */
-       fsnotify_put_mark(entry);
-
-       return send;
+       return true;
 }
 
 /* Update watch data in audit rules based on fsnotify events. */
-static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+static int audit_watch_handle_event(struct fsnotify_group *group,
+                                   struct fsnotify_mark *inode_mark,
+                                   struct fsnotify_mark *vfsmount_mark,
+                                   struct fsnotify_event *event)
 {
        struct inode *inode;
        __u32 mask = event->mask;
        const char *dname = event->file_name;
        struct audit_parent *parent;
 
-       BUG_ON(group != audit_watch_group);
+       parent = container_of(inode_mark, struct audit_parent, mark);
 
-       parent = audit_find_parent(event->to_tell);
-       if (unlikely(!parent))
-               return 0;
+       BUG_ON(group != audit_watch_group);
 
        switch (event->data_type) {
        case (FSNOTIFY_EVENT_PATH):
@@ -605,39 +544,25 @@ static int audit_watch_handle_event(struct fsnotify_group *group, struct fsnotif
                audit_update_watch(parent, dname, (dev_t)-1, (unsigned long)-1, 1);
        else if (mask & (FS_DELETE_SELF|FS_UNMOUNT|FS_MOVE_SELF))
                audit_remove_parent_watches(parent);
-       /* moved put_inotify_watch to freeing mark */
-
-       /* matched the ref taken by audit_find_parent */
-       audit_put_parent(parent);
 
        return 0;
 }
 
-static void audit_watch_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
-{
-       struct audit_parent *parent;
-
-       parent = container_of(entry, struct audit_parent, mark);
-       /* taken from audit_handle_ievent & FS_IGNORED please figure out what I match... */
-       audit_put_parent(parent);
-}
-
 static const struct fsnotify_ops audit_watch_fsnotify_ops = {
        .should_send_event =    audit_watch_should_send_event,
        .handle_event =         audit_watch_handle_event,
        .free_group_priv =      NULL,
-       .freeing_mark =         audit_watch_freeing_mark,
+       .freeing_mark =         NULL,
        .free_event_priv =      NULL,
 };
 
 static int __init audit_watch_init(void)
 {
-       audit_watch_group = fsnotify_obtain_group(AUDIT_WATCH_GROUP_NUM, AUDIT_FS_WATCH,
-                                                 &audit_watch_fsnotify_ops);
+       audit_watch_group = fsnotify_alloc_group(&audit_watch_fsnotify_ops);
        if (IS_ERR(audit_watch_group)) {
                audit_watch_group = NULL;
                audit_panic("cannot create audit fsnotify group");
        }
        return 0;
 }
-subsys_initcall(audit_watch_init);
+device_initcall(audit_watch_init);