162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com> 462306a36Sopenharmony_ci */ 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci#include <linux/dcache.h> 762306a36Sopenharmony_ci#include <linux/fs.h> 862306a36Sopenharmony_ci#include <linux/gfp.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/mount.h> 1262306a36Sopenharmony_ci#include <linux/srcu.h> 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include <linux/fsnotify_backend.h> 1562306a36Sopenharmony_ci#include "fsnotify.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci/* 1862306a36Sopenharmony_ci * Clear all of the marks on an inode when it is being evicted from core 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_civoid __fsnotify_inode_delete(struct inode *inode) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci fsnotify_clear_marks_by_inode(inode); 2362306a36Sopenharmony_ci} 2462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__fsnotify_inode_delete); 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_civoid __fsnotify_vfsmount_delete(struct vfsmount *mnt) 2762306a36Sopenharmony_ci{ 2862306a36Sopenharmony_ci fsnotify_clear_marks_by_mount(mnt); 2962306a36Sopenharmony_ci} 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_ci/** 3262306a36Sopenharmony_ci * fsnotify_unmount_inodes - an sb is unmounting. handle any watched inodes. 3362306a36Sopenharmony_ci * @sb: superblock being unmounted. 3462306a36Sopenharmony_ci * 3562306a36Sopenharmony_ci * Called during unmount with no locks held, so needs to be safe against 3662306a36Sopenharmony_ci * concurrent modifiers. We temporarily drop sb->s_inode_list_lock and CAN block. 3762306a36Sopenharmony_ci */ 3862306a36Sopenharmony_cistatic void fsnotify_unmount_inodes(struct super_block *sb) 3962306a36Sopenharmony_ci{ 4062306a36Sopenharmony_ci struct inode *inode, *iput_inode = NULL; 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci spin_lock(&sb->s_inode_list_lock); 4362306a36Sopenharmony_ci list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { 4462306a36Sopenharmony_ci /* 4562306a36Sopenharmony_ci * We cannot __iget() an inode in state I_FREEING, 4662306a36Sopenharmony_ci * I_WILL_FREE, or I_NEW which is fine because by that point 4762306a36Sopenharmony_ci * the inode cannot have any associated watches. 4862306a36Sopenharmony_ci */ 4962306a36Sopenharmony_ci spin_lock(&inode->i_lock); 5062306a36Sopenharmony_ci if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW)) { 5162306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 5262306a36Sopenharmony_ci continue; 5362306a36Sopenharmony_ci } 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci /* 5662306a36Sopenharmony_ci * If i_count is zero, the inode cannot have any watches and 5762306a36Sopenharmony_ci * doing an __iget/iput with SB_ACTIVE clear would actually 5862306a36Sopenharmony_ci * evict all inodes with zero i_count from icache which is 5962306a36Sopenharmony_ci * unnecessarily violent and may in fact be illegal to do. 6062306a36Sopenharmony_ci * However, we should have been called /after/ evict_inodes 6162306a36Sopenharmony_ci * removed all zero refcount inodes, in any case. Test to 6262306a36Sopenharmony_ci * be sure. 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_ci if (!atomic_read(&inode->i_count)) { 6562306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 6662306a36Sopenharmony_ci continue; 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci __iget(inode); 7062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 7162306a36Sopenharmony_ci spin_unlock(&sb->s_inode_list_lock); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci iput(iput_inode); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci /* for each watch, send FS_UNMOUNT and then remove it */ 7662306a36Sopenharmony_ci fsnotify_inode(inode, FS_UNMOUNT); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci fsnotify_inode_delete(inode); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci iput_inode = inode; 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci cond_resched(); 8362306a36Sopenharmony_ci spin_lock(&sb->s_inode_list_lock); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci spin_unlock(&sb->s_inode_list_lock); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci iput(iput_inode); 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid fsnotify_sb_delete(struct super_block *sb) 9162306a36Sopenharmony_ci{ 9262306a36Sopenharmony_ci fsnotify_unmount_inodes(sb); 9362306a36Sopenharmony_ci fsnotify_clear_marks_by_sb(sb); 9462306a36Sopenharmony_ci /* Wait for outstanding object references from connectors */ 9562306a36Sopenharmony_ci wait_var_event(&sb->s_fsnotify_connectors, 9662306a36Sopenharmony_ci !atomic_long_read(&sb->s_fsnotify_connectors)); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci/* 10062306a36Sopenharmony_ci * Given an inode, first check if we care what happens to our children. Inotify 10162306a36Sopenharmony_ci * and dnotify both tell their parents about events. If we care about any event 10262306a36Sopenharmony_ci * on a child we run all of our children and set a dentry flag saying that the 10362306a36Sopenharmony_ci * parent cares. Thus when an event happens on a child it can quickly tell 10462306a36Sopenharmony_ci * if there is a need to find a parent and send the event to the parent. 10562306a36Sopenharmony_ci */ 10662306a36Sopenharmony_civoid __fsnotify_update_child_dentry_flags(struct inode *inode) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci struct dentry *alias; 10962306a36Sopenharmony_ci int watched; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!S_ISDIR(inode->i_mode)) 11262306a36Sopenharmony_ci return; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci /* determine if the children should tell inode about their events */ 11562306a36Sopenharmony_ci watched = fsnotify_inode_watches_children(inode); 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci spin_lock(&inode->i_lock); 11862306a36Sopenharmony_ci /* run all of the dentries associated with this inode. Since this is a 11962306a36Sopenharmony_ci * directory, there damn well better only be one item on this list */ 12062306a36Sopenharmony_ci hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { 12162306a36Sopenharmony_ci struct dentry *child; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci /* run all of the children of the original inode and fix their 12462306a36Sopenharmony_ci * d_flags to indicate parental interest (their parent is the 12562306a36Sopenharmony_ci * original inode) */ 12662306a36Sopenharmony_ci spin_lock(&alias->d_lock); 12762306a36Sopenharmony_ci list_for_each_entry(child, &alias->d_subdirs, d_child) { 12862306a36Sopenharmony_ci if (!child->d_inode) 12962306a36Sopenharmony_ci continue; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED); 13262306a36Sopenharmony_ci if (watched) 13362306a36Sopenharmony_ci child->d_flags |= DCACHE_FSNOTIFY_PARENT_WATCHED; 13462306a36Sopenharmony_ci else 13562306a36Sopenharmony_ci child->d_flags &= ~DCACHE_FSNOTIFY_PARENT_WATCHED; 13662306a36Sopenharmony_ci spin_unlock(&child->d_lock); 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci spin_unlock(&alias->d_lock); 13962306a36Sopenharmony_ci } 14062306a36Sopenharmony_ci spin_unlock(&inode->i_lock); 14162306a36Sopenharmony_ci} 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci/* Are inode/sb/mount interested in parent and name info with this event? */ 14462306a36Sopenharmony_cistatic bool fsnotify_event_needs_parent(struct inode *inode, struct mount *mnt, 14562306a36Sopenharmony_ci __u32 mask) 14662306a36Sopenharmony_ci{ 14762306a36Sopenharmony_ci __u32 marks_mask = 0; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci /* We only send parent/name to inode/sb/mount for events on non-dir */ 15062306a36Sopenharmony_ci if (mask & FS_ISDIR) 15162306a36Sopenharmony_ci return false; 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci /* 15462306a36Sopenharmony_ci * All events that are possible on child can also may be reported with 15562306a36Sopenharmony_ci * parent/name info to inode/sb/mount. Otherwise, a watching parent 15662306a36Sopenharmony_ci * could result in events reported with unexpected name info to sb/mount. 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ci BUILD_BUG_ON(FS_EVENTS_POSS_ON_CHILD & ~FS_EVENTS_POSS_TO_PARENT); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci /* Did either inode/sb/mount subscribe for events with parent/name? */ 16162306a36Sopenharmony_ci marks_mask |= fsnotify_parent_needed_mask(inode->i_fsnotify_mask); 16262306a36Sopenharmony_ci marks_mask |= fsnotify_parent_needed_mask(inode->i_sb->s_fsnotify_mask); 16362306a36Sopenharmony_ci if (mnt) 16462306a36Sopenharmony_ci marks_mask |= fsnotify_parent_needed_mask(mnt->mnt_fsnotify_mask); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* Did they subscribe for this event with parent/name info? */ 16762306a36Sopenharmony_ci return mask & marks_mask; 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci/* 17162306a36Sopenharmony_ci * Notify this dentry's parent about a child's events with child name info 17262306a36Sopenharmony_ci * if parent is watching or if inode/sb/mount are interested in events with 17362306a36Sopenharmony_ci * parent and name info. 17462306a36Sopenharmony_ci * 17562306a36Sopenharmony_ci * Notify only the child without name info if parent is not watching and 17662306a36Sopenharmony_ci * inode/sb/mount are not interested in events with parent and name info. 17762306a36Sopenharmony_ci */ 17862306a36Sopenharmony_ciint __fsnotify_parent(struct dentry *dentry, __u32 mask, const void *data, 17962306a36Sopenharmony_ci int data_type) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci const struct path *path = fsnotify_data_path(data, data_type); 18262306a36Sopenharmony_ci struct mount *mnt = path ? real_mount(path->mnt) : NULL; 18362306a36Sopenharmony_ci struct inode *inode = d_inode(dentry); 18462306a36Sopenharmony_ci struct dentry *parent; 18562306a36Sopenharmony_ci bool parent_watched = dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED; 18662306a36Sopenharmony_ci bool parent_needed, parent_interested; 18762306a36Sopenharmony_ci __u32 p_mask; 18862306a36Sopenharmony_ci struct inode *p_inode = NULL; 18962306a36Sopenharmony_ci struct name_snapshot name; 19062306a36Sopenharmony_ci struct qstr *file_name = NULL; 19162306a36Sopenharmony_ci int ret = 0; 19262306a36Sopenharmony_ci 19362306a36Sopenharmony_ci /* 19462306a36Sopenharmony_ci * Do inode/sb/mount care about parent and name info on non-dir? 19562306a36Sopenharmony_ci * Do they care about any event at all? 19662306a36Sopenharmony_ci */ 19762306a36Sopenharmony_ci if (!inode->i_fsnotify_marks && !inode->i_sb->s_fsnotify_marks && 19862306a36Sopenharmony_ci (!mnt || !mnt->mnt_fsnotify_marks) && !parent_watched) 19962306a36Sopenharmony_ci return 0; 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci parent = NULL; 20262306a36Sopenharmony_ci parent_needed = fsnotify_event_needs_parent(inode, mnt, mask); 20362306a36Sopenharmony_ci if (!parent_watched && !parent_needed) 20462306a36Sopenharmony_ci goto notify; 20562306a36Sopenharmony_ci 20662306a36Sopenharmony_ci /* Does parent inode care about events on children? */ 20762306a36Sopenharmony_ci parent = dget_parent(dentry); 20862306a36Sopenharmony_ci p_inode = parent->d_inode; 20962306a36Sopenharmony_ci p_mask = fsnotify_inode_watches_children(p_inode); 21062306a36Sopenharmony_ci if (unlikely(parent_watched && !p_mask)) 21162306a36Sopenharmony_ci __fsnotify_update_child_dentry_flags(p_inode); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci /* 21462306a36Sopenharmony_ci * Include parent/name in notification either if some notification 21562306a36Sopenharmony_ci * groups require parent info or the parent is interested in this event. 21662306a36Sopenharmony_ci */ 21762306a36Sopenharmony_ci parent_interested = mask & p_mask & ALL_FSNOTIFY_EVENTS; 21862306a36Sopenharmony_ci if (parent_needed || parent_interested) { 21962306a36Sopenharmony_ci /* When notifying parent, child should be passed as data */ 22062306a36Sopenharmony_ci WARN_ON_ONCE(inode != fsnotify_data_inode(data, data_type)); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* Notify both parent and child with child name info */ 22362306a36Sopenharmony_ci take_dentry_name_snapshot(&name, dentry); 22462306a36Sopenharmony_ci file_name = &name.name; 22562306a36Sopenharmony_ci if (parent_interested) 22662306a36Sopenharmony_ci mask |= FS_EVENT_ON_CHILD; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cinotify: 23062306a36Sopenharmony_ci ret = fsnotify(mask, data, data_type, p_inode, file_name, inode, 0); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (file_name) 23362306a36Sopenharmony_ci release_dentry_name_snapshot(&name); 23462306a36Sopenharmony_ci dput(parent); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci return ret; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__fsnotify_parent); 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_cistatic int fsnotify_handle_inode_event(struct fsnotify_group *group, 24162306a36Sopenharmony_ci struct fsnotify_mark *inode_mark, 24262306a36Sopenharmony_ci u32 mask, const void *data, int data_type, 24362306a36Sopenharmony_ci struct inode *dir, const struct qstr *name, 24462306a36Sopenharmony_ci u32 cookie) 24562306a36Sopenharmony_ci{ 24662306a36Sopenharmony_ci const struct path *path = fsnotify_data_path(data, data_type); 24762306a36Sopenharmony_ci struct inode *inode = fsnotify_data_inode(data, data_type); 24862306a36Sopenharmony_ci const struct fsnotify_ops *ops = group->ops; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci if (WARN_ON_ONCE(!ops->handle_inode_event)) 25162306a36Sopenharmony_ci return 0; 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci if (WARN_ON_ONCE(!inode && !dir)) 25462306a36Sopenharmony_ci return 0; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if ((inode_mark->flags & FSNOTIFY_MARK_FLAG_EXCL_UNLINK) && 25762306a36Sopenharmony_ci path && d_unlinked(path->dentry)) 25862306a36Sopenharmony_ci return 0; 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* Check interest of this mark in case event was sent with two marks */ 26162306a36Sopenharmony_ci if (!(mask & inode_mark->mask & ALL_FSNOTIFY_EVENTS)) 26262306a36Sopenharmony_ci return 0; 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return ops->handle_inode_event(inode_mark, mask, inode, dir, name, cookie); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic int fsnotify_handle_event(struct fsnotify_group *group, __u32 mask, 26862306a36Sopenharmony_ci const void *data, int data_type, 26962306a36Sopenharmony_ci struct inode *dir, const struct qstr *name, 27062306a36Sopenharmony_ci u32 cookie, struct fsnotify_iter_info *iter_info) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct fsnotify_mark *inode_mark = fsnotify_iter_inode_mark(iter_info); 27362306a36Sopenharmony_ci struct fsnotify_mark *parent_mark = fsnotify_iter_parent_mark(iter_info); 27462306a36Sopenharmony_ci int ret; 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (WARN_ON_ONCE(fsnotify_iter_sb_mark(iter_info)) || 27762306a36Sopenharmony_ci WARN_ON_ONCE(fsnotify_iter_vfsmount_mark(iter_info))) 27862306a36Sopenharmony_ci return 0; 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci /* 28162306a36Sopenharmony_ci * For FS_RENAME, 'dir' is old dir and 'data' is new dentry. 28262306a36Sopenharmony_ci * The only ->handle_inode_event() backend that supports FS_RENAME is 28362306a36Sopenharmony_ci * dnotify, where it means file was renamed within same parent. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci if (mask & FS_RENAME) { 28662306a36Sopenharmony_ci struct dentry *moved = fsnotify_data_dentry(data, data_type); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci if (dir != moved->d_parent->d_inode) 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci } 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (parent_mark) { 29362306a36Sopenharmony_ci ret = fsnotify_handle_inode_event(group, parent_mark, mask, 29462306a36Sopenharmony_ci data, data_type, dir, name, 0); 29562306a36Sopenharmony_ci if (ret) 29662306a36Sopenharmony_ci return ret; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!inode_mark) 30062306a36Sopenharmony_ci return 0; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci if (mask & FS_EVENT_ON_CHILD) { 30362306a36Sopenharmony_ci /* 30462306a36Sopenharmony_ci * Some events can be sent on both parent dir and child marks 30562306a36Sopenharmony_ci * (e.g. FS_ATTRIB). If both parent dir and child are 30662306a36Sopenharmony_ci * watching, report the event once to parent dir with name (if 30762306a36Sopenharmony_ci * interested) and once to child without name (if interested). 30862306a36Sopenharmony_ci * The child watcher is expecting an event without a file name 30962306a36Sopenharmony_ci * and without the FS_EVENT_ON_CHILD flag. 31062306a36Sopenharmony_ci */ 31162306a36Sopenharmony_ci mask &= ~FS_EVENT_ON_CHILD; 31262306a36Sopenharmony_ci dir = NULL; 31362306a36Sopenharmony_ci name = NULL; 31462306a36Sopenharmony_ci } 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci return fsnotify_handle_inode_event(group, inode_mark, mask, data, data_type, 31762306a36Sopenharmony_ci dir, name, cookie); 31862306a36Sopenharmony_ci} 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_cistatic int send_to_group(__u32 mask, const void *data, int data_type, 32162306a36Sopenharmony_ci struct inode *dir, const struct qstr *file_name, 32262306a36Sopenharmony_ci u32 cookie, struct fsnotify_iter_info *iter_info) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci struct fsnotify_group *group = NULL; 32562306a36Sopenharmony_ci __u32 test_mask = (mask & ALL_FSNOTIFY_EVENTS); 32662306a36Sopenharmony_ci __u32 marks_mask = 0; 32762306a36Sopenharmony_ci __u32 marks_ignore_mask = 0; 32862306a36Sopenharmony_ci bool is_dir = mask & FS_ISDIR; 32962306a36Sopenharmony_ci struct fsnotify_mark *mark; 33062306a36Sopenharmony_ci int type; 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci if (!iter_info->report_mask) 33362306a36Sopenharmony_ci return 0; 33462306a36Sopenharmony_ci 33562306a36Sopenharmony_ci /* clear ignored on inode modification */ 33662306a36Sopenharmony_ci if (mask & FS_MODIFY) { 33762306a36Sopenharmony_ci fsnotify_foreach_iter_mark_type(iter_info, mark, type) { 33862306a36Sopenharmony_ci if (!(mark->flags & 33962306a36Sopenharmony_ci FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)) 34062306a36Sopenharmony_ci mark->ignore_mask = 0; 34162306a36Sopenharmony_ci } 34262306a36Sopenharmony_ci } 34362306a36Sopenharmony_ci 34462306a36Sopenharmony_ci /* Are any of the group marks interested in this event? */ 34562306a36Sopenharmony_ci fsnotify_foreach_iter_mark_type(iter_info, mark, type) { 34662306a36Sopenharmony_ci group = mark->group; 34762306a36Sopenharmony_ci marks_mask |= mark->mask; 34862306a36Sopenharmony_ci marks_ignore_mask |= 34962306a36Sopenharmony_ci fsnotify_effective_ignore_mask(mark, is_dir, type); 35062306a36Sopenharmony_ci } 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci pr_debug("%s: group=%p mask=%x marks_mask=%x marks_ignore_mask=%x data=%p data_type=%d dir=%p cookie=%d\n", 35362306a36Sopenharmony_ci __func__, group, mask, marks_mask, marks_ignore_mask, 35462306a36Sopenharmony_ci data, data_type, dir, cookie); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci if (!(test_mask & marks_mask & ~marks_ignore_mask)) 35762306a36Sopenharmony_ci return 0; 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci if (group->ops->handle_event) { 36062306a36Sopenharmony_ci return group->ops->handle_event(group, mask, data, data_type, dir, 36162306a36Sopenharmony_ci file_name, cookie, iter_info); 36262306a36Sopenharmony_ci } 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci return fsnotify_handle_event(group, mask, data, data_type, dir, 36562306a36Sopenharmony_ci file_name, cookie, iter_info); 36662306a36Sopenharmony_ci} 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_cistatic struct fsnotify_mark *fsnotify_first_mark(struct fsnotify_mark_connector **connp) 36962306a36Sopenharmony_ci{ 37062306a36Sopenharmony_ci struct fsnotify_mark_connector *conn; 37162306a36Sopenharmony_ci struct hlist_node *node = NULL; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci conn = srcu_dereference(*connp, &fsnotify_mark_srcu); 37462306a36Sopenharmony_ci if (conn) 37562306a36Sopenharmony_ci node = srcu_dereference(conn->list.first, &fsnotify_mark_srcu); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return hlist_entry_safe(node, struct fsnotify_mark, obj_list); 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic struct fsnotify_mark *fsnotify_next_mark(struct fsnotify_mark *mark) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct hlist_node *node = NULL; 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (mark) 38562306a36Sopenharmony_ci node = srcu_dereference(mark->obj_list.next, 38662306a36Sopenharmony_ci &fsnotify_mark_srcu); 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_ci return hlist_entry_safe(node, struct fsnotify_mark, obj_list); 38962306a36Sopenharmony_ci} 39062306a36Sopenharmony_ci 39162306a36Sopenharmony_ci/* 39262306a36Sopenharmony_ci * iter_info is a multi head priority queue of marks. 39362306a36Sopenharmony_ci * Pick a subset of marks from queue heads, all with the same group 39462306a36Sopenharmony_ci * and set the report_mask to a subset of the selected marks. 39562306a36Sopenharmony_ci * Returns false if there are no more groups to iterate. 39662306a36Sopenharmony_ci */ 39762306a36Sopenharmony_cistatic bool fsnotify_iter_select_report_types( 39862306a36Sopenharmony_ci struct fsnotify_iter_info *iter_info) 39962306a36Sopenharmony_ci{ 40062306a36Sopenharmony_ci struct fsnotify_group *max_prio_group = NULL; 40162306a36Sopenharmony_ci struct fsnotify_mark *mark; 40262306a36Sopenharmony_ci int type; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Choose max prio group among groups of all queue heads */ 40562306a36Sopenharmony_ci fsnotify_foreach_iter_type(type) { 40662306a36Sopenharmony_ci mark = iter_info->marks[type]; 40762306a36Sopenharmony_ci if (mark && 40862306a36Sopenharmony_ci fsnotify_compare_groups(max_prio_group, mark->group) > 0) 40962306a36Sopenharmony_ci max_prio_group = mark->group; 41062306a36Sopenharmony_ci } 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci if (!max_prio_group) 41362306a36Sopenharmony_ci return false; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci /* Set the report mask for marks from same group as max prio group */ 41662306a36Sopenharmony_ci iter_info->current_group = max_prio_group; 41762306a36Sopenharmony_ci iter_info->report_mask = 0; 41862306a36Sopenharmony_ci fsnotify_foreach_iter_type(type) { 41962306a36Sopenharmony_ci mark = iter_info->marks[type]; 42062306a36Sopenharmony_ci if (mark && mark->group == iter_info->current_group) { 42162306a36Sopenharmony_ci /* 42262306a36Sopenharmony_ci * FSNOTIFY_ITER_TYPE_PARENT indicates that this inode 42362306a36Sopenharmony_ci * is watching children and interested in this event, 42462306a36Sopenharmony_ci * which is an event possible on child. 42562306a36Sopenharmony_ci * But is *this mark* watching children? 42662306a36Sopenharmony_ci */ 42762306a36Sopenharmony_ci if (type == FSNOTIFY_ITER_TYPE_PARENT && 42862306a36Sopenharmony_ci !(mark->mask & FS_EVENT_ON_CHILD) && 42962306a36Sopenharmony_ci !(fsnotify_ignore_mask(mark) & FS_EVENT_ON_CHILD)) 43062306a36Sopenharmony_ci continue; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci fsnotify_iter_set_report_type(iter_info, type); 43362306a36Sopenharmony_ci } 43462306a36Sopenharmony_ci } 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci return true; 43762306a36Sopenharmony_ci} 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci/* 44062306a36Sopenharmony_ci * Pop from iter_info multi head queue, the marks that belong to the group of 44162306a36Sopenharmony_ci * current iteration step. 44262306a36Sopenharmony_ci */ 44362306a36Sopenharmony_cistatic void fsnotify_iter_next(struct fsnotify_iter_info *iter_info) 44462306a36Sopenharmony_ci{ 44562306a36Sopenharmony_ci struct fsnotify_mark *mark; 44662306a36Sopenharmony_ci int type; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci /* 44962306a36Sopenharmony_ci * We cannot use fsnotify_foreach_iter_mark_type() here because we 45062306a36Sopenharmony_ci * may need to advance a mark of type X that belongs to current_group 45162306a36Sopenharmony_ci * but was not selected for reporting. 45262306a36Sopenharmony_ci */ 45362306a36Sopenharmony_ci fsnotify_foreach_iter_type(type) { 45462306a36Sopenharmony_ci mark = iter_info->marks[type]; 45562306a36Sopenharmony_ci if (mark && mark->group == iter_info->current_group) 45662306a36Sopenharmony_ci iter_info->marks[type] = 45762306a36Sopenharmony_ci fsnotify_next_mark(iter_info->marks[type]); 45862306a36Sopenharmony_ci } 45962306a36Sopenharmony_ci} 46062306a36Sopenharmony_ci 46162306a36Sopenharmony_ci/* 46262306a36Sopenharmony_ci * fsnotify - This is the main call to fsnotify. 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * The VFS calls into hook specific functions in linux/fsnotify.h. 46562306a36Sopenharmony_ci * Those functions then in turn call here. Here will call out to all of the 46662306a36Sopenharmony_ci * registered fsnotify_group. Those groups can then use the notification event 46762306a36Sopenharmony_ci * in whatever means they feel necessary. 46862306a36Sopenharmony_ci * 46962306a36Sopenharmony_ci * @mask: event type and flags 47062306a36Sopenharmony_ci * @data: object that event happened on 47162306a36Sopenharmony_ci * @data_type: type of object for fanotify_data_XXX() accessors 47262306a36Sopenharmony_ci * @dir: optional directory associated with event - 47362306a36Sopenharmony_ci * if @file_name is not NULL, this is the directory that 47462306a36Sopenharmony_ci * @file_name is relative to 47562306a36Sopenharmony_ci * @file_name: optional file name associated with event 47662306a36Sopenharmony_ci * @inode: optional inode associated with event - 47762306a36Sopenharmony_ci * If @dir and @inode are both non-NULL, event may be 47862306a36Sopenharmony_ci * reported to both. 47962306a36Sopenharmony_ci * @cookie: inotify rename cookie 48062306a36Sopenharmony_ci */ 48162306a36Sopenharmony_ciint fsnotify(__u32 mask, const void *data, int data_type, struct inode *dir, 48262306a36Sopenharmony_ci const struct qstr *file_name, struct inode *inode, u32 cookie) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci const struct path *path = fsnotify_data_path(data, data_type); 48562306a36Sopenharmony_ci struct super_block *sb = fsnotify_data_sb(data, data_type); 48662306a36Sopenharmony_ci struct fsnotify_iter_info iter_info = {}; 48762306a36Sopenharmony_ci struct mount *mnt = NULL; 48862306a36Sopenharmony_ci struct inode *inode2 = NULL; 48962306a36Sopenharmony_ci struct dentry *moved; 49062306a36Sopenharmony_ci int inode2_type; 49162306a36Sopenharmony_ci int ret = 0; 49262306a36Sopenharmony_ci __u32 test_mask, marks_mask; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci if (path) 49562306a36Sopenharmony_ci mnt = real_mount(path->mnt); 49662306a36Sopenharmony_ci 49762306a36Sopenharmony_ci if (!inode) { 49862306a36Sopenharmony_ci /* Dirent event - report on TYPE_INODE to dir */ 49962306a36Sopenharmony_ci inode = dir; 50062306a36Sopenharmony_ci /* For FS_RENAME, inode is old_dir and inode2 is new_dir */ 50162306a36Sopenharmony_ci if (mask & FS_RENAME) { 50262306a36Sopenharmony_ci moved = fsnotify_data_dentry(data, data_type); 50362306a36Sopenharmony_ci inode2 = moved->d_parent->d_inode; 50462306a36Sopenharmony_ci inode2_type = FSNOTIFY_ITER_TYPE_INODE2; 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci } else if (mask & FS_EVENT_ON_CHILD) { 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * Event on child - report on TYPE_PARENT to dir if it is 50962306a36Sopenharmony_ci * watching children and on TYPE_INODE to child. 51062306a36Sopenharmony_ci */ 51162306a36Sopenharmony_ci inode2 = dir; 51262306a36Sopenharmony_ci inode2_type = FSNOTIFY_ITER_TYPE_PARENT; 51362306a36Sopenharmony_ci } 51462306a36Sopenharmony_ci 51562306a36Sopenharmony_ci /* 51662306a36Sopenharmony_ci * Optimization: srcu_read_lock() has a memory barrier which can 51762306a36Sopenharmony_ci * be expensive. It protects walking the *_fsnotify_marks lists. 51862306a36Sopenharmony_ci * However, if we do not walk the lists, we do not have to do 51962306a36Sopenharmony_ci * SRCU because we have no references to any objects and do not 52062306a36Sopenharmony_ci * need SRCU to keep them "alive". 52162306a36Sopenharmony_ci */ 52262306a36Sopenharmony_ci if (!sb->s_fsnotify_marks && 52362306a36Sopenharmony_ci (!mnt || !mnt->mnt_fsnotify_marks) && 52462306a36Sopenharmony_ci (!inode || !inode->i_fsnotify_marks) && 52562306a36Sopenharmony_ci (!inode2 || !inode2->i_fsnotify_marks)) 52662306a36Sopenharmony_ci return 0; 52762306a36Sopenharmony_ci 52862306a36Sopenharmony_ci marks_mask = sb->s_fsnotify_mask; 52962306a36Sopenharmony_ci if (mnt) 53062306a36Sopenharmony_ci marks_mask |= mnt->mnt_fsnotify_mask; 53162306a36Sopenharmony_ci if (inode) 53262306a36Sopenharmony_ci marks_mask |= inode->i_fsnotify_mask; 53362306a36Sopenharmony_ci if (inode2) 53462306a36Sopenharmony_ci marks_mask |= inode2->i_fsnotify_mask; 53562306a36Sopenharmony_ci 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* 53862306a36Sopenharmony_ci * If this is a modify event we may need to clear some ignore masks. 53962306a36Sopenharmony_ci * In that case, the object with ignore masks will have the FS_MODIFY 54062306a36Sopenharmony_ci * event in its mask. 54162306a36Sopenharmony_ci * Otherwise, return if none of the marks care about this type of event. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_ci test_mask = (mask & ALL_FSNOTIFY_EVENTS); 54462306a36Sopenharmony_ci if (!(test_mask & marks_mask)) 54562306a36Sopenharmony_ci return 0; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci iter_info.srcu_idx = srcu_read_lock(&fsnotify_mark_srcu); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci iter_info.marks[FSNOTIFY_ITER_TYPE_SB] = 55062306a36Sopenharmony_ci fsnotify_first_mark(&sb->s_fsnotify_marks); 55162306a36Sopenharmony_ci if (mnt) { 55262306a36Sopenharmony_ci iter_info.marks[FSNOTIFY_ITER_TYPE_VFSMOUNT] = 55362306a36Sopenharmony_ci fsnotify_first_mark(&mnt->mnt_fsnotify_marks); 55462306a36Sopenharmony_ci } 55562306a36Sopenharmony_ci if (inode) { 55662306a36Sopenharmony_ci iter_info.marks[FSNOTIFY_ITER_TYPE_INODE] = 55762306a36Sopenharmony_ci fsnotify_first_mark(&inode->i_fsnotify_marks); 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci if (inode2) { 56062306a36Sopenharmony_ci iter_info.marks[inode2_type] = 56162306a36Sopenharmony_ci fsnotify_first_mark(&inode2->i_fsnotify_marks); 56262306a36Sopenharmony_ci } 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_ci /* 56562306a36Sopenharmony_ci * We need to merge inode/vfsmount/sb mark lists so that e.g. inode mark 56662306a36Sopenharmony_ci * ignore masks are properly reflected for mount/sb mark notifications. 56762306a36Sopenharmony_ci * That's why this traversal is so complicated... 56862306a36Sopenharmony_ci */ 56962306a36Sopenharmony_ci while (fsnotify_iter_select_report_types(&iter_info)) { 57062306a36Sopenharmony_ci ret = send_to_group(mask, data, data_type, dir, file_name, 57162306a36Sopenharmony_ci cookie, &iter_info); 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS)) 57462306a36Sopenharmony_ci goto out; 57562306a36Sopenharmony_ci 57662306a36Sopenharmony_ci fsnotify_iter_next(&iter_info); 57762306a36Sopenharmony_ci } 57862306a36Sopenharmony_ci ret = 0; 57962306a36Sopenharmony_ciout: 58062306a36Sopenharmony_ci srcu_read_unlock(&fsnotify_mark_srcu, iter_info.srcu_idx); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci return ret; 58362306a36Sopenharmony_ci} 58462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(fsnotify); 58562306a36Sopenharmony_ci 58662306a36Sopenharmony_cistatic __init int fsnotify_init(void) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci int ret; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ci BUILD_BUG_ON(HWEIGHT32(ALL_FSNOTIFY_BITS) != 23); 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci ret = init_srcu_struct(&fsnotify_mark_srcu); 59362306a36Sopenharmony_ci if (ret) 59462306a36Sopenharmony_ci panic("initializing fsnotify_mark_srcu"); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci fsnotify_mark_connector_cachep = KMEM_CACHE(fsnotify_mark_connector, 59762306a36Sopenharmony_ci SLAB_PANIC); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci return 0; 60062306a36Sopenharmony_ci} 60162306a36Sopenharmony_cicore_initcall(fsnotify_init); 602