]> nv-tegra.nvidia Code Review - linux-2.6.git/blobdiff - kernel/audit_watch.c
printk: do not handle non-sleepable notification in console_cpu_notify
[linux-2.6.git] / kernel / audit_watch.c
index 097a61c65fe0ede73d73d800ae188f01f4084751..e683869365d9bdaf60abcb44e37da05506ab5672 100644 (file)
@@ -60,7 +60,7 @@ struct audit_parent {
 };
 
 /* fsnotify handle. */
-struct fsnotify_group *audit_watch_group;
+static struct fsnotify_group *audit_watch_group;
 
 /* fsnotify events we care about. */
 #define AUDIT_FS_WATCH (FS_MOVE | FS_CREATE | FS_DELETE | FS_DELETE_SELF |\
@@ -123,7 +123,7 @@ void audit_put_watch(struct audit_watch *watch)
        }
 }
 
-void audit_remove_watch(struct audit_watch *watch)
+static void audit_remove_watch(struct audit_watch *watch)
 {
        list_del(&watch->wlist);
        audit_put_parent(watch->parent);
@@ -144,9 +144,9 @@ int audit_watch_compare(struct audit_watch *watch, unsigned long ino, dev_t dev)
 }
 
 /* Initialize a parent watch entry. */
-static struct audit_parent *audit_init_parent(struct nameidata *ndp)
+static struct audit_parent *audit_init_parent(struct path *path)
 {
-       struct inode *inode = ndp->path.dentry->d_inode;
+       struct inode *inode = path->dentry->d_inode;
        struct audit_parent *parent;
        int ret;
 
@@ -164,8 +164,6 @@ static struct audit_parent *audit_init_parent(struct nameidata *ndp)
                return ERR_PTR(ret);
        }
 
-       fsnotify_recalc_group_mask(audit_watch_group);
-
        return parent;
 }
 
@@ -352,59 +350,43 @@ static void audit_remove_parent_watches(struct audit_parent *parent)
        mutex_unlock(&audit_filter_mutex);
 
        fsnotify_destroy_mark(&parent->mark);
-
-       fsnotify_recalc_group_mask(audit_watch_group);
-
 }
 
 /* Get path information necessary for adding watches. */
