static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event) { struct fsnotify_mark_entry *entry; struct inotify_inode_mark_entry *ientry; struct inode *to_tell; struct inotify_event_private_data *event_priv; struct fsnotify_event_private_data *fsn_event_priv; int wd, ret; to_tell = event->to_tell; spin_lock(&to_tell->i_lock); entry = fsnotify_find_mark_entry(group, to_tell); spin_unlock(&to_tell->i_lock); /* race with watch removal? We already passes should_send */ if (unlikely(!entry)) return 0; ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry); wd = ientry->wd; event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL); if (unlikely(!event_priv)) return -ENOMEM; fsn_event_priv = &event_priv->fsnotify_event_priv_data; fsn_event_priv->group = group; event_priv->wd = wd; ret = fsnotify_add_notify_event(group, event, fsn_event_priv); if (ret) { inotify_free_event_priv(fsn_event_priv); /* EEXIST says we tail matched, EOVERFLOW isn't something * to report up the stack. */ if ((ret == -EEXIST) || (ret == -EOVERFLOW)) ret = 0; } if (entry->mask & IN_ONESHOT) fsnotify_destroy_mark_by_entry(entry); /* * If we hold the entry until after the event is on the queue * IN_IGNORED won't be able to pass this event in the queue */ fsnotify_put_mark(entry); return ret; }
static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask) { struct fsnotify_mark_entry *entry; bool send; spin_lock(&inode->i_lock); entry = fsnotify_find_mark_entry(group, inode); spin_unlock(&inode->i_lock); if (!entry) return false; mask = (mask & ~FS_EVENT_ON_CHILD); send = (entry->mask & mask); /* find took a reference */ fsnotify_put_mark(entry); return send; }