xref: /openbmc/linux/fs/notify/fsnotify.c (revision e637835e)
190586523SEric Paris /*
290586523SEric Paris  *  Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
390586523SEric Paris  *
490586523SEric Paris  *  This program is free software; you can redistribute it and/or modify
590586523SEric Paris  *  it under the terms of the GNU General Public License as published by
690586523SEric Paris  *  the Free Software Foundation; either version 2, or (at your option)
790586523SEric Paris  *  any later version.
890586523SEric Paris  *
990586523SEric Paris  *  This program is distributed in the hope that it will be useful,
1090586523SEric Paris  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
1190586523SEric Paris  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1290586523SEric Paris  *  GNU General Public License for more details.
1390586523SEric Paris  *
1490586523SEric Paris  *  You should have received a copy of the GNU General Public License
1590586523SEric Paris  *  along with this program; see the file COPYING.  If not, write to
1690586523SEric Paris  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
1790586523SEric Paris  */
1890586523SEric Paris 
1990586523SEric Paris #include <linux/dcache.h>
2090586523SEric Paris #include <linux/fs.h>
215a0e3ad6STejun Heo #include <linux/gfp.h>
2290586523SEric Paris #include <linux/init.h>
2390586523SEric Paris #include <linux/module.h>
247131485aSEric Paris #include <linux/mount.h>
2590586523SEric Paris #include <linux/srcu.h>
2690586523SEric Paris 
2790586523SEric Paris #include <linux/fsnotify_backend.h>
2890586523SEric Paris #include "fsnotify.h"
2990586523SEric Paris 
3090586523SEric Paris /*
313be25f49SEric Paris  * Clear all of the marks on an inode when it is being evicted from core
323be25f49SEric Paris  */
333be25f49SEric Paris void __fsnotify_inode_delete(struct inode *inode)
343be25f49SEric Paris {
353be25f49SEric Paris 	fsnotify_clear_marks_by_inode(inode);
363be25f49SEric Paris }
373be25f49SEric Paris EXPORT_SYMBOL_GPL(__fsnotify_inode_delete);
383be25f49SEric Paris 
39ca9c726eSAndreas Gruenbacher void __fsnotify_vfsmount_delete(struct vfsmount *mnt)
40ca9c726eSAndreas Gruenbacher {
41ca9c726eSAndreas Gruenbacher 	fsnotify_clear_marks_by_mount(mnt);
42ca9c726eSAndreas Gruenbacher }
43ca9c726eSAndreas Gruenbacher 
443be25f49SEric Paris /*
45c28f7e56SEric Paris  * Given an inode, first check if we care what happens to our children.  Inotify
46c28f7e56SEric Paris  * and dnotify both tell their parents about events.  If we care about any event
47c28f7e56SEric Paris  * on a child we run all of our children and set a dentry flag saying that the
48c28f7e56SEric Paris  * parent cares.  Thus when an event happens on a child it can quickly tell if
49c28f7e56SEric Paris  * if there is a need to find a parent and send the event to the parent.
50c28f7e56SEric Paris  */
51c28f7e56SEric Paris void __fsnotify_update_child_dentry_flags(struct inode *inode)
52c28f7e56SEric Paris {
53c28f7e56SEric Paris 	struct dentry *alias;
54c28f7e56SEric Paris 	int watched;
55c28f7e56SEric Paris 
56c28f7e56SEric Paris 	if (!S_ISDIR(inode->i_mode))
57c28f7e56SEric Paris 		return;
58c28f7e56SEric Paris 
59c28f7e56SEric Paris 	/* determine if the children should tell inode about their events */
60c28f7e56SEric Paris 	watched = fsnotify_inode_watches_children(inode);
61c28f7e56SEric Paris 
62873feea0SNick Piggin 	spin_lock(&inode->i_lock);
63c28f7e56SEric Paris 	/* run all of the dentries associated with this inode.  Since this is a
64c28f7e56SEric Paris 	 * directory, there damn well better only be one item on this list */
65946e51f2SAl Viro 	hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
66c28f7e56SEric Paris 		struct dentry *child;
67c28f7e56SEric Paris 
68c28f7e56SEric Paris 		/* run all of the children of the original inode and fix their
69c28f7e56SEric Paris 		 * d_flags to indicate parental interest (their parent is the
70c28f7e56SEric Paris 		 * original inode) */
712fd6b7f5SNick Piggin 		spin_lock(&alias->d_lock);
72946e51f2SAl Viro 		list_for_each_entry(child, &alias->d_subdirs, d_child) {
73c28f7e56SEric Paris 			if (!child->d_inode)
74c28f7e56SEric Paris 				continue;
75c28f7e56SEric Paris 
762fd6b7f5SNick Piggin 			spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
77c28f7e56SEric Paris 			if (watched)
78c28f7e56SEric Paris 				child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED;
79c28f7e56SEric Paris 			else
80c28f7e56SEric Paris 				child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED;
81c28f7e56SEric Paris 			spin_unlock(&child->d_lock);
82c28f7e56SEric Paris 		}
832fd6b7f5SNick Piggin 		spin_unlock(&alias->d_lock);
84c28f7e56SEric Paris 	}
85873feea0SNick Piggin 	spin_unlock(&inode->i_lock);
86c28f7e56SEric Paris }
87c28f7e56SEric Paris 
88c28f7e56SEric Paris /* Notify this dentry's parent about a child's events. */
8952420392SEric Paris int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
90c28f7e56SEric Paris {
91c28f7e56SEric Paris 	struct dentry *parent;
92c28f7e56SEric Paris 	struct inode *p_inode;
9352420392SEric Paris 	int ret = 0;
94c28f7e56SEric Paris 
9572acc854SAndreas Gruenbacher 	if (!dentry)
962069601bSLinus Torvalds 		dentry = path->dentry;
9728c60e37SEric Paris 
98c28f7e56SEric Paris 	if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
9952420392SEric Paris 		return 0;
100c28f7e56SEric Paris 
1014d4eb366SChristoph Hellwig 	parent = dget_parent(dentry);
102c28f7e56SEric Paris 	p_inode = parent->d_inode;
103c28f7e56SEric Paris 
1044d4eb366SChristoph Hellwig 	if (unlikely(!fsnotify_inode_watches_children(p_inode)))
1054d4eb366SChristoph Hellwig 		__fsnotify_update_child_dentry_flags(p_inode);
1064d4eb366SChristoph Hellwig 	else if (p_inode->i_fsnotify_mask & mask) {
107c28f7e56SEric Paris 		/* we are notifying a parent so come up with the new mask which
108c28f7e56SEric Paris 		 * specifies these are events which came from a child. */
109c28f7e56SEric Paris 		mask |= FS_EVENT_ON_CHILD;
110c28f7e56SEric Paris 
1112069601bSLinus Torvalds 		if (path)
11252420392SEric Paris 			ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
11328c60e37SEric Paris 				       dentry->d_name.name, 0);
11428c60e37SEric Paris 		else
11552420392SEric Paris 			ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
11647882c6fSEric Paris 				       dentry->d_name.name, 0);
117c28f7e56SEric Paris 	}
118c28f7e56SEric Paris 
119c28f7e56SEric Paris 	dput(parent);
12052420392SEric Paris 
12152420392SEric Paris 	return ret;
122c28f7e56SEric Paris }
123c28f7e56SEric Paris EXPORT_SYMBOL_GPL(__fsnotify_parent);
124c28f7e56SEric Paris 
125fd657170SDan Carpenter static int send_to_group(struct inode *to_tell,
126ce8f76fbSEric Paris 			 struct fsnotify_mark *inode_mark,
127ce8f76fbSEric Paris 			 struct fsnotify_mark *vfsmount_mark,
128e637835eSAl Viro 			 __u32 mask, const void *data,
129613a807fSEric Paris 			 int data_is, u32 cookie,
1307053aee2SJan Kara 			 const unsigned char *file_name)
1317131485aSEric Paris {
132faa9560aSEric Paris 	struct fsnotify_group *group = NULL;
13384e1ab4dSEric Paris 	__u32 inode_test_mask = 0;
13484e1ab4dSEric Paris 	__u32 vfsmount_test_mask = 0;
135613a807fSEric Paris 
136faa9560aSEric Paris 	if (unlikely(!inode_mark && !vfsmount_mark)) {
137faa9560aSEric Paris 		BUG();
138faa9560aSEric Paris 		return 0;
139faa9560aSEric Paris 	}
1405ba08e2eSEric Paris 
141ce8f76fbSEric Paris 	/* clear ignored on inode modification */
142ce8f76fbSEric Paris 	if (mask & FS_MODIFY) {
143ce8f76fbSEric Paris 		if (inode_mark &&
144ce8f76fbSEric Paris 		    !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
145ce8f76fbSEric Paris 			inode_mark->ignored_mask = 0;
146ce8f76fbSEric Paris 		if (vfsmount_mark &&
147ce8f76fbSEric Paris 		    !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY))
148ce8f76fbSEric Paris 			vfsmount_mark->ignored_mask = 0;
149ce8f76fbSEric Paris 	}
150613a807fSEric Paris 
151ce8f76fbSEric Paris 	/* does the inode mark tell us to do something? */
152ce8f76fbSEric Paris 	if (inode_mark) {
153faa9560aSEric Paris 		group = inode_mark->group;
15484e1ab4dSEric Paris 		inode_test_mask = (mask & ~FS_EVENT_ON_CHILD);
155ce8f76fbSEric Paris 		inode_test_mask &= inode_mark->mask;
156ce8f76fbSEric Paris 		inode_test_mask &= ~inode_mark->ignored_mask;
157ce8f76fbSEric Paris 	}
158ce8f76fbSEric Paris 
159ce8f76fbSEric Paris 	/* does the vfsmount_mark tell us to do something? */
160ce8f76fbSEric Paris 	if (vfsmount_mark) {
16184e1ab4dSEric Paris 		vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD);
162faa9560aSEric Paris 		group = vfsmount_mark->group;
163ce8f76fbSEric Paris 		vfsmount_test_mask &= vfsmount_mark->mask;
164ce8f76fbSEric Paris 		vfsmount_test_mask &= ~vfsmount_mark->ignored_mask;
165ce8f76fbSEric Paris 		if (inode_mark)
166ce8f76fbSEric Paris 			vfsmount_test_mask &= ~inode_mark->ignored_mask;
167ce8f76fbSEric Paris 	}
168ce8f76fbSEric Paris 
169fd657170SDan Carpenter 	pr_debug("%s: group=%p to_tell=%p mask=%x inode_mark=%p"
17084e1ab4dSEric Paris 		 " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x"
1717053aee2SJan Kara 		 " data=%p data_is=%d cookie=%d\n",
172fd657170SDan Carpenter 		 __func__, group, to_tell, mask, inode_mark,
17384e1ab4dSEric Paris 		 inode_test_mask, vfsmount_mark, vfsmount_test_mask, data,
1747053aee2SJan Kara 		 data_is, cookie);
175faa9560aSEric Paris 
176ce8f76fbSEric Paris 	if (!inode_test_mask && !vfsmount_test_mask)
177613a807fSEric Paris 		return 0;
178613a807fSEric Paris 
1797053aee2SJan Kara 	return group->ops->handle_event(group, to_tell, inode_mark,
1807053aee2SJan Kara 					vfsmount_mark, mask, data, data_is,
18145a22f4cSJan Kara 					file_name, cookie);
1827131485aSEric Paris }
1837131485aSEric Paris 
184c28f7e56SEric Paris /*
18590586523SEric Paris  * This is the main call to fsnotify.  The VFS calls into hook specific functions
18690586523SEric Paris  * in linux/fsnotify.h.  Those functions then in turn call here.  Here will call
18790586523SEric Paris  * out to all of the registered fsnotify_group.  Those groups can then use the
18890586523SEric Paris  * notification event in whatever means they feel necessary.
18990586523SEric Paris  */
190e637835eSAl Viro int fsnotify(struct inode *to_tell, __u32 mask, const void *data, int data_is,
19159b0df21SEric Paris 	     const unsigned char *file_name, u32 cookie)
19290586523SEric Paris {
19384e1ab4dSEric Paris 	struct hlist_node *inode_node = NULL, *vfsmount_node = NULL;
194613a807fSEric Paris 	struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL;
195613a807fSEric Paris 	struct fsnotify_group *inode_group, *vfsmount_group;
196c63181e6SAl Viro 	struct mount *mnt;
197c4ec54b4SEric Paris 	int idx, ret = 0;
198e42e2773SEric Paris 	/* global tests shouldn't care about events on child only the specific event */
199e42e2773SEric Paris 	__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
20090586523SEric Paris 
2012069601bSLinus Torvalds 	if (data_is == FSNOTIFY_EVENT_PATH)
202e637835eSAl Viro 		mnt = real_mount(((const struct path *)data)->mnt);
203613a807fSEric Paris 	else
204613a807fSEric Paris 		mnt = NULL;
205613a807fSEric Paris 
206613a807fSEric Paris 	/*
2077c49b861SDave Hansen 	 * Optimization: srcu_read_lock() has a memory barrier which can
2087c49b861SDave Hansen 	 * be expensive.  It protects walking the *_fsnotify_marks lists.
2097c49b861SDave Hansen 	 * However, if we do not walk the lists, we do not have to do
2107c49b861SDave Hansen 	 * SRCU because we have no references to any objects and do not
2117c49b861SDave Hansen 	 * need SRCU to keep them "alive".
2127c49b861SDave Hansen 	 */
2137c49b861SDave Hansen 	if (hlist_empty(&to_tell->i_fsnotify_marks) &&
2147c49b861SDave Hansen 	    (!mnt || hlist_empty(&mnt->mnt_fsnotify_marks)))
2157c49b861SDave Hansen 		return 0;
2167c49b861SDave Hansen 	/*
217613a807fSEric Paris 	 * if this is a modify event we may need to clear the ignored masks
218613a807fSEric Paris 	 * otherwise return if neither the inode nor the vfsmount care about
219613a807fSEric Paris 	 * this type of event.
220613a807fSEric Paris 	 */
221613a807fSEric Paris 	if (!(mask & FS_MODIFY) &&
222613a807fSEric Paris 	    !(test_mask & to_tell->i_fsnotify_mask) &&
223613a807fSEric Paris 	    !(mnt && test_mask & mnt->mnt_fsnotify_mask))
224613a807fSEric Paris 		return 0;
2253a9fb89fSEric Paris 
22675c1be48SEric Paris 	idx = srcu_read_lock(&fsnotify_mark_srcu);
2277131485aSEric Paris 
228613a807fSEric Paris 	if ((mask & FS_MODIFY) ||
229613a807fSEric Paris 	    (test_mask & to_tell->i_fsnotify_mask))
230ce8f76fbSEric Paris 		inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
231ce8f76fbSEric Paris 					      &fsnotify_mark_srcu);
23275c1be48SEric Paris 
23384e1ab4dSEric Paris 	if (mnt && ((mask & FS_MODIFY) ||
23484e1ab4dSEric Paris 		    (test_mask & mnt->mnt_fsnotify_mask))) {
235ce8f76fbSEric Paris 		vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first,
236ce8f76fbSEric Paris 						 &fsnotify_mark_srcu);
23784e1ab4dSEric Paris 		inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first,
23884e1ab4dSEric Paris 					      &fsnotify_mark_srcu);
2397131485aSEric Paris 	}
24075c1be48SEric Paris 
2418edc6e16SJan Kara 	/*
2428edc6e16SJan Kara 	 * We need to merge inode & vfsmount mark lists so that inode mark
2438edc6e16SJan Kara 	 * ignore masks are properly reflected for mount mark notifications.
2448edc6e16SJan Kara 	 * That's why this traversal is so complicated...
2458edc6e16SJan Kara 	 */
246613a807fSEric Paris 	while (inode_node || vfsmount_node) {
2478edc6e16SJan Kara 		inode_group = NULL;
2488edc6e16SJan Kara 		inode_mark = NULL;
2498edc6e16SJan Kara 		vfsmount_group = NULL;
2508edc6e16SJan Kara 		vfsmount_mark = NULL;
2515f3f259fSEric Paris 
252613a807fSEric Paris 		if (inode_node) {
253613a807fSEric Paris 			inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu),
2540809ab69SJan Kara 						 struct fsnotify_mark, obj_list);
255613a807fSEric Paris 			inode_group = inode_mark->group;
256f72adfd5SEric Paris 		}
25775c1be48SEric Paris 
258613a807fSEric Paris 		if (vfsmount_node) {
259613a807fSEric Paris 			vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu),
2600809ab69SJan Kara 						    struct fsnotify_mark, obj_list);
261613a807fSEric Paris 			vfsmount_group = vfsmount_mark->group;
262f72adfd5SEric Paris 		}
26375c1be48SEric Paris 
2648edc6e16SJan Kara 		if (inode_group && vfsmount_group) {
2658edc6e16SJan Kara 			int cmp = fsnotify_compare_groups(inode_group,
2668edc6e16SJan Kara 							  vfsmount_group);
2678edc6e16SJan Kara 			if (cmp > 0) {
26892b4678eSEric Paris 				inode_group = NULL;
2698edc6e16SJan Kara 				inode_mark = NULL;
2708edc6e16SJan Kara 			} else if (cmp < 0) {
2718edc6e16SJan Kara 				vfsmount_group = NULL;
2728edc6e16SJan Kara 				vfsmount_mark = NULL;
273613a807fSEric Paris 			}
2748edc6e16SJan Kara 		}
2758edc6e16SJan Kara 		ret = send_to_group(to_tell, inode_mark, vfsmount_mark, mask,
2768edc6e16SJan Kara 				    data, data_is, cookie, file_name);
27784a5b68eSEric Paris 
278ff8bcbd0SEric Paris 		if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
279ff8bcbd0SEric Paris 			goto out;
280ff8bcbd0SEric Paris 
28192b4678eSEric Paris 		if (inode_group)
282ce8f76fbSEric Paris 			inode_node = srcu_dereference(inode_node->next,
283ce8f76fbSEric Paris 						      &fsnotify_mark_srcu);
28492b4678eSEric Paris 		if (vfsmount_group)
285ce8f76fbSEric Paris 			vfsmount_node = srcu_dereference(vfsmount_node->next,
286ce8f76fbSEric Paris 							 &fsnotify_mark_srcu);
2877131485aSEric Paris 	}
288ff8bcbd0SEric Paris 	ret = 0;
289ff8bcbd0SEric Paris out:
29075c1be48SEric Paris 	srcu_read_unlock(&fsnotify_mark_srcu, idx);
291c4ec54b4SEric Paris 
29298b5c10dSJean-Christophe Dubois 	return ret;
29390586523SEric Paris }
29490586523SEric Paris EXPORT_SYMBOL_GPL(fsnotify);
29590586523SEric Paris 
29690586523SEric Paris static __init int fsnotify_init(void)
29790586523SEric Paris {
29875c1be48SEric Paris 	int ret;
29975c1be48SEric Paris 
30020dee624SEric Paris 	BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23);
30120dee624SEric Paris 
30275c1be48SEric Paris 	ret = init_srcu_struct(&fsnotify_mark_srcu);
30375c1be48SEric Paris 	if (ret)
30475c1be48SEric Paris 		panic("initializing fsnotify_mark_srcu");
30575c1be48SEric Paris 
30675c1be48SEric Paris 	return 0;
30790586523SEric Paris }
30875c1be48SEric Paris core_initcall(fsnotify_init);
309