From patchwork Wed Dec 11 15:40:28 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Frederic Weisbecker X-Patchwork-Id: 13903666 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 114EEE7717D for ; Wed, 11 Dec 2024 15:41:27 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 8E8706B009D; Wed, 11 Dec 2024 10:41:26 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 897036B009E; Wed, 11 Dec 2024 10:41:26 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 75E4C6B009F; Wed, 11 Dec 2024 10:41:26 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 536A06B009D for ; Wed, 11 Dec 2024 10:41:26 -0500 (EST) Received: from smtpin27.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay06.hostedemail.com (Postfix) with ESMTP id 0B3AFAF331 for ; Wed, 11 Dec 2024 15:41:26 +0000 (UTC) X-FDA: 82883091564.27.70D6BF5 Received: from dfw.source.kernel.org (dfw.source.kernel.org [139.178.84.217]) by imf11.hostedemail.com (Postfix) with ESMTP id 202CD40026 for ; Wed, 11 Dec 2024 15:41:02 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=sCvgr+yk; spf=pass (imf11.hostedemail.com: domain of frederic@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=frederic@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1733931665; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=i/KBpelLVH+E3LXTlfnW5i5EhTJMAPzaoIzAqkWJmvE=; b=KYTsxj+EzsDWsLMKTYUndhuCmppaZWS48u2XVLI2cL4/g6xt88SCYE4cZvQaPSCc075+7v JQ23XLlgNieQoNdq7PiXUYLONKxySTwipwu+1gyGmzfYfwKaqMsbI/Hn1nUXXfWm+gxNNn 19EXPtx4Kje+QVvfiAnRvU1o5U8W67Q= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b=sCvgr+yk; spf=pass (imf11.hostedemail.com: domain of frederic@kernel.org designates 139.178.84.217 as permitted sender) smtp.mailfrom=frederic@kernel.org; dmarc=pass (policy=quarantine) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1733931665; a=rsa-sha256; cv=none; b=SK3vZegeGEIvtj4RXfGoXG/lBYUZ6MBv7mNWc8oGYYvV3YDeOBvopKu4BpSdByIr9MJUOR qKgJLl1iO/hTsM5dC64XDwPgVKUf1ZrJflMkrvU37C64hRvWksgRrk4jQTZpNUAr2Gee8I bJwpbKY3FdOsSfSgxTuy0hruYmtLp2c= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by dfw.source.kernel.org (Postfix) with ESMTP id 3CED45C6335; Wed, 11 Dec 2024 15:40:40 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9FF31C4CEDE; Wed, 11 Dec 2024 15:41:18 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1733931681; bh=wfa26vkbMku7mDNG8fnP6q/jOJVhfATHz/uHwN2VjCk=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=sCvgr+ykc+LJbnVbi4/G2Kcv66f8o+lWtDiEYD0vWiLjOhwMWqw1PW7qvoHMVme6q i17QdKAQUXlCCGJeSbefpaPSdF7G4LKkvuYkDNxOOP+8modoCX82sy1ej+nExxiqQD e5X7Mcv9g4D7gc4XeRCWD8Fsd44tIBn9TnbjNsAeXIx8xZsAmTI9ueqPgrPpnvf6CR TT98zadKaIevzUYs6pgENEUtiOq+ZAbQ45ZeITExF8L+xJTbvHM0s09tpFA8MMlWpI xKAckKYHpXsmknvNRa4HgElMoROrJxnd0OkfT4OpGpZh6IL4vfxgz/wmUn3DF6HARE sCD91CxFb17Ew== From: Frederic Weisbecker To: LKML Cc: Frederic Weisbecker , Andrew Morton , Kees Cook , Peter Zijlstra , Thomas Gleixner , Michal Hocko , Vlastimil Babka , linux-mm@kvack.org, "Paul E. McKenney" , Neeraj Upadhyay , Joel Fernandes , Boqun Feng , Uladzislau Rezki , Zqiang , rcu@vger.kernel.org Subject: [PATCH 15/19] kthread: Implement preferred affinity Date: Wed, 11 Dec 2024 16:40:28 +0100 Message-ID: <20241211154035.75565-16-frederic@kernel.org> X-Mailer: git-send-email 2.46.0 In-Reply-To: <20241211154035.75565-1-frederic@kernel.org> References: <20241211154035.75565-1-frederic@kernel.org> MIME-Version: 1.0 X-Rspamd-Queue-Id: 202CD40026 X-Rspamd-Server: rspam12 X-Stat-Signature: wb54ew96ut6meb481anapiu7r81cgo1i X-Rspam-User: X-HE-Tag: 1733931662-395793 X-HE-Meta: U2FsdGVkX1/NztTD6KxfS0aWxI6yV55aMxeBdBP04fiy19CppXEvWtd1d5brXnN0XJmIc6jcv1b45LlbuVsvCJnXYYdCDtxpRqN0UzZ9C4gQlPsi02BDa391hXSxPxOAwhoFkHsqNf7gzoBiEIw4deFl5Sn0eT4wXLMJDrlCe0TsD6kAMai+lFDT7Z76lDoIDH37FSq2yTkzBhyEaapn4t6KXJk58seybzaVXoXKBgAN9/JZ0crWxyYGjXQ61CKii4Gs3Kr4qE8dft8gpN4/nzBA+ZrkP7q7EPkScAmaFDh5BJgazR45qut4FsFINFT0piwQg5cBIdSGpG5Ds+kPvCAABj8rKNaWpr+/4ZZ+HUTH0B1hTiKO9LivZKCd/8xe3ciYVXJqYVVerllS2lk8UKQxKW9NMVMCRnjFG1d/TTYzwS7XC8D2LczOmbUPRWeTb2vzGvaUvuah7b/9efd19IOq3EoY0KKYsAfWoqDTcZvAuG4UPU0SOCwyxyaQZg7wl6CcPJVCOBRDZsxh1txJTYYOoyZuHOkbeSCmft3IVnnoYGR5SwrWv3Ph9R+Dt9/4F34HqsnXVe/a3Z7oYaj2nDUWBpuu3zXfzpskuO5yBQFbxEKaMZwMFtFi2ukR4PuszPRPQBdTZzjh1Pbhv+NbkpaYD+GJdTviHvsXQsNlPcw2hyrGXrigLejJqLao5FzbkzoEP4uY6wMMz9f+S7WjBvkMqecjqSZjQAhODOXpL91Spf0G4LifcgAqch80ajsWgcQBrrRMkYPQ982ou7sOMFjvVJhTkFEfOa7S5mycgy1rnHQBWtHMR4OzDiV614ZCmizcgjyjtRuQr0xokmc3nlUqo6rs+rd97c6MXoh3bENtmt1n/jxuFVA+wkp+NwzqxnNpqlQBSijDZaycmMwrtsBCKdtH1c/+NPmvtQEPLTOJpCAlfWIoepsT969kJuQ5bHoHW+b7cxTH5boBmOn fm/HeYOc BGiL+U/o/BB6fvwZcuKrEK9BBDZD0QsZ6tvjcBcNDgMw1ujgDCelvQT+cS6zETIP62UyWVuXJEitAYhjPbin5QFwhPQwnb54Vv0eyGws4OhFO7BVm6Nj6S+diSg8GG86AJm5x04W7DexuNkkhPCJEQhNhFBvF6fncP7+KkV7Zojjjo9GZxKyZ8HeV/E2tPPbt128cybqSDf4WeFJzIOURuEnusvxoY9KQ207k88QPZDtwI+FZW7R1gs//n4a4viC6cxVfrpXZLbm7nx6fvfdxJzDwVfFcI4JsVD+o+fiByoUVhzqRkMII2Nyybg== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Affining kthreads follow either of four existing different patterns: 1) Per-CPU kthreads must stay affine to a single CPU and never execute relevant code on any other CPU. This is currently handled by smpboot code which takes care of CPU-hotplug operations. 2) Kthreads that _have_ to be affine to a specific set of CPUs and can't run anywhere else. The affinity is set through kthread_bind_mask() and the subsystem takes care by itself to handle CPU-hotplug operations. 3) Kthreads that prefer to be affine to a specific NUMA node. That preferred affinity is applied by default when an actual node ID is passed on kthread creation, provided the kthread is not per-CPU and no call to kthread_bind_mask() has been issued before the first wake-up. 4) Similar to the previous point but kthreads have a preferred affinity different than a node. It is set manually like any other task and CPU-hotplug is supposed to be handled by the relevant subsystem so that the task is properly reaffined whenever a given CPU from the preferred affinity comes up. Also care must be taken so that the preferred affinity doesn't cross housekeeping cpumask boundaries. Provide a function to handle the last usecase, mostly reusing the current node default affinity infrastructure. kthread_affine_preferred() is introduced, to be used just like kthread_bind_mask(), right after kthread creation and before the first wake up. The kthread is then affine right away to the cpumask passed through the API if it has online housekeeping CPUs. Otherwise it will be affine to all online housekeeping CPUs as a last resort. As with node affinity, it is aware of CPU hotplug events such that: * When a housekeeping CPU goes up that is part of the preferred affinity of a given kthread, the related task is re-affined to that preferred affinity if it was previously running on the default last resort online housekeeping set. * When a housekeeping CPU goes down while it was part of the preferred affinity of a kthread, the running task is migrated (or the sleeping task is woken up) automatically by the scheduler to other housekeepers within the preferred affinity or, as a last resort, to all housekeepers from other nodes. Acked-by: Vlastimil Babka Signed-off-by: Frederic Weisbecker --- include/linux/kthread.h | 1 + kernel/kthread.c | 68 ++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 7 deletions(-) diff --git a/include/linux/kthread.h b/include/linux/kthread.h index b11f53c1ba2e..30209bdf83a2 100644 --- a/include/linux/kthread.h +++ b/include/linux/kthread.h @@ -85,6 +85,7 @@ kthread_run_on_cpu(int (*threadfn)(void *data), void *data, void free_kthread_struct(struct task_struct *k); void kthread_bind(struct task_struct *k, unsigned int cpu); void kthread_bind_mask(struct task_struct *k, const struct cpumask *mask); +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask); int kthread_stop(struct task_struct *k); int kthread_stop_put(struct task_struct *k); bool kthread_should_stop(void); diff --git a/kernel/kthread.c b/kernel/kthread.c index 3394ff024a5a..6bb958a75a0b 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -70,6 +70,7 @@ struct kthread { char *full_name; struct task_struct *task; struct list_head hotplug_node; + struct cpumask *preferred_affinity; }; enum KTHREAD_BITS { @@ -327,6 +328,11 @@ void __noreturn kthread_exit(long result) mutex_lock(&kthreads_hotplug_lock); list_del(&kthread->hotplug_node); mutex_unlock(&kthreads_hotplug_lock); + + if (kthread->preferred_affinity) { + kfree(kthread->preferred_affinity); + kthread->preferred_affinity = NULL; + } } do_exit(0); } @@ -355,9 +361,17 @@ EXPORT_SYMBOL(kthread_complete_and_exit); static void kthread_fetch_affinity(struct kthread *kthread, struct cpumask *cpumask) { - cpumask_and(cpumask, cpumask_of_node(kthread->node), - housekeeping_cpumask(HK_TYPE_KTHREAD)); + const struct cpumask *pref; + if (kthread->preferred_affinity) { + pref = kthread->preferred_affinity; + } else { + if (WARN_ON_ONCE(kthread->node == NUMA_NO_NODE)) + return; + pref = cpumask_of_node(kthread->node); + } + + cpumask_and(cpumask, pref, housekeeping_cpumask(HK_TYPE_KTHREAD)); if (cpumask_empty(cpumask)) cpumask_copy(cpumask, housekeeping_cpumask(HK_TYPE_KTHREAD)); } @@ -440,7 +454,7 @@ static int kthread(void *_create) self->started = 1; - if (!(current->flags & PF_NO_SETAFFINITY)) + if (!(current->flags & PF_NO_SETAFFINITY) && !self->preferred_affinity) kthread_affine_node(); ret = -EINTR; @@ -839,12 +853,53 @@ int kthreadd(void *unused) return 0; } +int kthread_affine_preferred(struct task_struct *p, const struct cpumask *mask) +{ + struct kthread *kthread = to_kthread(p); + cpumask_var_t affinity; + unsigned long flags; + int ret; + + if (!wait_task_inactive(p, TASK_UNINTERRUPTIBLE) || kthread->started) { + WARN_ON(1); + return -EINVAL; + } + + WARN_ON_ONCE(kthread->preferred_affinity); + + if (!zalloc_cpumask_var(&affinity, GFP_KERNEL)) + return -ENOMEM; + + kthread->preferred_affinity = kzalloc(sizeof(struct cpumask), GFP_KERNEL); + if (!kthread->preferred_affinity) { + ret = -ENOMEM; + goto out; + } + + mutex_lock(&kthreads_hotplug_lock); + cpumask_copy(kthread->preferred_affinity, mask); + WARN_ON_ONCE(!list_empty(&kthread->hotplug_node)); + list_add_tail(&kthread->hotplug_node, &kthreads_hotplug); + kthread_fetch_affinity(kthread, affinity); + + /* It's safe because the task is inactive. */ + raw_spin_lock_irqsave(&p->pi_lock, flags); + do_set_cpus_allowed(p, affinity); + raw_spin_unlock_irqrestore(&p->pi_lock, flags); + + mutex_unlock(&kthreads_hotplug_lock); +out: + free_cpumask_var(affinity); + + return 0; +} + /* * Re-affine kthreads according to their preferences * and the newly online CPU. The CPU down part is handled * by select_fallback_rq() which default re-affines to - * housekeepers in case the preferred affinity doesn't - * apply anymore. + * housekeepers from other nodes in case the preferred + * affinity doesn't apply anymore. */ static int kthreads_online_cpu(unsigned int cpu) { @@ -864,8 +919,7 @@ static int kthreads_online_cpu(unsigned int cpu) list_for_each_entry(k, &kthreads_hotplug, hotplug_node) { if (WARN_ON_ONCE((k->task->flags & PF_NO_SETAFFINITY) || - kthread_is_per_cpu(k->task) || - k->node == NUMA_NO_NODE)) { + kthread_is_per_cpu(k->task))) { ret = -EINVAL; continue; }