diff --git a/fs/notify/fsnotify.h b/fs/notify/fsnotify.h index 72050b75ca8c..2a92dc06198c 100644 --- a/fs/notify/fsnotify.h +++ b/fs/notify/fsnotify.h @@ -36,10 +36,8 @@ static inline void fsnotify_clear_marks_by_mount(struct vfsmount *mnt) } /* prepare for freeing all marks associated with given group */ extern void fsnotify_detach_group_marks(struct fsnotify_group *group); -/* - * wait for fsnotify_mark_srcu period to end and free all marks in destroy_list - */ -extern void fsnotify_mark_destroy_list(void); +/* Wait until all marks queued for destruction are destroyed */ +extern void fsnotify_wait_marks_destroyed(void); /* * update the dentry->d_flags of all of inode's children to indicate if inode cares diff --git a/fs/notify/group.c b/fs/notify/group.c index fbe3cbebec16..0fb4aadcc19f 100644 --- a/fs/notify/group.c +++ b/fs/notify/group.c @@ -66,14 +66,16 @@ void fsnotify_destroy_group(struct fsnotify_group *group) */ fsnotify_group_stop_queueing(group); - /* clear all inode marks for this group, attach them to destroy_list */ + /* Clear all marks for this group and queue them for destruction */ fsnotify_detach_group_marks(group); /* - * Wait for fsnotify_mark_srcu period to end and free all marks in - * destroy_list + * Wait until all marks get really destroyed. We could actually destroy + * them ourselves instead of waiting for worker to do it, however that + * would be racy as worker can already be processing some marks before + * we even entered fsnotify_destroy_group(). */ - fsnotify_mark_destroy_list(); + fsnotify_wait_marks_destroyed(); /* * Since we have waited for fsnotify_mark_srcu in diff --git a/fs/notify/mark.c b/fs/notify/mark.c index 21c7791362c8..f916b71c9139 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c @@ -703,7 +703,7 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, * Destroy all marks in destroy_list, waits for SRCU period to finish before * actually freeing marks. */ -void fsnotify_mark_destroy_list(void) +static void fsnotify_mark_destroy_workfn(struct work_struct *work) { struct fsnotify_mark *mark, *next; struct list_head private_destroy_list; @@ -721,7 +721,8 @@ void fsnotify_mark_destroy_list(void) } } -static void fsnotify_mark_destroy_workfn(struct work_struct *work) +/* Wait for all marks queued for destruction to be actually destroyed */ +void fsnotify_wait_marks_destroyed(void) { - fsnotify_mark_destroy_list(); + flush_delayed_work(&reaper_work); }