diff options
author | Jeff Layton <jlayton@poochiereds.net> | 2016-02-17 16:11:21 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-02-18 19:23:24 -0500 |
commit | 0918f1c309b86301605650c836ddd2021d311ae2 (patch) | |
tree | 973765405f04bda0739f6649b5cca78cac719ca7 /fs | |
parent | 13d34ac6e55b8284c592c67e166ac614b3c4c1d7 (diff) |
fsnotify: turn fsnotify reaper thread into a workqueue job
We don't require a dedicated thread for fsnotify cleanup. Switch it
over to a workqueue job instead that runs on the system_unbound_wq.
In the interest of not thrashing the queued job too often when there are
a lot of marks being removed, we delay the reaper job slightly when
queueing it, to allow several to gather on the list.
Signed-off-by: Jeff Layton <jeff.layton@primarydata.com>
Tested-by: Eryu Guan <guaneryu@gmail.com>
Reviewed-by: Jan Kara <jack@suse.cz>
Cc: Eric Paris <eparis@parisplace.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/notify/mark.c | 49 |
1 files changed, 18 insertions, 31 deletions
diff --git a/fs/notify/mark.c b/fs/notify/mark.c index fc0df4442f7b..7115c5d7d373 100644 --- a/fs/notify/mark.c +++ b/fs/notify/mark.c | |||
@@ -91,10 +91,14 @@ | |||
91 | #include <linux/fsnotify_backend.h> | 91 | #include <linux/fsnotify_backend.h> |
92 | #include "fsnotify.h" | 92 | #include "fsnotify.h" |
93 | 93 | ||
94 | #define FSNOTIFY_REAPER_DELAY (1) /* 1 jiffy */ | ||
95 | |||
94 | struct srcu_struct fsnotify_mark_srcu; | 96 | struct srcu_struct fsnotify_mark_srcu; |
95 | static DEFINE_SPINLOCK(destroy_lock); | 97 | static DEFINE_SPINLOCK(destroy_lock); |
96 | static LIST_HEAD(destroy_list); | 98 | static LIST_HEAD(destroy_list); |
97 | static DECLARE_WAIT_QUEUE_HEAD(destroy_waitq); | 99 | |
100 | static void fsnotify_mark_destroy(struct work_struct *work); | ||
101 | static DECLARE_DELAYED_WORK(reaper_work, fsnotify_mark_destroy); | ||
98 | 102 | ||
99 | void fsnotify_get_mark(struct fsnotify_mark *mark) | 103 | void fsnotify_get_mark(struct fsnotify_mark *mark) |
100 | { | 104 | { |
@@ -189,7 +193,8 @@ void fsnotify_free_mark(struct fsnotify_mark *mark) | |||
189 | spin_lock(&destroy_lock); | 193 | spin_lock(&destroy_lock); |
190 | list_add(&mark->g_list, &destroy_list); | 194 | list_add(&mark->g_list, &destroy_list); |
191 | spin_unlock(&destroy_lock); | 195 | spin_unlock(&destroy_lock); |
192 | wake_up(&destroy_waitq); | 196 | queue_delayed_work(system_unbound_wq, &reaper_work, |
197 | FSNOTIFY_REAPER_DELAY); | ||
193 | 198 | ||
194 | /* | 199 | /* |
195 | * Some groups like to know that marks are being freed. This is a | 200 | * Some groups like to know that marks are being freed. This is a |
@@ -388,7 +393,8 @@ err: | |||
388 | spin_lock(&destroy_lock); | 393 | spin_lock(&destroy_lock); |
389 | list_add(&mark->g_list, &destroy_list); | 394 | list_add(&mark->g_list, &destroy_list); |
390 | spin_unlock(&destroy_lock); | 395 | spin_unlock(&destroy_lock); |
391 | wake_up(&destroy_waitq); | 396 | queue_delayed_work(system_unbound_wq, &reaper_work, |
397 | FSNOTIFY_REAPER_DELAY); | ||
392 | 398 | ||
393 | return ret; | 399 | return ret; |
394 | } | 400 | } |
@@ -493,39 +499,20 @@ void fsnotify_init_mark(struct fsnotify_mark *mark, | |||
493 | mark->free_mark = free_mark; | 499 | mark->free_mark = free_mark; |
494 | } | 500 | } |
495 | 501 | ||
496 | static int fsnotify_mark_destroy(void *ignored) | 502 | static void fsnotify_mark_destroy(struct work_struct *work) |
497 | { | 503 | { |
498 | struct fsnotify_mark *mark, *next; | 504 | struct fsnotify_mark *mark, *next; |
499 | struct list_head private_destroy_list; | 505 | struct list_head private_destroy_list; |
500 | 506 | ||
501 | for (;;) { | 507 | spin_lock(&destroy_lock); |
502 | spin_lock(&destroy_lock); | 508 | /* exchange the list head */ |
503 | /* exchange the list head */ | 509 | list_replace_init(&destroy_list, &private_destroy_list); |
504 | list_replace_init(&destroy_list, &private_destroy_list); | 510 | spin_unlock(&destroy_lock); |
505 | spin_unlock(&destroy_lock); | ||
506 | |||
507 | synchronize_srcu(&fsnotify_mark_srcu); | ||
508 | 511 | ||
509 | list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) { | 512 | synchronize_srcu(&fsnotify_mark_srcu); |
510 | list_del_init(&mark->g_list); | ||
511 | fsnotify_put_mark(mark); | ||
512 | } | ||
513 | 513 | ||
514 | wait_event_interruptible(destroy_waitq, !list_empty(&destroy_list)); | 514 | list_for_each_entry_safe(mark, next, &private_destroy_list, g_list) { |
515 | list_del_init(&mark->g_list); | ||
516 | fsnotify_put_mark(mark); | ||
515 | } | 517 | } |
516 | |||
517 | return 0; | ||
518 | } | ||
519 | |||
520 | static int __init fsnotify_mark_init(void) | ||
521 | { | ||
522 | struct task_struct *thread; | ||
523 | |||
524 | thread = kthread_run(fsnotify_mark_destroy, NULL, | ||
525 | "fsnotify_mark"); | ||
526 | if (IS_ERR(thread)) | ||
527 | panic("unable to start fsnotify mark destruction thread."); | ||
528 | |||
529 | return 0; | ||
530 | } | 518 | } |
531 | device_initcall(fsnotify_mark_init); | ||