mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-12-01 14:26:46 +07:00
23e964c284
Get a group ref for each mark that is added to the groups list and release that ref when the mark is freed in fsnotify_put_mark(). We also use get a group reference for duplicated marks and for private event data. Now we dont free a group any more when the number of marks becomes 0 but when the groups ref count does. Since this will only happen when all marks are removed from a groups mark list, we dont have to set the groups number of marks to 1 at group creation. Beside clearing all marks in fsnotify_destroy_group() we do also flush the groups event queue. This is since events may hold references to groups (due to private event data) and we have to put those references first before we get a chance to put the final ref, which will result in a call to fsnotify_final_destroy_group(). Signed-off-by: Lino Sanfilippo <LinoSanfilippo@gmx.de> Signed-off-by: Eric Paris <eparis@redhat.com>
105 lines
2.7 KiB
C
105 lines
2.7 KiB
C
/*
|
|
* Copyright (C) 2008 Red Hat, Inc., Eric Paris <eparis@redhat.com>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2, or (at your option)
|
|
* any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; see the file COPYING. If not, write to
|
|
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
|
|
#include <linux/list.h>
|
|
#include <linux/mutex.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/srcu.h>
|
|
#include <linux/rculist.h>
|
|
#include <linux/wait.h>
|
|
|
|
#include <linux/fsnotify_backend.h>
|
|
#include "fsnotify.h"
|
|
|
|
#include <linux/atomic.h>
|
|
|
|
/*
|
|
* Final freeing of a group
|
|
*/
|
|
void fsnotify_final_destroy_group(struct fsnotify_group *group)
|
|
{
|
|
if (group->ops->free_group_priv)
|
|
group->ops->free_group_priv(group);
|
|
|
|
kfree(group);
|
|
}
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
/* clear all inode marks for this group */
|
|
fsnotify_clear_marks_by_group(group);
|
|
|
|
synchronize_srcu(&fsnotify_mark_srcu);
|
|
|
|
/* clear the notification queue of all events */
|
|
fsnotify_flush_notify(group);
|
|
|
|
fsnotify_put_group(group);
|
|
}
|
|
|
|
/*
|
|
* Get reference to a group.
|
|
*/
|
|
void fsnotify_get_group(struct fsnotify_group *group)
|
|
{
|
|
atomic_inc(&group->refcnt);
|
|
}
|
|
|
|
/*
|
|
* Drop a reference to a group. Free it if it's through.
|
|
*/
|
|
void fsnotify_put_group(struct fsnotify_group *group)
|
|
{
|
|
if (atomic_dec_and_test(&group->refcnt))
|
|
fsnotify_final_destroy_group(group);
|
|
}
|
|
|
|
/*
|
|
* Create a new fsnotify_group and hold a reference for the group returned.
|
|
*/
|
|
struct fsnotify_group *fsnotify_alloc_group(const struct fsnotify_ops *ops)
|
|
{
|
|
struct fsnotify_group *group;
|
|
|
|
group = kzalloc(sizeof(struct fsnotify_group), GFP_KERNEL);
|
|
if (!group)
|
|
return ERR_PTR(-ENOMEM);
|
|
|
|
/* set to 0 when there a no external references to this group */
|
|
atomic_set(&group->refcnt, 1);
|
|
atomic_set(&group->num_marks, 0);
|
|
|
|
mutex_init(&group->notification_mutex);
|
|
INIT_LIST_HEAD(&group->notification_list);
|
|
init_waitqueue_head(&group->notification_waitq);
|
|
group->max_events = UINT_MAX;
|
|
|
|
spin_lock_init(&group->mark_lock);
|
|
INIT_LIST_HEAD(&group->marks_list);
|
|
|
|
group->ops = ops;
|
|
|
|
return group;
|
|
}
|