]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - fs/kernfs/file.c
Merge branches 'acpi-general' and 'acpi-video'
[karo-tx-linux.git] / fs / kernfs / file.c
index e01ea4a14a014b3123dddf6d2ad1ecb9a6381736..e3d37f607f975dd06f6c9534b2dc929c3fa5fa21 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/poll.h>
 #include <linux/pagemap.h>
 #include <linux/sched.h>
+#include <linux/fsnotify.h>
 
 #include "kernfs-internal.h"
 
@@ -610,6 +611,7 @@ static void kernfs_put_open_node(struct kernfs_node *kn,
 static int kernfs_fop_open(struct inode *inode, struct file *file)
 {
        struct kernfs_node *kn = file->f_path.dentry->d_fsdata;
+       struct kernfs_root *root = kernfs_root(kn);
        const struct kernfs_ops *ops;
        struct kernfs_open_file *of;
        bool has_read, has_write, has_mmap;
@@ -624,14 +626,16 @@ static int kernfs_fop_open(struct inode *inode, struct file *file)
        has_write = ops->write || ops->mmap;
        has_mmap = ops->mmap;
 
-       /* check perms and supported operations */
-       if ((file->f_mode & FMODE_WRITE) &&
-           (!(inode->i_mode & S_IWUGO) || !has_write))
-               goto err_out;
+       /* see the flag definition for details */
+       if (root->flags & KERNFS_ROOT_EXTRA_OPEN_PERM_CHECK) {
+               if ((file->f_mode & FMODE_WRITE) &&
+                   (!(inode->i_mode & S_IWUGO) || !has_write))
+                       goto err_out;
 
-       if ((file->f_mode & FMODE_READ) &&
-           (!(inode->i_mode & S_IRUGO) || !has_read))
-               goto err_out;
+               if ((file->f_mode & FMODE_READ) &&
+                   (!(inode->i_mode & S_IRUGO) || !has_read))
+                       goto err_out;
+       }
 
        /* allocate a kernfs_open_file for the file */
        error = -ENOMEM;
@@ -787,20 +791,48 @@ static unsigned int kernfs_fop_poll(struct file *filp, poll_table *wait)
  */
 void kernfs_notify(struct kernfs_node *kn)
 {
+       struct kernfs_root *root = kernfs_root(kn);
        struct kernfs_open_node *on;
+       struct kernfs_super_info *info;
        unsigned long flags;
 
+       if (WARN_ON(kernfs_type(kn) != KERNFS_FILE))
+               return;
+
+       /* kick poll */
        spin_lock_irqsave(&kernfs_open_node_lock, flags);
 
-       if (!WARN_ON(kernfs_type(kn) != KERNFS_FILE)) {
-               on = kn->attr.open;
-               if (on) {
-                       atomic_inc(&on->event);
-                       wake_up_interruptible(&on->poll);
-               }
+       on = kn->attr.open;
+       if (on) {
+               atomic_inc(&on->event);
+               wake_up_interruptible(&on->poll);
        }
 
        spin_unlock_irqrestore(&kernfs_open_node_lock, flags);
+
+       /* kick fsnotify */
+       mutex_lock(&kernfs_mutex);
+
+       list_for_each_entry(info, &root->supers, node) {
+               struct inode *inode;
+               struct dentry *dentry;
+
+               inode = ilookup(info->sb, kn->ino);
+               if (!inode)
+                       continue;
+
+               dentry = d_find_any_alias(inode);
+               if (dentry) {
+                       fsnotify_parent(NULL, dentry, FS_MODIFY);
+                       fsnotify(inode, FS_MODIFY, inode, FSNOTIFY_EVENT_INODE,
+                                NULL, 0);
+                       dput(dentry);
+               }
+
+               iput(inode);
+       }
+
+       mutex_unlock(&kernfs_mutex);
 }
 EXPORT_SYMBOL_GPL(kernfs_notify);