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