Skip to content

Commit

Permalink
kernfs: make kernfs_notify() trigger inotify events too
Browse files Browse the repository at this point in the history
kernfs_notify() is used to indicate either new data is available or
the content of a file has changed.  It currently only triggers poll
which may not be the most convenient to monitor especially when there
are a lot to monitor.  Let's hook it up to fsnotify too so that the
events can be monitored via inotify too.

fsnotify_modify() requires file * but kernfs_notify() doesn't have any
specific file associated; however, we can walk all super_blocks
associated with a kernfs_root and as kernfs always associate one ino
with inode and one dentry with an inode, it's trivial to look up the
dentry associated with a given kernfs_node.  As any active monitor
would pin dentry, just looking up existing dentry is enough.  This
patch looks up the dentry associated with the specified kernfs_node
and generates events equivalent to fsnotify_modify().

Note that as fsnotify doesn't provide fsnotify_modify() equivalent
which can be called with dentry, kernfs_notify() directly calls
fsnotify_parent() and fsnotify().  It might be better to add a wrapper
in fsnotify.h instead.

Signed-off-by: Tejun Heo <tj@kernel.org>
Cc: John McCutchan <john@johnmccutchan.com>
Cc: Robert Love <rlove@rlove.org>
Cc: Eric Paris <eparis@parisplace.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
htejun authored and gregkh committed Apr 25, 2014
1 parent 7d568a8 commit d911d98
Showing 1 changed file with 35 additions and 6 deletions.
41 changes: 35 additions & 6 deletions fs/kernfs/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include <linux/poll.h>
#include <linux/pagemap.h>
#include <linux/sched.h>
#include <linux/fsnotify.h>

#include "kernfs-internal.h"

Expand Down Expand Up @@ -785,20 +786,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);

Expand Down

0 comments on commit d911d98

Please sign in to comment.