-static int audit_get_nd(char *path, struct nameidata **ndp, struct nameidata **ndw)
+static int audit_get_nd(struct audit_watch *watch, struct path *parent)
 {
-       struct nameidata *ndparent, *ndwatch;
+       struct nameidata nd;
+       struct dentry *d;
        int err;
 
-       ndparent = kmalloc(sizeof(*ndparent), GFP_KERNEL);
-       if (unlikely(!ndparent))
-               return -ENOMEM;
+       err = kern_path_parent(watch->path, &nd);
+       if (err)
+               return err;
 
-       ndwatch = kmalloc(sizeof(*ndwatch), GFP_KERNEL);
-       if (unlikely(!ndwatch)) {
-               kfree(ndparent);
-               return -ENOMEM;
+       if (nd.last_type != LAST_NORM) {
+               path_put(&nd.path);
+               return -EINVAL;
        }
 
-       err = path_lookup(path, LOOKUP_PARENT, ndparent);
-       if (err) {
-               kfree(ndparent);
-               kfree(ndwatch);
-               return err;
+       mutex_lock_nested(&nd.path.dentry->d_inode->i_mutex, I_MUTEX_PARENT);
+       d = lookup_one_len(nd.last.name, nd.path.dentry, nd.last.len);
+       if (IS_ERR(d)) {
+               mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
+               path_put(&nd.path);
+               return PTR_ERR(d);
        }
-
-       err = path_lookup(path, 0, ndwatch);
-       if (err) {
-               kfree(ndwatch);
-               ndwatch = NULL;
+       if (d->d_inode) {
+               /* update watch filter fields */
+               watch->dev = d->d_inode->i_sb->s_dev;
+               watch->ino = d->d_inode->i_ino;
        }
+       mutex_unlock(&nd.path.dentry->d_inode->i_mutex);
 
-       *ndp = ndparent;
-       *ndw = ndwatch;
-
+       *parent = nd.path;
+       dput(d);
        return 0;
 }
 
-/* Release resources used for watch path information. */
-static void audit_put_nd(struct nameidata *ndp, struct nameidata *ndw)
-{
-       if (ndp) {
-               path_put(&ndp->path);
-               kfree(ndp);
-       }
-       if (ndw) {
-               path_put(&ndw->path);
-               kfree(ndw);
-       }
-}
-
 /* Associate the given rule with an existing parent.
  * Caller must hold audit_filter_mutex. */
 static void audit_add_to_parent(struct audit_krule *krule,
@@ -445,31 +427,24 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
 {
        struct audit_watch *watch = krule->watch;
        struct audit_parent *parent;
-       struct nameidata *ndp = NULL, *ndw = NULL;
+       struct path parent_path;
        int h, ret = 0;
 
        mutex_unlock(&audit_filter_mutex);
 
        /* Avoid calling path_lookup under audit_filter_mutex. */
-       ret = audit_get_nd(watch->path, &ndp, &ndw);
-       if (ret) {
-               /* caller expects mutex locked */
-               mutex_lock(&audit_filter_mutex);
-               goto error;
-       }
+       ret = audit_get_nd(watch, &parent_path);
 
+       /* caller expects mutex locked */
        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;
-       }
+       if (ret)
+               return ret;
 
        /* either find an old parent or attach a new one */
-       parent = audit_find_parent(ndp->path.dentry->d_inode);
+       parent = audit_find_parent(parent_path.dentry->d_inode);
        if (!parent) {
-               parent = audit_init_parent(ndp);
+               parent = audit_init_parent(&parent_path);
                if (IS_ERR(parent)) {
                        ret = PTR_ERR(parent);
                        goto error;
@@ -484,9 +459,8 @@ int audit_add_watch(struct audit_krule *krule, struct list_head **list)
        h = audit_hash_ino((u32)watch->ino);
        *list = &audit_inode_hash[h];
 error:
-       audit_put_nd(ndp, ndw);         /* NULL args OK */
+       path_put(&parent_path);
        return ret;
-
 }
 
 void audit_remove_watch_rule(struct audit_krule *krule)
@@ -505,13 +479,11 @@ void audit_remove_watch_rule(struct audit_krule *krule)
                        audit_put_parent(parent);
                }
        }
-
-       fsnotify_recalc_group_mask(audit_watch_group);
-
 }
 
 static bool audit_watch_should_send_event(struct fsnotify_group *group, struct inode *inode,
-                                         struct vfsmount *mnt, struct fsnotify_mark *mark,
+                                         struct fsnotify_mark *inode_mark,
+                                         struct fsnotify_mark *vfsmount_mark,
                                          __u32 mask, void *data, int data_type)
 {
        return true;
@@ -519,7 +491,8 @@ static bool audit_watch_should_send_event(struct fsnotify_group *group, struct i
 
 /* Update watch data in audit rules based on fsnotify events. */
 static int audit_watch_handle_event(struct fsnotify_group *group,
-                                   struct fsnotify_mark *mark,
+                                   struct fsnotify_mark *inode_mark,
+                                   struct fsnotify_mark *vfsmount_mark,
                                    struct fsnotify_event *event)
 {
        struct inode *inode;
@@ -527,13 +500,13 @@ static int audit_watch_handle_event(struct fsnotify_group *group,
        const char *dname = event->file_name;
        struct audit_parent *parent;
 
-       parent = container_of(mark, struct audit_parent, mark);
+       parent = container_of(inode_mark, struct audit_parent, mark);
 
        BUG_ON(group != audit_watch_group);
 
        switch (event->data_type) {
-       case (FSNOTIFY_EVENT_FILE):
-               inode = event->file->f_path.dentry->d_inode;
+       case (FSNOTIFY_EVENT_PATH):
+               inode = event->path.dentry->d_inode;
                break;
        case (FSNOTIFY_EVENT_INODE):
                inode = event->inode;