* General Public License for more details.
*/
+#include <linux/dcache.h> /* d_unlinked */
#include <linux/fs.h> /* struct inode */
#include <linux/fsnotify_backend.h>
#include <linux/inotify.h>
!strcmp(old->file_name, new->file_name))
return true;
break;
- case (FSNOTIFY_EVENT_PATH):
- if ((old->path.mnt == new->path.mnt) &&
- (old->path.dentry == new->path.dentry))
+ case (FSNOTIFY_EVENT_FILE):
+ if ((old->file->f_path.mnt == new->file->f_path.mnt) &&
+ (old->file->f_path.dentry == new->file->f_path.dentry))
return true;
break;
case (FSNOTIFY_EVENT_NONE):
return false;
}
-static int inotify_merge(struct list_head *list,
- struct fsnotify_event *event,
- void **arg)
+static struct fsnotify_event *inotify_merge(struct list_head *list,
+ struct fsnotify_event *event)
{
struct fsnotify_event_holder *last_holder;
struct fsnotify_event *last_event;
- int ret = 0;
/* and the list better be locked by something too */
spin_lock(&event->lock);
last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
last_event = last_holder->event;
if (event_compare(last_event, event))
- ret = -EEXIST;
+ fsnotify_get_event(last_event);
+ else
+ last_event = NULL;
spin_unlock(&event->lock);
- return ret;
+ return last_event;
}
-static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
+static int inotify_handle_event(struct fsnotify_group *group,
+ struct fsnotify_mark *mark,
+ struct fsnotify_event *event)
{
- struct fsnotify_mark *fsn_mark;
struct inotify_inode_mark *i_mark;
struct inode *to_tell;
struct inotify_event_private_data *event_priv;
struct fsnotify_event_private_data *fsn_event_priv;
- int wd, ret;
+ struct fsnotify_event *added_event;
+ int wd, ret = 0;
+
+ pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group,
+ event, event->to_tell, event->mask);
to_tell = event->to_tell;
- fsn_mark = fsnotify_find_inode_mark(group, to_tell);
- /* race with watch removal? We already passes should_send */
- if (unlikely(!fsn_mark))
- return 0;
- i_mark = container_of(fsn_mark, struct inotify_inode_mark,
+ i_mark = container_of(mark, struct inotify_inode_mark,
fsn_mark);
wd = i_mark->wd;
fsn_event_priv->group = group;
event_priv->wd = wd;
- ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge, NULL);
- if (ret) {
+ added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
+ if (added_event) {
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 (!IS_ERR(added_event))
+ fsnotify_put_event(added_event);
+ else
+ ret = PTR_ERR(added_event);
}
- if (fsn_mark->mask & IN_ONESHOT)
- fsnotify_destroy_mark(fsn_mark);
-
- /*
- * If we hold the fsn_mark until after the event is on the queue
- * IN_IGNORED won't be able to pass this event in the queue
- */
- fsnotify_put_mark(fsn_mark);
+ if (mark->mask & IN_ONESHOT)
+ fsnotify_destroy_mark(mark);
return ret;
}
}
static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
- struct vfsmount *mnt, __u32 mask, void *data,
- int data_type)
+ struct vfsmount *mnt, struct fsnotify_mark *mark,
+ __u32 mask, void *data, int data_type)
{
- struct fsnotify_mark *fsn_mark;
- bool send;
-
- fsn_mark = fsnotify_find_inode_mark(group, inode);
- if (!fsn_mark)
- return false;
+ if ((mark->mask & FS_EXCL_UNLINK) &&
+ (data_type == FSNOTIFY_EVENT_FILE)) {
+ struct file *file = data;
- mask = (mask & ~FS_EVENT_ON_CHILD);
- send = (fsn_mark->mask & mask);
-
- /* find took a reference */
- fsnotify_put_mark(fsn_mark);
+ if (d_unlinked(file->f_path.dentry))
+ return false;
+ }
- return send;
+ return true;
}
/*