diff options
author | Jan Kara <jack@suse.cz> | 2016-12-21 08:48:18 -0500 |
---|---|---|
committer | Jan Kara <jack@suse.cz> | 2017-04-10 11:37:36 -0400 |
commit | f09b04a03e0239f65bd964a1de758e53cf6349e8 (patch) | |
tree | dc8f9b75eb2f98fee22d48e516a3734035868c69 | |
parent | 6b3f05d24d355f50f3d9814304650fcab0efb482 (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.h | 6 | ||||
-rw-r--r-- | fs/notify/group.c | 10 | ||||
-rw-r--r-- | fs/notify/mark.c | 7 |
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 */ |
38 | extern void fsnotify_detach_group_marks(struct fsnotify_group *group); | 38 | extern 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 | 40 | extern void fsnotify_wait_marks_destroyed(void); |
41 | */ | ||
42 | extern 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 | */ |
706 | void fsnotify_mark_destroy_list(void) | 706 | static 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 | ||
724 | static void fsnotify_mark_destroy_workfn(struct work_struct *work) | 724 | /* Wait for all marks queued for destruction to be actually destroyed */ |
725 | void fsnotify_wait_marks_destroyed(void) | ||
725 | { | 726 | { |
726 | fsnotify_mark_destroy_list(); | 727 | flush_delayed_work(&reaper_work); |
727 | } | 728 | } |