Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 207627
b: refs/heads/master
c: 1201a53
h: refs/heads/master
i:
  207625: 86a3e99
  207623: 80d383c
v: v3
  • Loading branch information
Eric Paris committed Jul 28, 2010
1 parent f638c12 commit 02eddbd
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: b4e4e1407312ae5a267ed7d716e6d4e7120a8430
refs/heads/master: 1201a5361b9bd6512ae01e6f2b7aa79d458cafb1
56 changes: 56 additions & 0 deletions trunk/fs/notify/notification.c
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,62 @@ static void initialize_event(struct fsnotify_event *event)
INIT_LIST_HEAD(&event->private_data_list);
}

/*
* Caller damn well better be holding whatever mutex is protecting the
* old_holder->event_list.
*/
int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
struct fsnotify_event *new_event)
{
struct fsnotify_event *old_event = old_holder->event;
struct fsnotify_event_holder *new_holder = NULL;

/*
* There is one fsnotify_event_holder embedded inside each fsnotify_event.
* Check if we expect to be able to use that holder. If not alloc a new
* holder.
* For the overflow event it's possible that something will use the in
* event holder before we get the lock so we may need to jump back and
* alloc a new holder, this can't happen for most events...
*/
if (!list_empty(&new_event->holder.event_list)) {
alloc_holder:
new_holder = fsnotify_alloc_event_holder();
if (!new_holder)
return -ENOMEM;
}

spin_lock(&old_event->lock);
spin_lock(&new_event->lock);

if (list_empty(&new_event->holder.event_list)) {
if (unlikely(new_holder))
fsnotify_destroy_event_holder(new_holder);
new_holder = &new_event->holder;
} else if (unlikely(!new_holder)) {
/* between the time we checked above and got the lock the in
* event holder was used, go back and get a new one */
spin_unlock(&new_event->lock);
spin_unlock(&old_event->lock);
goto alloc_holder;
}

new_holder->event = new_event;
list_replace_init(&old_holder->event_list, &new_holder->event_list);

spin_unlock(&new_event->lock);
spin_unlock(&old_event->lock);

/* event == holder means we are referenced through the in event holder */
if (old_holder != &old_event->holder)
fsnotify_destroy_event_holder(old_holder);

fsnotify_get_event(new_event); /* on the list take reference */
fsnotify_put_event(old_event); /* off the list, drop reference */

return 0;
}

struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event)
{
struct fsnotify_event *event;
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/fsnotify_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,8 @@ extern struct fsnotify_event *fsnotify_create_event(struct inode *to_tell, __u32

/* fanotify likes to change events after they are on lists... */
extern struct fsnotify_event *fsnotify_clone_event(struct fsnotify_event *old_event);
extern int fsnotify_replace_event(struct fsnotify_event_holder *old_holder,
struct fsnotify_event *new_event);

#else

Expand Down

0 comments on commit 02eddbd

Please sign in to comment.