Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 347896
b: refs/heads/master
c: 23e964c
h: refs/heads/master
v: v3
  • Loading branch information
Lino Sanfilippo authored and Eric Paris committed Dec 11, 2012
1 parent f3783af commit 629c65d
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 29 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: 986129520479d689962a42c31acdeaf854ac91f5
refs/heads/master: 23e964c284ca0a767b80a30482bd53b059d30391
28 changes: 10 additions & 18 deletions trunk/fs/notify/group.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,22 +33,17 @@
*/
void fsnotify_final_destroy_group(struct fsnotify_group *group)
{
/* clear the notification queue of all events */
fsnotify_flush_notify(group);

if (group->ops->free_group_priv)
group->ops->free_group_priv(group);

kfree(group);
}

/*
* Trying to get rid of a group. We need to first get rid of any outstanding
* allocations and then free the group. Remember that fsnotify_clear_marks_by_group
* could miss marks that are being freed by inode and those marks could still
* hold a reference to this group (via group->num_marks) If we get into that
* situtation, the fsnotify_final_destroy_group will get called when that final
* mark is freed.
* Trying to get rid of a group. Remove all marks, flush all events and release
* the group reference.
* Note that another thread calling fsnotify_clear_marks_by_group() may still
* hold a ref to the group.
*/
void fsnotify_destroy_group(struct fsnotify_group *group)
{
Expand All @@ -57,9 +52,10 @@ void fsnotify_destroy_group(struct fsnotify_group *group)

synchronize_srcu(&fsnotify_mark_srcu);

/* past the point of no return, matches the initial value of 1 */
if (atomic_dec_and_test(&group->num_marks))
fsnotify_final_destroy_group(group);
/* clear the notification queue of all events */
fsnotify_flush_notify(group);

fsnotify_put_group(group);
}

/*
Expand All @@ -76,7 +72,7 @@ void fsnotify_get_group(struct fsnotify_group *group)
void fsnotify_put_group(struct fsnotify_group *group)
{
if (atomic_dec_and_test(&group->refcnt))
fsnotify_destroy_group(group);
fsnotify_final_destroy_group(group);
}

/*
Expand All @@ -92,11 +88,7 @@ struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)

/* set to 0 when there a no external references to this group */
atomic_set(&group->refcnt, 1);
/*
* hits 0 when there are no external references AND no marks for
* this group
*/
atomic_set(&group->num_marks, 1);
atomic_set(&group->num_marks, 0);

mutex_init(&group->notification_mutex);
INIT_LIST_HEAD(&group->notification_list);
Expand Down
2 changes: 2 additions & 0 deletions trunk/fs/notify/inotify/inotify_fsnotify.c
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ static int inotify_handle_event(struct fsnotify_group *group,

fsn_event_priv = &event_priv->fsnotify_event_priv_data;

fsnotify_get_group(group);
fsn_event_priv->group = group;
event_priv->wd = wd;

Expand Down Expand Up @@ -210,6 +211,7 @@ void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv)
event_priv = container_of(fsn_event_priv, struct inotify_event_private_data,
fsnotify_event_priv_data);

fsnotify_put_group(fsn_event_priv->group);
kmem_cache_free(event_priv_cachep, event_priv);
}

Expand Down
1 change: 1 addition & 0 deletions trunk/fs/notify/inotify/inotify_user.c
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,

fsn_event_priv = &event_priv->fsnotify_event_priv_data;

fsnotify_get_group(group);
fsn_event_priv->group = group;
event_priv->wd = i_mark->wd;

Expand Down
24 changes: 14 additions & 10 deletions trunk/fs/notify/mark.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,11 @@ void fsnotify_get_mark(struct fsnotify_mark *mark)

void fsnotify_put_mark(struct fsnotify_mark *mark)
{
if (atomic_dec_and_test(&mark->refcnt))
if (atomic_dec_and_test(&mark->refcnt)) {
if (mark->group)
fsnotify_put_group(mark->group);
mark->free_mark(mark);
}
}

/*
Expand All @@ -125,12 +128,13 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)

spin_lock(&mark->lock);

fsnotify_get_group(mark->group);
group = mark->group;

/* something else already called this function on this mark */
if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE)) {
spin_unlock(&mark->lock);
return;
goto put_group;
}

mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
Expand Down Expand Up @@ -177,19 +181,15 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark)

if (inode && (mark->flags & FSNOTIFY_MARK_FLAG_OBJECT_PINNED))
iput(inode);

/*
* We don't necessarily have a ref on mark from caller so the above iput
* may have already destroyed it. Don't touch from now on.
*/

/*
* it's possible that this group tried to destroy itself, but this
* this mark was simultaneously being freed by inode. If that's the
* case, we finish freeing the group here.
*/
if (unlikely(atomic_dec_and_test(&group->num_marks)))
fsnotify_final_destroy_group(group);
atomic_dec(&group->num_marks);

put_group:
fsnotify_put_group(group);
}

void fsnotify_set_mark_mask_locked(struct fsnotify_mark *mark, __u32 mask)
Expand Down Expand Up @@ -234,6 +234,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,

mark->flags |= FSNOTIFY_MARK_FLAG_ALIVE;

fsnotify_get_group(group);
mark->group = group;
list_add(&mark->g_list, &group->marks_list);
atomic_inc(&group->num_marks);
Expand Down Expand Up @@ -265,6 +266,7 @@ int fsnotify_add_mark(struct fsnotify_mark *mark,
err:
mark->flags &= ~FSNOTIFY_MARK_FLAG_ALIVE;
list_del_init(&mark->g_list);
fsnotify_put_group(group);
mark->group = NULL;
atomic_dec(&group->num_marks);

Expand Down Expand Up @@ -317,6 +319,8 @@ void fsnotify_duplicate_mark(struct fsnotify_mark *new, struct fsnotify_mark *ol
assert_spin_locked(&old->lock);
new->i.inode = old->i.inode;
new->m.mnt = old->m.mnt;
if (old->group)
fsnotify_get_group(old->group);
new->group = old->group;
new->mask = old->mask;
new->free_mark = old->free_mark;
Expand Down

0 comments on commit 629c65d

Please sign in to comment.