From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756753AbdJPSww (ORCPT ); Mon, 16 Oct 2017 14:52:52 -0400 Received: from mail-io0-f196.google.com ([209.85.223.196]:44386 "EHLO mail-io0-f196.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753141AbdJPSwu (ORCPT ); Mon, 16 Oct 2017 14:52:50 -0400 X-Google-Smtp-Source: ABhQp+RWQgXQL36Jf+MhjuD6B1/1YvwQMESmCkV+cVLlqVTdqBhcrczsqiBhsKswk4fSTmk6Ebqd4Q== From: Leon Yang X-Google-Original-From: Leon Yang < leon.gh.yang@gmail.com > To: Alexander Viro , linux-fsdevel@vger.kernel.org (open list:FILESYSTEMS (VFS and infrastructure)), linux-kernel@vger.kernel.org (open list) Cc: Leon Yang Subject: [PATCH] Batch unmount cleanup Date: Mon, 16 Oct 2017 13:52:16 -0500 Message-Id: <1508179936-15591-1-git-send-email-leon.gh.yang@gmail.com> X-Mailer: git-send-email 2.7.4 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Leon Yang Each time the unmounted list is cleanup, synchronize_rcu() is called, which is relatively costly. Scheduling the cleanup in a workqueue, similar to what is being done in net/core/net_namespace.c:cleanup_net, makes unmounting faster without adding too much overhead. This is useful especially for servers with many containers where mounting/unmounting happens a lot. Signed-off-by: Leon Yang --- fs/namespace.c | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/fs/namespace.c b/fs/namespace.c index 3b601f1..864ce7e 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -68,6 +68,7 @@ static int mnt_group_start = 1; static struct hlist_head *mount_hashtable __read_mostly; static struct hlist_head *mountpoint_hashtable __read_mostly; static struct kmem_cache *mnt_cache __read_mostly; +static struct workqueue_struct *unmounted_wq; static DECLARE_RWSEM(namespace_sem); /* /sys/fs */ @@ -1409,22 +1410,29 @@ EXPORT_SYMBOL(may_umount); static HLIST_HEAD(unmounted); /* protected by namespace_sem */ -static void namespace_unlock(void) +static void cleanup_unmounted(struct work_struct *work) { struct hlist_head head; + down_write(&namespace_sem); hlist_move_list(&unmounted, &head); up_write(&namespace_sem); - if (likely(hlist_empty(&head))) - return; - synchronize_rcu(); group_pin_kill(&head); } +static DECLARE_WORK(unmounted_cleanup_work, cleanup_unmounted); + +static void namespace_unlock(void) +{ + if (!likely(hlist_empty(&unmounted))) + queue_work(unmounted_wq, &unmounted_cleanup_work); + up_write(&namespace_sem); +} + static inline void namespace_lock(void) { down_write(&namespace_sem); @@ -3276,6 +3284,17 @@ void __init mnt_init(void) init_mount_tree(); } +static int __init unmounted_wq_init(void) +{ + /* Create workqueue for cleanup */ + unmounted_wq = create_singlethread_workqueue("unmounted"); + if (!unmounted_wq) + panic("Could not create unmounted workq"); + return 0; +} + +pure_initcall(unmounted_wq_init); + void put_mnt_ns(struct mnt_namespace *ns) { if (!atomic_dec_and_test(&ns->count)) -- 2.7.4