From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f43.google.com (mail-pj1-f43.google.com [209.85.216.43]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4E55636C9EC for ; Fri, 17 Jul 2026 10:53:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.43 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784285593; cv=none; b=o4pyIKlGGPEDl9Py3sTIgCCcrEFFv1rPyemq+Vg7rx8HMdHWjSDiwtHIZ3w5vwNPfvFGJJavocrMmWoZWPRiLi8gLzf3DSPZDipS0J9AKHjlf08o8fL41MnBbdIjWBCTwKgEmt8wKV59s4a9vnk8aMhzPKt/DTfH4LSSOpuZGeA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1784285593; c=relaxed/simple; bh=aj4WQ2f6QPCfqQMfs8ZwyaFtAcS8IRdZlqjVLDIgIZE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=q9fw6+50Gjy/YuRlL+AyCn5xGw/UqZ2Mm5Z0ZGBj2Bvv5JywwHmZdAkLSp5MGkYTm6THPVIS3CsQN22jFDeZUNy3NhDAfJmW+Acet7odlvqVaPAAauoYMxnoMNCYVRQCnLEzzFMBFuugoVgB0xizwNPFqZRIFnvd8Ucfk9AvT6g= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=QAjGi80J; arc=none smtp.client-ip=209.85.216.43 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="QAjGi80J" Received: by mail-pj1-f43.google.com with SMTP id 98e67ed59e1d1-38df94d4dd8so3100343a91.2 for ; Fri, 17 Jul 2026 03:53:12 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1784285591; x=1784890391; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to:content-type; bh=Qojx+MA+3lPpl/55+mlC2NkwWgpqPsjKb3imDhkRyhg=; b=QAjGi80JHUyPLIyT5VNdCcEyBOFdZC2vNpavfatMiEVFZDhvaWfLykXpnzaaVWQbhs UhM9odNt4+xNMRol34NGN75af+OmJsls/hvzow64KY6L2ij1fLtt7NrJA3kc3bGyjI/I CMTLh/rPiiqxLQbUUH/ca75FEfnv38rdy5ZvSS6KwhaU6PgHWfDYPR/PVwvghKbQcSz4 qbdd1wBluJSSCfzf6CVJX2RaIzMei6BdGm0qgw9Eu0glXUzflx6LWU7KrVJcBpP/zPh2 N+ek9bSC60xqR+1n7Dbl5vpBMGVQCzhiVHAFJgSosP0q4dVJ6K/nBfQBuxyEd8qJh2Ax R3xQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1784285591; x=1784890391; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to:content-type; bh=Qojx+MA+3lPpl/55+mlC2NkwWgpqPsjKb3imDhkRyhg=; b=emECCdwc1muAhJSfqUBL5NYlpbpMQVaaqVLGcnXw3zQ5PDt37rbkeLXJLjohsXrDUO 4eqG7tpbrC/f4urGPmnn3eLlq/MhCBJZL3bAyOns9sm+6AHs72flKVJIDU/4YUVJG2qm S9FU3zPH52QzhAmCLC5ba9XksuPpS8ClnQTFy/bV0AY/z1kBnVRK+ELo9OIKUcBu2pUo mP+hZT4VZup6xSBSDRrYaMUTRmcewJMKcyhL9yE6E9srCXYgsMsOQlFhH5rZgZzU+g8q d9SybdsEWQ1qTs3Zi7EhhwlTFjteDfbv6o8d+yPzL/y7VlNduUHLZ6in+Hz5KB7CuOm4 e9cg== X-Forwarded-Encrypted: i=1; AHgh+Rplsel5zpCvjhwV96/ouk3tCoE8HEoExuYVO213wXHQPgBoaAuzaL4nlQ8nOoXkECsgW9coKZsQESeWZtU=@vger.kernel.org X-Gm-Message-State: AOJu0YxwZiU+j0tazt3lF+hzq3OGW3SYACTzFwCT5oEjVlkQ4/b4wxqg 2JrjLr1WgqNflB1HblFWna1QIgFFoSmjBsaBFcmxJcDwKi77zNCpu33S X-Gm-Gg: AfdE7ckwedyyK0wYG/PhfEvfuVSB0LvUt6e0N2ROa/Q5mxQolgyM6NViOm0BOHdPcX0 5hVpH0KZdeNBWse63xZMMMkgtJN2C9aS4OU7jSp5KRxTJrqkvY1db4y9F062AtJsdU/LsfQRJ4R gzeQ8woQxSSKK3xupXZ1MXyalvFT53A9hvgaGKmpDJpqfk6moUNpQ3Nb9kwbW+tVoBzPBFqsT+f Qgd6//Hfnq03CT7KGUhHGcAPEfX4MCxiYKbSIDpfu+Z/5lx1mlmrU5LMAreIV63BnREPo21ZDx0 plxXvcM2vp59bIInoO76DVNQ59y7JY4di19J+RWoouq0dxjpYxs1e8b1hjC++RbS/K2ijWmyyij lmOSYbhk70Quy4vaLWisCEEMWJZl2X/kSivuIoN4JWaE7bEPkVqJ0uCZVfR0mwVuNvEnDD8MQ3a G4jbXHGb9wlxhPOe/IFQRY/DckoAtfvHIXHLqLdsRqDORb6PDnlT2hmQ== X-Received: by 2002:a17:90b:5344:b0:38e:2e86:ed02 with SMTP id 98e67ed59e1d1-38e4b423596mr2018578a91.14.1784285591442; Fri, 17 Jul 2026 03:53:11 -0700 (PDT) Received: from mi-HP-ProDesk-680-G6-PCI-Microtower-PC.mioffice.cn ([43.224.245.226]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-38e4b0e9bb5sm848181a91.11.2026.07.17.03.53.07 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 17 Jul 2026 03:53:11 -0700 (PDT) From: "zhidao su (Xiaomi)" To: K Prateek Nayak , John Stultz Cc: Peter Zijlstra , Ingo Molnar , Juri Lelli , Vincent Guittot , Dietmar Eggemann , Steven Rostedt , Ben Segall , Mel Gorman , Valentin Schneider , linux-kernel@vger.kernel.org, "zhidao su (Xiaomi)" Subject: [PATCH v3] sched/proxy_exec: Detect cycles in proxy walks Date: Fri, 17 Jul 2026 18:52:59 +0800 Message-ID: <20260717105259.747783-1-soolaugust@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260714152220.4046736-1-soolaugust@gmail.com> References: <20260714152220.4046736-1-soolaugust@gmail.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit find_proxy_task() can keep walking the same blocked_on chain if the chain contains a cycle. This happens with a simple A->B->A mutex deadlock under proxy execution, and can leave the CPU spinning in __schedule() with the rq lock held. Mark each task visited during one proxy walk with the rq's pick sequence. If the walk sees the same task again in the same pick, break the cycle by clearing the blocked_on state at the detection point and deactivating that task. Clear the marker when proxy execution migrates a blocked task, so a later walk on another CPU cannot match stale state. Tested with a PE cycle reproducer in virtme-ng: buggy kernel: vng timed out without returning fixed kernel: WARN_ONCE "sched/pe: deadlock cycle detected" Signed-off-by: zhidao su (Xiaomi) --- Changes since v2: - Drop the proxy-chain depth limit. - Detect cycles anywhere in the proxy walk, not only cycles back to the original donor. - Use a separate per-pick marker instead of overloading blocked_donor. - Clear the marker on proxy-exec blocked-task migration. include/linux/sched.h | 4 ++++ kernel/fork.c | 4 ++++ kernel/sched/core.c | 34 ++++++++++++++++++++++++++++++++-- kernel/sched/sched.h | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/include/linux/sched.h b/include/linux/sched.h index 968b18a7f4702..b83a4e775d736 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -1256,6 +1256,10 @@ struct task_struct { * under preempt_disable(). */ struct task_struct *blocked_donor; +#ifdef CONFIG_SCHED_PROXY_EXEC + int proxy_pick_cpu; + u64 proxy_pick_seq; /* find_proxy_task() seq */ +#endif #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER /* diff --git a/kernel/fork.c b/kernel/fork.c index 13e38e89a1f30..2219cce602c62 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -2242,6 +2242,10 @@ __latent_entropy struct task_struct *copy_process( p->blocked_on = NULL; /* not blocked yet */ p->blocked_donor = NULL; /* nobody is boosting p yet */ +#ifdef CONFIG_SCHED_PROXY_EXEC + p->proxy_pick_cpu = -1; + p->proxy_pick_seq = 0; +#endif #ifdef CONFIG_BCACHE p->sequential_io = 0; diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 2e7cde033a319..3db4e6c2b786a 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -6724,6 +6724,7 @@ static bool try_to_block_task(struct rq *rq, struct task_struct *p, } #ifdef CONFIG_SCHED_PROXY_EXEC + static inline void proxy_set_task_cpu(struct task_struct *p, int cpu) { unsigned int wake_cpu; @@ -6830,6 +6831,10 @@ static void proxy_migrate_task(struct rq *rq, struct rq_flags *rf, deactivate_task(rq, p, DEQUEUE_NOCLOCK); proxy_set_task_cpu(p, target_cpu); +#ifdef CONFIG_SCHED_PROXY_EXEC + WRITE_ONCE(p->proxy_pick_cpu, -1); + WRITE_ONCE(p->proxy_pick_seq, 0); +#endif proxy_release_rq_lock(rq, rf); @@ -6839,14 +6844,14 @@ static void proxy_migrate_task(struct rq *rq, struct rq_flags *rf, } /* - * Find runnable lock owner to proxy for mutex blocked donor + * Find runnable lock owner to proxy for a blocked donor * * Follow the blocked-on relation: * * ,-> task * | | blocked-on * | v - * blocked_donor | mutex + * blocked_donor | blocking primitive * | | owner * | v * `-- task @@ -6874,6 +6879,10 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf) struct task_struct *p; int owner_cpu; + rq->proxy_pick_seq++; + if (unlikely(!rq->proxy_pick_seq)) + rq->proxy_pick_seq++; + /* Follow blocked_on chain. */ for (p = donor; p->is_blocked; p = owner) { /* if its PROXY_WAKING, do return migration or run if current */ @@ -6905,6 +6914,16 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf) return NULL; } + if (READ_ONCE(p->proxy_pick_cpu) == this_cpu && + READ_ONCE(p->proxy_pick_seq) == rq->proxy_pick_seq) { + WARN_ONCE(1, "sched/pe: deadlock cycle detected, pid %d\n", + p->pid); + __clear_task_blocked_on(p, NULL); + goto deactivate; + } + WRITE_ONCE(p->proxy_pick_cpu, this_cpu); + WRITE_ONCE(p->proxy_pick_seq, rq->proxy_pick_seq); + if (task_current(rq, p)) curr_in_chain = true; @@ -6990,6 +7009,14 @@ find_proxy_task(struct rq *rq, struct task_struct *donor, struct rq_flags *rf) */ return proxy_resched_idle(rq); } + + if (READ_ONCE(owner->proxy_pick_cpu) == this_cpu && + READ_ONCE(owner->proxy_pick_seq) == rq->proxy_pick_seq) { + WARN_ONCE(1, "sched/pe: deadlock cycle detected, pid %d\n", + p->pid); + __clear_task_blocked_on(p, NULL); + goto deactivate; + } /* * OK, now we're absolutely sure @owner is on this * rq, therefore holding @rq->lock is sufficient to @@ -9057,6 +9084,9 @@ void __init sched_init(void) raw_spin_lock_init(&rq->cpu_epoch_lock); rq->cpu_epoch_next = jiffies; #endif +#ifdef CONFIG_SCHED_PROXY_EXEC + rq->proxy_pick_seq = 0; +#endif zalloc_cpumask_var_node(&rq->scratch_mask, GFP_KERNEL, cpu_to_node(i)); } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 26ae13c86b699..f63c024d160e8 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -1154,6 +1154,7 @@ struct rq { #ifdef CONFIG_SCHED_PROXY_EXEC struct task_struct __rcu *donor; /* Scheduling context */ struct task_struct __rcu *curr; /* Execution context */ + u64 proxy_pick_seq; /* find_proxy_task() seq */ #else union { struct task_struct __rcu *donor; /* Scheduler context */ base-commit: 04998aa54848f15332202d0bea008d2ca1ed1713 -- 2.43.0