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 */ 65c28f7e56SEric Paris list_for_each_entry(alias, &inode->i_dentry, 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); 72c28f7e56SEric Paris list_for_each_entry(child, &alias->d_subdirs, d_u.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 125613a807fSEric Paris static int send_to_group(struct inode *to_tell, struct vfsmount *mnt, 126ce8f76fbSEric Paris struct fsnotify_mark *inode_mark, 127ce8f76fbSEric Paris struct fsnotify_mark *vfsmount_mark, 128613a807fSEric Paris __u32 mask, void *data, 129613a807fSEric Paris int data_is, u32 cookie, 1303a9b16b4SEric Paris const unsigned char *file_name, 1313a9fb89fSEric Paris struct fsnotify_event **event) 1327131485aSEric Paris { 133faa9560aSEric Paris struct fsnotify_group *group = NULL; 13484e1ab4dSEric Paris __u32 inode_test_mask = 0; 13584e1ab4dSEric Paris __u32 vfsmount_test_mask = 0; 136613a807fSEric Paris 137faa9560aSEric Paris if (unlikely(!inode_mark && !vfsmount_mark)) { 138faa9560aSEric Paris BUG(); 139faa9560aSEric Paris return 0; 140faa9560aSEric Paris } 1415ba08e2eSEric Paris 142ce8f76fbSEric Paris /* clear ignored on inode modification */ 143ce8f76fbSEric Paris if (mask & FS_MODIFY) { 144ce8f76fbSEric Paris if (inode_mark && 145ce8f76fbSEric Paris !(inode_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 146ce8f76fbSEric Paris inode_mark->ignored_mask = 0; 147ce8f76fbSEric Paris if (vfsmount_mark && 148ce8f76fbSEric Paris !(vfsmount_mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 149ce8f76fbSEric Paris vfsmount_mark->ignored_mask = 0; 150ce8f76fbSEric Paris } 151613a807fSEric Paris 152ce8f76fbSEric Paris /* does the inode mark tell us to do something? */ 153ce8f76fbSEric Paris if (inode_mark) { 154faa9560aSEric Paris group = inode_mark->group; 15584e1ab4dSEric Paris inode_test_mask = (mask & ~FS_EVENT_ON_CHILD); 156ce8f76fbSEric Paris inode_test_mask &= inode_mark->mask; 157ce8f76fbSEric Paris inode_test_mask &= ~inode_mark->ignored_mask; 158ce8f76fbSEric Paris } 159ce8f76fbSEric Paris 160ce8f76fbSEric Paris /* does the vfsmount_mark tell us to do something? */ 161ce8f76fbSEric Paris if (vfsmount_mark) { 16284e1ab4dSEric Paris vfsmount_test_mask = (mask & ~FS_EVENT_ON_CHILD); 163faa9560aSEric Paris group = vfsmount_mark->group; 164ce8f76fbSEric Paris vfsmount_test_mask &= vfsmount_mark->mask; 165ce8f76fbSEric Paris vfsmount_test_mask &= ~vfsmount_mark->ignored_mask; 166ce8f76fbSEric Paris if (inode_mark) 167ce8f76fbSEric Paris vfsmount_test_mask &= ~inode_mark->ignored_mask; 168ce8f76fbSEric Paris } 169ce8f76fbSEric Paris 17084e1ab4dSEric Paris pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x inode_mark=%p" 17184e1ab4dSEric Paris " inode_test_mask=%x vfsmount_mark=%p vfsmount_test_mask=%x" 17284e1ab4dSEric Paris " data=%p data_is=%d cookie=%d event=%p\n", 17384e1ab4dSEric Paris __func__, group, to_tell, mnt, mask, inode_mark, 17484e1ab4dSEric Paris inode_test_mask, vfsmount_mark, vfsmount_test_mask, data, 17584e1ab4dSEric Paris data_is, cookie, *event); 176faa9560aSEric Paris 177ce8f76fbSEric Paris if (!inode_test_mask && !vfsmount_test_mask) 178613a807fSEric Paris return 0; 179613a807fSEric Paris 1801968f5eeSEric Paris if (group->ops->should_send_event(group, to_tell, inode_mark, 181ce8f76fbSEric Paris vfsmount_mark, mask, data, 182ce8f76fbSEric Paris data_is) == false) 183c4ec54b4SEric Paris return 0; 184613a807fSEric Paris 1857131485aSEric Paris if (!*event) { 1867131485aSEric Paris *event = fsnotify_create_event(to_tell, mask, data, 1877131485aSEric Paris data_is, file_name, 1887131485aSEric Paris cookie, GFP_KERNEL); 1897131485aSEric Paris if (!*event) 190c4ec54b4SEric Paris return -ENOMEM; 1917131485aSEric Paris } 192ce8f76fbSEric Paris return group->ops->handle_event(group, inode_mark, vfsmount_mark, *event); 1937131485aSEric Paris } 1947131485aSEric Paris 195c28f7e56SEric Paris /* 19690586523SEric Paris * This is the main call to fsnotify. The VFS calls into hook specific functions 19790586523SEric Paris * in linux/fsnotify.h. Those functions then in turn call here. Here will call 19890586523SEric Paris * out to all of the registered fsnotify_group. Those groups can then use the 19990586523SEric Paris * notification event in whatever means they feel necessary. 20090586523SEric Paris */ 201c4ec54b4SEric Paris int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, 20259b0df21SEric Paris const unsigned char *file_name, u32 cookie) 20390586523SEric Paris { 20484e1ab4dSEric Paris struct hlist_node *inode_node = NULL, *vfsmount_node = NULL; 205613a807fSEric Paris struct fsnotify_mark *inode_mark = NULL, *vfsmount_mark = NULL; 206613a807fSEric Paris struct fsnotify_group *inode_group, *vfsmount_group; 20790586523SEric Paris struct fsnotify_event *event = NULL; 208613a807fSEric Paris struct vfsmount *mnt; 209c4ec54b4SEric Paris int idx, ret = 0; 210e42e2773SEric Paris /* global tests shouldn't care about events on child only the specific event */ 211e42e2773SEric Paris __u32 test_mask = (mask & ~FS_EVENT_ON_CHILD); 21290586523SEric Paris 2132069601bSLinus Torvalds if (data_is == FSNOTIFY_EVENT_PATH) 2142069601bSLinus Torvalds mnt = ((struct path *)data)->mnt; 215613a807fSEric Paris else 216613a807fSEric Paris mnt = NULL; 217613a807fSEric Paris 218613a807fSEric Paris /* 219613a807fSEric Paris * if this is a modify event we may need to clear the ignored masks 220613a807fSEric Paris * otherwise return if neither the inode nor the vfsmount care about 221613a807fSEric Paris * this type of event. 222613a807fSEric Paris */ 223613a807fSEric Paris if (!(mask & FS_MODIFY) && 224613a807fSEric Paris !(test_mask & to_tell->i_fsnotify_mask) && 225613a807fSEric Paris !(mnt && test_mask & mnt->mnt_fsnotify_mask)) 226613a807fSEric Paris return 0; 2273a9fb89fSEric Paris 22875c1be48SEric Paris idx = srcu_read_lock(&fsnotify_mark_srcu); 2297131485aSEric Paris 230613a807fSEric Paris if ((mask & FS_MODIFY) || 231613a807fSEric Paris (test_mask & to_tell->i_fsnotify_mask)) 232ce8f76fbSEric Paris inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, 233ce8f76fbSEric Paris &fsnotify_mark_srcu); 23475c1be48SEric Paris 23584e1ab4dSEric Paris if (mnt && ((mask & FS_MODIFY) || 23684e1ab4dSEric Paris (test_mask & mnt->mnt_fsnotify_mask))) { 237ce8f76fbSEric Paris vfsmount_node = srcu_dereference(mnt->mnt_fsnotify_marks.first, 238ce8f76fbSEric Paris &fsnotify_mark_srcu); 23984e1ab4dSEric Paris inode_node = srcu_dereference(to_tell->i_fsnotify_marks.first, 24084e1ab4dSEric Paris &fsnotify_mark_srcu); 2417131485aSEric Paris } 24275c1be48SEric Paris 243613a807fSEric Paris while (inode_node || vfsmount_node) { 244f72adfd5SEric Paris inode_group = vfsmount_group = NULL; 2455f3f259fSEric Paris 246613a807fSEric Paris if (inode_node) { 247613a807fSEric Paris inode_mark = hlist_entry(srcu_dereference(inode_node, &fsnotify_mark_srcu), 248613a807fSEric Paris struct fsnotify_mark, i.i_list); 249613a807fSEric Paris inode_group = inode_mark->group; 250f72adfd5SEric Paris } 25175c1be48SEric Paris 252613a807fSEric Paris if (vfsmount_node) { 253613a807fSEric Paris vfsmount_mark = hlist_entry(srcu_dereference(vfsmount_node, &fsnotify_mark_srcu), 254613a807fSEric Paris struct fsnotify_mark, m.m_list); 255613a807fSEric Paris vfsmount_group = vfsmount_mark->group; 256f72adfd5SEric Paris } 25775c1be48SEric Paris 258f72adfd5SEric Paris if (inode_group > vfsmount_group) { 259613a807fSEric Paris /* handle inode */ 260ff8bcbd0SEric Paris ret = send_to_group(to_tell, NULL, inode_mark, NULL, mask, data, 261613a807fSEric Paris data_is, cookie, file_name, &event); 26292b4678eSEric Paris /* we didn't use the vfsmount_mark */ 26392b4678eSEric Paris vfsmount_group = NULL; 264f72adfd5SEric Paris } else if (vfsmount_group > inode_group) { 265ff8bcbd0SEric Paris ret = send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data, 266613a807fSEric Paris data_is, cookie, file_name, &event); 26792b4678eSEric Paris inode_group = NULL; 268613a807fSEric Paris } else { 269ff8bcbd0SEric Paris ret = send_to_group(to_tell, mnt, inode_mark, vfsmount_mark, 270ce8f76fbSEric Paris mask, data, data_is, cookie, file_name, 271ce8f76fbSEric Paris &event); 272613a807fSEric Paris } 27384a5b68eSEric Paris 274ff8bcbd0SEric Paris if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) 275ff8bcbd0SEric Paris goto out; 276ff8bcbd0SEric Paris 27792b4678eSEric Paris if (inode_group) 278ce8f76fbSEric Paris inode_node = srcu_dereference(inode_node->next, 279ce8f76fbSEric Paris &fsnotify_mark_srcu); 28092b4678eSEric Paris if (vfsmount_group) 281ce8f76fbSEric Paris vfsmount_node = srcu_dereference(vfsmount_node->next, 282ce8f76fbSEric Paris &fsnotify_mark_srcu); 2837131485aSEric Paris } 284ff8bcbd0SEric Paris ret = 0; 285ff8bcbd0SEric Paris out: 28675c1be48SEric Paris srcu_read_unlock(&fsnotify_mark_srcu, idx); 28790586523SEric Paris /* 28890586523SEric Paris * fsnotify_create_event() took a reference so the event can't be cleaned 28990586523SEric Paris * up while we are still trying to add it to lists, drop that one. 29090586523SEric Paris */ 29190586523SEric Paris if (event) 29290586523SEric Paris fsnotify_put_event(event); 293c4ec54b4SEric Paris 29498b5c10dSJean-Christophe Dubois return ret; 29590586523SEric Paris } 29690586523SEric Paris EXPORT_SYMBOL_GPL(fsnotify); 29790586523SEric Paris 29890586523SEric Paris static __init int fsnotify_init(void) 29990586523SEric Paris { 30075c1be48SEric Paris int ret; 30175c1be48SEric Paris 30220dee624SEric Paris BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23); 30320dee624SEric Paris 30475c1be48SEric Paris ret = init_srcu_struct(&fsnotify_mark_srcu); 30575c1be48SEric Paris if (ret) 30675c1be48SEric Paris panic("initializing fsnotify_mark_srcu"); 30775c1be48SEric Paris 30875c1be48SEric Paris return 0; 30990586523SEric Paris } 31075c1be48SEric Paris core_initcall(fsnotify_init); 311