fsnotify: remove mark->free_list
Free list is used when all marks on given inode / mount should be destroyed when inode / mount is going away. However we can free all of the marks without using a special list with some care. Signed-off-by: Jan Kara <jack@suse.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
parent
1e39fc0183
commit
925d1132a0
|
@ -26,7 +26,6 @@
|
||||||
|
|
||||||
#include <linux/fsnotify_backend.h>
|
#include <linux/fsnotify_backend.h>
|
||||||
#include "fsnotify.h"
|
#include "fsnotify.h"
|
||||||
#include "../mount.h"
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear all of the marks on an inode when it is being evicted from core
|
* Clear all of the marks on an inode when it is being evicted from core
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
#include <linux/srcu.h>
|
#include <linux/srcu.h>
|
||||||
#include <linux/types.h>
|
#include <linux/types.h>
|
||||||
|
|
||||||
|
#include "../mount.h"
|
||||||
|
|
||||||
/* destroy all events sitting in this groups notification queue */
|
/* destroy all events sitting in this groups notification queue */
|
||||||
extern void fsnotify_flush_notify(struct fsnotify_group *group);
|
extern void fsnotify_flush_notify(struct fsnotify_group *group);
|
||||||
|
|
||||||
|
@ -38,15 +40,22 @@ extern int fsnotify_add_vfsmount_mark(struct fsnotify_mark *mark,
|
||||||
extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
|
extern void fsnotify_destroy_vfsmount_mark(struct fsnotify_mark *mark);
|
||||||
/* inode specific destruction of a mark */
|
/* inode specific destruction of a mark */
|
||||||
extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
|
extern void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark);
|
||||||
/* Destroy all marks in the given list */
|
|
||||||
extern void fsnotify_destroy_marks(struct list_head *to_free);
|
|
||||||
/* Find mark belonging to given group in the list of marks */
|
/* Find mark belonging to given group in the list of marks */
|
||||||
extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
|
extern struct fsnotify_mark *fsnotify_find_mark(struct hlist_head *head,
|
||||||
struct fsnotify_group *group);
|
struct fsnotify_group *group);
|
||||||
/* run the list of all marks associated with inode and flag them to be freed */
|
/* Destroy all marks in the given list protected by 'lock' */
|
||||||
extern void fsnotify_clear_marks_by_inode(struct inode *inode);
|
extern void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock);
|
||||||
/* run the list of all marks associated with vfsmount and flag them to be freed */
|
/* run the list of all marks associated with inode and destroy them */
|
||||||
extern void fsnotify_clear_marks_by_mount(struct vfsmount *mnt);
|
static inline void fsnotify_clear_marks_by_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
fsnotify_destroy_marks(&inode->i_fsnotify_marks, &inode->i_lock);
|
||||||
|
}
|
||||||
|
/* run the list of all marks associated with vfsmount and destroy them */
|
||||||
|
static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
|
||||||
|
{
|
||||||
|
fsnotify_destroy_marks(&real_mount(mnt)->mnt_fsnotify_marks,
|
||||||
|
&mnt->mnt_root->d_lock);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* update the dentry->d_flags of all of inode's children to indicate if inode cares
|
* update the dentry->d_flags of all of inode's children to indicate if inode cares
|
||||||
* about events that happen to its children.
|
* about events that happen to its children.
|
||||||
|
|
|
@ -64,26 +64,6 @@ void fsnotify_destroy_inode_mark(struct fsnotify_mark *mark)
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Given an inode, destroy all of the marks associated with that inode.
|
|
||||||
*/
|
|
||||||
void fsnotify_clear_marks_by_inode(struct inode *inode)
|
|
||||||
{
|
|
||||||
struct fsnotify_mark *mark;
|
|
||||||
struct hlist_node *n;
|
|
||||||
LIST_HEAD(free_list);
|
|
||||||
|
|
||||||
spin_lock(&inode->i_lock);
|
|
||||||
hlist_for_each_entry_safe(mark, n, &inode->i_fsnotify_marks, obj_list) {
|
|
||||||
list_add(&mark->free_list, &free_list);
|
|
||||||
hlist_del_init_rcu(&mark->obj_list);
|
|
||||||
fsnotify_get_mark(mark);
|
|
||||||
}
|
|
||||||
spin_unlock(&inode->i_lock);
|
|
||||||
|
|
||||||
fsnotify_destroy_marks(&free_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Given a group clear all of the inode marks associated with that group.
|
* Given a group clear all of the inode marks associated with that group.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -203,24 +203,34 @@ void fsnotify_destroy_mark(struct fsnotify_mark *mark,
|
||||||
mutex_unlock(&group->mark_mutex);
|
mutex_unlock(&group->mark_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void fsnotify_destroy_marks(struct hlist_head *head, spinlock_t *lock)
|
||||||
* Destroy all marks in the given list. The marks must be already detached from
|
|
||||||
* the original inode / vfsmount.
|
|
||||||
*/
|
|
||||||
void fsnotify_destroy_marks(struct list_head *to_free)
|
|
||||||
{
|
{
|
||||||
struct fsnotify_mark *mark, *lmark;
|
struct fsnotify_mark *mark;
|
||||||
struct fsnotify_group *group;
|
|
||||||
|
|
||||||
list_for_each_entry_safe(mark, lmark, to_free, free_list) {
|
while (1) {
|
||||||
spin_lock(&mark->lock);
|
/*
|
||||||
fsnotify_get_group(mark->group);
|
* We have to be careful since we can race with e.g.
|
||||||
group = mark->group;
|
* fsnotify_clear_marks_by_group() and once we drop 'lock',
|
||||||
spin_unlock(&mark->lock);
|
* mark can get removed from the obj_list and destroyed. But
|
||||||
|
* we are holding mark reference so mark cannot be freed and
|
||||||
fsnotify_destroy_mark(mark, group);
|
* calling fsnotify_destroy_mark() more than once is fine.
|
||||||
|
*/
|
||||||
|
spin_lock(lock);
|
||||||
|
if (hlist_empty(head)) {
|
||||||
|
spin_unlock(lock);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
mark = hlist_entry(head->first, struct fsnotify_mark, obj_list);
|
||||||
|
/*
|
||||||
|
* We don't update i_fsnotify_mask / mnt_fsnotify_mask here
|
||||||
|
* since inode / mount is going away anyway. So just remove
|
||||||
|
* mark from the list.
|
||||||
|
*/
|
||||||
|
hlist_del_init_rcu(&mark->obj_list);
|
||||||
|
fsnotify_get_mark(mark);
|
||||||
|
spin_unlock(lock);
|
||||||
|
fsnotify_destroy_mark(mark, mark->group);
|
||||||
fsnotify_put_mark(mark);
|
fsnotify_put_mark(mark);
|
||||||
fsnotify_put_group(group);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,25 +28,6 @@
|
||||||
|
|
||||||
#include <linux/fsnotify_backend.h>
|
#include <linux/fsnotify_backend.h>
|
||||||
#include "fsnotify.h"
|
#include "fsnotify.h"
|
||||||
#include "../mount.h"
|
|
||||||
|
|
||||||
void fsnotify_clear_marks_by_mount(struct vfsmount *mnt)
|
|
||||||
{
|
|
||||||
struct fsnotify_mark *mark;
|
|
||||||
struct hlist_node *n;
|
|
||||||
struct mount *m = real_mount(mnt);
|
|
||||||
LIST_HEAD(free_list);
|
|
||||||
|
|
||||||
spin_lock(&mnt->mnt_root->d_lock);
|
|
||||||
hlist_for_each_entry_safe(mark, n, &m->mnt_fsnotify_marks, obj_list) {
|
|
||||||
list_add(&mark->free_list, &free_list);
|
|
||||||
hlist_del_init_rcu(&mark->obj_list);
|
|
||||||
fsnotify_get_mark(mark);
|
|
||||||
}
|
|
||||||
spin_unlock(&mnt->mnt_root->d_lock);
|
|
||||||
|
|
||||||
fsnotify_destroy_marks(&free_list);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
|
void fsnotify_clear_vfsmount_marks_by_group(struct fsnotify_group *group)
|
||||||
{
|
{
|
||||||
|
|
|
@ -225,8 +225,6 @@ struct fsnotify_mark {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
/* List of marks for inode / vfsmount [obj_lock] */
|
/* List of marks for inode / vfsmount [obj_lock] */
|
||||||
struct hlist_node obj_list;
|
struct hlist_node obj_list;
|
||||||
/* tmp list used when freeing this mark */
|
|
||||||
struct list_head free_list;
|
|
||||||
union { /* Object pointer [mark->lock, group->mark_mutex] */
|
union { /* Object pointer [mark->lock, group->mark_mutex] */
|
||||||
struct inode *inode; /* inode this mark is associated with */
|
struct inode *inode; /* inode this mark is associated with */
|
||||||
struct vfsmount *mnt; /* vfsmount this mark is associated with */
|
struct vfsmount *mnt; /* vfsmount this mark is associated with */
|
||||||
|
|
Loading…
Reference in New Issue