kernfs: make kernfs_notify() trigger inotify events too
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>
This commit is contained in:
		
					parent
					
						
							
								7d568a8383
							
						
					
				
			
			
				commit
				
					
						d911d98748
					
				
			
		
					 1 changed files with 35 additions and 6 deletions
				
			
		|  | @ -14,6 +14,7 @@ | |||
| #include <linux/poll.h> | ||||
| #include <linux/pagemap.h> | ||||
| #include <linux/sched.h> | ||||
| #include <linux/fsnotify.h> | ||||
| 
 | ||||
| #include "kernfs-internal.h" | ||||
| 
 | ||||
|  | @ -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); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Tejun Heo
				Tejun Heo