aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2016-12-21 08:48:18 -0500
committerJan Kara <jack@suse.cz>2017-04-10 11:37:36 -0400
commitf09b04a03e0239f65bd964a1de758e53cf6349e8 (patch)
treedc8f9b75eb2f98fee22d48e516a3734035868c69
parent6b3f05d24d355f50f3d9814304650fcab0efb482 (diff)
fsnotify: Remove special handling of mark destruction on group shutdown
Currently we queue all marks for destruction on group shutdown and then destroy them from fsnotify_destroy_group() instead from a worker thread which is the usual path. However worker can already be processing some list of marks to destroy so this does not make 100% all marks are really destroyed by the time group is shut down. This isn't a big problem as each mark holds group reference and thus group stays partially alive until all marks are really freed but there's no point in complicating our lives - just wait for the delayed work to be finished instead. Reviewed-by: Miklos Szeredi <mszeredi@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--fs/notify/fsnotify.h6
-rw-r--r--fs/notify/group.c10
-rw-r--r--fs/notify/mark.c7
3 files changed, 12 insertions, 11 deletions
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)
36} 36}
37/* prepare for freeing all marks associated with given group */ 37/* prepare for freeing all marks associated with given group */
38extern void fsnotify_detach_group_marks(struct fsnotify_group *group); 38extern void fsnotify_detach_group_marks(struct fsnotify_group *group);
39/* 39/* Wait until all marks queued for destruction are destroyed */
40 * wait for fsnotify_mark_srcu period to end and free all marks in destroy_list 40extern void fsnotify_wait_marks_destroyed(void);
41 */
42extern void fsnotify_mark_destroy_list(void);
43 41
44/* 42/*
45 * update the dentry->d_flags of all of inode's children to indicate if inode cares 43 * 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)
66 */ 66 */
67 fsnotify_group_stop_queueing(group); 67 fsnotify_group_stop_queueing(group);
68 68
69 /* clear all inode marks for this group, attach them to destroy_list */ 69 /* Clear all marks for this group and queue them for destruction */
70 fsnotify_detach_group_marks(group); 70 fsnotify_detach_group_marks(group);
71 71
72 /* 72 /*
73 * Wait for fsnotify_mark_srcu period to end and free all marks in 73 * Wait until all marks get really destroyed. We could actually destroy
74 * destroy_list 74 * them ourselves instead of waiting for worker to do it, however that
75 * would be racy as worker can already be processing some marks before
76 * we even entered fsnotify_destroy_group().
75 */ 77 */
76 fsnotify_mark_destroy_list(); 78 fsnotify_wait_marks_destroyed();
77 79
78 /* 80 /*
79 * Since we have waited for fsnotify_mark_srcu in 81 * 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,
703 * Destroy all marks in destroy_list, waits for SRCU period to finish before 703 * Destroy all marks in destroy_list, waits for SRCU period to finish before
704 * actually freeing marks. 704 * actually freeing marks.
705 */ 705 */
706void fsnotify_mark_destroy_list(void) 706static void fsnotify_mark_destroy_workfn(struct work_struct *work)
707{ 707{
708 struct fsnotify_mark *mark, *next; 708 struct fsnotify_mark *mark, *next;
709 struct list_head private_destroy_list; 709 struct list_head private_destroy_list;
@@ -721,7 +721,8 @@ void fsnotify_mark_destroy_list(void)
721 } 721 }
722} 722}
723 723
724static void fsnotify_mark_destroy_workfn(struct work_struct *work) 724/* Wait for all marks queued for destruction to be actually destroyed */
725void fsnotify_wait_marks_destroyed(void)
725{ 726{
726 fsnotify_mark_destroy_list(); 727 flush_delayed_work(&reaper_work);
727} 728}