Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 207625
b: refs/heads/master
c: 74766bb
h: refs/heads/master
i:
  207623: 80d383c
v: v3
  • Loading branch information
Eric Paris committed Jul 28, 2010
1 parent 89a8f41 commit 86a3e99
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 59 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 28c60e37f874dcbb93c4afc839ba5e4911c4f4bc
refs/heads/master: 74766bbfa99adf8cb8119df6121851edba21c9d9
56 changes: 55 additions & 1 deletion trunk/fs/notify/inotify/inotify_fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,60 @@

#include "inotify.h"

/*
* Check if 2 events contain the same information. We do not compare private data
* but at this moment that isn't a problem for any know fsnotify listeners.
*/
static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
{
if ((old->mask == new->mask) &&
(old->to_tell == new->to_tell) &&
(old->data_type == new->data_type) &&
(old->name_len == new->name_len)) {
switch (old->data_type) {
case (FSNOTIFY_EVENT_INODE):
/* remember, after old was put on the wait_q we aren't
* allowed to look at the inode any more, only thing
* left to check was if the file_name is the same */
if (!old->name_len ||
!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))
return true;
break;
case (FSNOTIFY_EVENT_NONE):
if (old->mask & FS_Q_OVERFLOW)
return true;
else if (old->mask & FS_IN_IGNORED)
return false;
return true;
};
}
return false;
}

static int 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;

spin_unlock(&event->lock);

return ret;
}

static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
{
struct fsnotify_mark_entry *entry;
Expand Down Expand Up @@ -62,7 +116,7 @@ static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_ev
fsn_event_priv->group = group;
event_priv->wd = wd;

ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
ret = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
if (ret) {
inotify_free_event_priv(fsn_event_priv);
/* EEXIST says we tail matched, EOVERFLOW isn't something
Expand Down
2 changes: 1 addition & 1 deletion trunk/fs/notify/inotify/inotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,7 +531,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark_entry *entry,
fsn_event_priv->group = group;
event_priv->wd = ientry->wd;

ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv);
ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
if (ret)
inotify_free_event_priv(fsn_event_priv);

Expand Down
73 changes: 19 additions & 54 deletions trunk/fs/notify/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ struct fsnotify_event_holder *fsnotify_alloc_event_holder(void)

void fsnotify_destroy_event_holder(struct fsnotify_event_holder *holder)
{
kmem_cache_free(fsnotify_event_holder_cachep, holder);
if (holder)
kmem_cache_free(fsnotify_event_holder_cachep, holder);
}

/*
Expand All @@ -128,54 +129,18 @@ struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struct fsnot
return priv;
}

/*
* Check if 2 events contain the same information. We do not compare private data
* but at this moment that isn't a problem for any know fsnotify listeners.
*/
static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
{
if ((old->mask == new->mask) &&
(old->to_tell == new->to_tell) &&
(old->data_type == new->data_type) &&
(old->name_len == new->name_len)) {
switch (old->data_type) {
case (FSNOTIFY_EVENT_INODE):
/* remember, after old was put on the wait_q we aren't
* allowed to look at the inode any more, only thing
* left to check was if the file_name is the same */
if (!old->name_len ||
!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))
return true;
break;
case (FSNOTIFY_EVENT_NONE):
if (old->mask & FS_Q_OVERFLOW)
return true;
else if (old->mask & FS_IN_IGNORED)
return false;
return false;
};
}
return false;
}

/*
* Add an event to the group notification queue. The group can later pull this
* event off the queue to deal with. If the event is successfully added to the
* group's notification queue, a reference is taken on event.
*/
int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
struct fsnotify_event_private_data *priv)
struct fsnotify_event_private_data *priv,
int (*merge)(struct list_head *, struct fsnotify_event *))
{
struct fsnotify_event_holder *holder = NULL;
struct list_head *list = &group->notification_list;
struct fsnotify_event_holder *last_holder;
struct fsnotify_event *last_event;
int ret = 0;
int rc = 0;

/*
* There is one fsnotify_event_holder embedded inside each fsnotify_event.
Expand All @@ -196,11 +161,23 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even

if (group->q_len >= group->max_events) {
event = q_overflow_event;
ret = -EOVERFLOW;
rc = -EOVERFLOW;
/* sorry, no private data on the overflow event */
priv = NULL;
}

if (!list_empty(list) && merge) {
int ret;

ret = merge(list, event);
if (ret) {
mutex_unlock(&group->notification_mutex);
if (holder != &event->holder)
fsnotify_destroy_event_holder(holder);
return ret;
}
}

spin_lock(&event->lock);

if (list_empty(&event->holder.event_list)) {
Expand All @@ -215,18 +192,6 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
goto alloc_holder;
}

if (!list_empty(list)) {
last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
last_event = last_holder->event;
if (event_compare(last_event, event)) {
spin_unlock(&event->lock);
mutex_unlock(&group->notification_mutex);
if (holder != &event->holder)
fsnotify_destroy_event_holder(holder);
return -EEXIST;
}
}

group->q_len++;
holder->event = event;

Expand All @@ -238,7 +203,7 @@ int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_even
mutex_unlock(&group->notification_mutex);

wake_up(&group->notification_waitq);
return ret;
return rc;
}

/*
Expand Down
6 changes: 4 additions & 2 deletions trunk/include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -328,8 +328,10 @@ extern struct fsnotify_event_private_data *fsnotify_remove_priv_from_event(struc
struct fsnotify_event *event);

/* attach the event to the group notification queue */
extern int fsnotify_add_notify_event(struct fsnotify_group *group, struct fsnotify_event *event,
struct fsnotify_event_private_data *priv);
extern int fsnotify_add_notify_event(struct fsnotify_group *group,
struct fsnotify_event *event,
struct fsnotify_event_private_data *priv,
int (*merge)(struct list_head *, struct fsnotify_event *));
/* true if the group notification queue is empty */
extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
/* return, but do not dequeue the first event on the notification queue */
Expand Down

0 comments on commit 86a3e99

Please sign in to comment.