ucounts: move kfree() out of critical zone protected by ucounts_lock
authorMengEn Sun <mengensun@tencent.com>
Fri, 6 Dec 2024 04:13:47 +0000 (12:13 +0800)
committerAndrew Morton <akpm@linux-foundation.org>
Mon, 13 Jan 2025 04:21:00 +0000 (20:21 -0800)
Although kfree is a non-sleep function, it is possible to enter a long
chain of calls probabilistically, so it looks better to move kfree from
alloc_ucounts() out of the critical zone of ucounts_lock.

Link: https://lkml.kernel.org/r/1733458427-11794-1-git-send-email-mengensun@tencent.com
Signed-off-by: MengEn Sun <mengensun@tencent.com>
Reviewed-by: YueHong Wu <yuehongwu@tencent.com>
Reviewed-by: Andrew Morton <akpm@linux-foundation.org>
Cc: Andrei Vagin <avagin@google.com>
Cc: Joel Granados <joel.granados@kernel.org>
Cc: Thomas Weißschuh <linux@weissschuh.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
kernel/ucount.c

index f950b5e59d638d80b73560bba3c189e6bc638354..86c5f1c0bad909c69ca32d7438f2de9c443af9e6 100644 (file)
@@ -164,8 +164,8 @@ struct ucounts *get_ucounts(struct ucounts *ucounts)
 struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
 {
        struct hlist_head *hashent = ucounts_hashentry(ns, uid);
-       struct ucounts *ucounts, *new;
        bool wrapped;
+       struct ucounts *ucounts, *new = NULL;
 
        spin_lock_irq(&ucounts_lock);
        ucounts = find_ucounts(ns, uid, hashent);
@@ -182,17 +182,17 @@ struct ucounts *alloc_ucounts(struct user_namespace *ns, kuid_t uid)
 
                spin_lock_irq(&ucounts_lock);
                ucounts = find_ucounts(ns, uid, hashent);
-               if (ucounts) {
-                       kfree(new);
-               } else {
+               if (!ucounts) {
                        hlist_add_head(&new->node, hashent);
                        get_user_ns(new->ns);
                        spin_unlock_irq(&ucounts_lock);
                        return new;
                }
        }
+
        wrapped = !get_ucounts_or_wrap(ucounts);
        spin_unlock_irq(&ucounts_lock);
+       kfree(new);
        if (wrapped) {
                put_ucounts(ucounts);
                return NULL;