}
/* Notify this dentry's parent about a child's events. */
-void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
+void __fsnotify_parent(struct file *file, struct dentry *dentry, __u32 mask)
{
struct dentry *parent;
struct inode *p_inode;
bool should_update_children = false;
if (!dentry)
- dentry = path->dentry;
+ dentry = file->f_path.dentry;
if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
return;
* specifies these are events which came from a child. */
mask |= FS_EVENT_ON_CHILD;
- if (path)
- fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
+ if (file)
+ fsnotify(p_inode, mask, file, FSNOTIFY_EVENT_FILE,
dentry->d_name.name, 0);
else
fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
spin_unlock(&inode->i_lock);
}
- if (data_is == FSNOTIFY_EVENT_PATH) {
+ if (data_is == FSNOTIFY_EVENT_FILE) {
struct vfsmount *mnt;
- mnt = ((struct path *)data)->mnt;
+ mnt = ((struct file *)data)->f_path.mnt;
if (mnt && !hlist_empty(&mnt->mnt_fsnotify_marks)) {
spin_lock(&mnt->mnt_root->d_lock);
hlist_for_each_entry(mark, node, &mnt->mnt_fsnotify_marks, m.m_list) {
}
}
-static void send_to_group(struct fsnotify_group *group, struct inode *to_tell,
- struct vfsmount *mnt, __u32 mask, void *data,
- int data_is, u32 cookie, const char *file_name,
- struct fsnotify_event **event)
+static int send_to_group(struct fsnotify_group *group, struct inode *to_tell,
+ struct vfsmount *mnt, __u32 mask, void *data,
+ int data_is, u32 cookie, const unsigned char *file_name,
+ struct fsnotify_event **event)
{
+ pr_debug("%s: group=%p to_tell=%p mnt=%p mask=%x data=%p data_is=%d"
+ " cookie=%d event=%p\n", __func__, group, to_tell, mnt,
+ mask, data, data_is, cookie, *event);
+
if (!group->ops->should_send_event(group, to_tell, mnt, mask,
data, data_is))
- return;
+ return 0;
if (!*event) {
*event = fsnotify_create_event(to_tell, mask, data,
data_is, file_name,
cookie, GFP_KERNEL);
- /*
- * shit, we OOM'd and now we can't tell, maybe
- * someday someone else will want to do something
- * here
- */
if (!*event)
- return;
+ return -ENOMEM;
}
- group->ops->handle_event(group, *event);
+ return group->ops->handle_event(group, *event);
}
static bool needed_by_vfsmount(__u32 test_mask, struct vfsmount *mnt)
* out to all of the registered fsnotify_group. Those groups can then use the
* notification event in whatever means they feel necessary.
*/
-void fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is, const char *file_name, u32 cookie)
+int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
+ const unsigned char *file_name, u32 cookie)
{
struct fsnotify_group *group;
struct fsnotify_event *event = NULL;
struct vfsmount *mnt = NULL;
- int idx;
+ int idx, ret = 0;
/* global tests shouldn't care about events on child only the specific event */
__u32 test_mask = (mask & ~FS_EVENT_ON_CHILD);
/* if no fsnotify listeners, nothing to do */
if (list_empty(&fsnotify_inode_groups) &&
list_empty(&fsnotify_vfsmount_groups))
- return;
+ return 0;
if (mask & FS_MODIFY)
__fsnotify_flush_ignored_mask(to_tell, data, data_is);
/* if none of the directed listeners or vfsmount listeners care */
if (!(test_mask & fsnotify_inode_mask) &&
!(test_mask & fsnotify_vfsmount_mask))
- return;
+ return 0;
- if (data_is == FSNOTIFY_EVENT_PATH)
- mnt = ((struct path *)data)->mnt;
+ if (data_is == FSNOTIFY_EVENT_FILE)
+ mnt = ((struct file *)data)->f_path.mnt;
/* if this inode's directed listeners don't care and nothing on the vfsmount
* listeners list cares, nothing to do */
if (!(test_mask & to_tell->i_fsnotify_mask) &&
!needed_by_vfsmount(test_mask, mnt))
- return;
+ return 0;
/*
* SRCU!! the groups list is very very much read only and the path is
if (test_mask & to_tell->i_fsnotify_mask) {
list_for_each_entry_rcu(group, &fsnotify_inode_groups, inode_group_list) {
if (test_mask & group->mask) {
- send_to_group(group, to_tell, NULL, mask, data, data_is,
- cookie, file_name, &event);
+ ret = send_to_group(group, to_tell, NULL, mask, data, data_is,
+ cookie, file_name, &event);
+ if (ret)
+ goto out;
}
}
}
if (needed_by_vfsmount(test_mask, mnt)) {
list_for_each_entry_rcu(group, &fsnotify_vfsmount_groups, vfsmount_group_list) {
if (test_mask & group->mask) {
- send_to_group(group, to_tell, mnt, mask, data, data_is,
- cookie, file_name, &event);
+ ret = send_to_group(group, to_tell, mnt, mask, data, data_is,
+ cookie, file_name, &event);
+ if (ret)
+ goto out;
}
}
}
-
+out:
srcu_read_unlock(&fsnotify_grp_srcu, idx);
/*
* fsnotify_create_event() took a reference so the event can't be cleaned
*/
if (event)
fsnotify_put_event(event);
+
+ return ret;
}
EXPORT_SYMBOL_GPL(fsnotify);
static __init int fsnotify_init(void)
{
+ BUG_ON(hweight32(ALL_FSNOTIFY_EVENTS) != 23);
+
return init_srcu_struct(&fsnotify_grp_srcu);
}
subsys_initcall(fsnotify_init);