This and the next patches in this series aim to make time effect of synchronize_srcu() invisible for user. The patch splits unregister_shrinker() in two functions: unregister_shrinker_delayed_initiate() unregister_shrinker_delayed_finalize() and shrinker users may make the second of them to be called asynchronous (e.g., from workqueue). Next patches make superblock shrinker to follow this way, so user-visible umount() time won't contain delays from synchronize_srcu(). Signed-off-by: Kirill Tkhai <ktkhai@xxxxxxxxxxxxx> --- include/linux/shrinker.h | 2 ++ mm/vmscan.c | 22 ++++++++++++++++++---- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/include/linux/shrinker.h b/include/linux/shrinker.h index 9443cafd1969..92062d1239c2 100644 --- a/include/linux/shrinker.h +++ b/include/linux/shrinker.h @@ -86,5 +86,7 @@ extern int prealloc_shrinker(struct shrinker *shrinker); extern void register_shrinker_prepared(struct shrinker *shrinker); extern int register_shrinker(struct shrinker *shrinker); extern void unregister_shrinker(struct shrinker *shrinker); +extern void unregister_shrinker_delayed_initiate(struct shrinker *shrinker); +extern void unregister_shrinker_delayed_finalize(struct shrinker *shrinker); extern void free_prealloced_shrinker(struct shrinker *shrinker); #endif diff --git a/mm/vmscan.c b/mm/vmscan.c index 2dc274a385b9..fba4996dfe25 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -422,10 +422,7 @@ int register_shrinker(struct shrinker *shrinker) } EXPORT_SYMBOL(register_shrinker); -/* - * Remove one - */ -void unregister_shrinker(struct shrinker *shrinker) +void unregister_shrinker_delayed_initiate(struct shrinker *shrinker) { if (!shrinker->nr_deferred) return; @@ -434,12 +431,29 @@ void unregister_shrinker(struct shrinker *shrinker) mutex_lock(&shrinker_mutex); list_del_rcu(&shrinker->list); mutex_unlock(&shrinker_mutex); +} +EXPORT_SYMBOL(unregister_shrinker_delayed_initiate); + +void unregister_shrinker_delayed_finalize(struct shrinker *shrinker) +{ + if (!shrinker->nr_deferred) + return; synchronize_srcu(&srcu); kfree(shrinker->nr_deferred); shrinker->nr_deferred = NULL; } +EXPORT_SYMBOL(unregister_shrinker_delayed_finalize); + +/* + * Remove one + */ +void unregister_shrinker(struct shrinker *shrinker) +{ + unregister_shrinker_delayed_initiate(shrinker); + unregister_shrinker_delayed_finalize(shrinker); +} EXPORT_SYMBOL(unregister_shrinker); #define SHRINK_BATCH 128