From nobody Tue Jun 16 11:27:42 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96C4B37CD5C for ; Sun, 19 Apr 2026 13:27:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776605226; cv=none; b=nj/UisZ254/qX1/guC6Cu+06Sl/ggQSQzPKnZRaw5KaS0vsMPq/ltaApV+xGuZcPIxtjhwH3UE1NXgBeH32FmMp+enx29gAnS0J1ptl2DgHhUu0vyfLnfpe317nNWbZzEfI/BElxfw+K559waM39GKoSp5F/0wf7TLdJFysSWPU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776605226; c=relaxed/simple; bh=waVur1s1NbhGAVdXbYgap1Gr/DCzt5p7sIh5A4kXf1s=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=NoQvsH0EKvvNk34IJdjCk1kseoEzRKDa0gf8BVnylZRla22JuQkl+iDocQdrgzKoWtCr2cV7IUt5R83Kh4qNeAkQo+gNPw37Y4qWI51YwDi44LDtiW3twEkvqMl9pY9BMhC30cKn715N9fcdGtrgzBhH0bM6bAukPtSN0ldmKTg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=Gcqy66JI; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=hn90K3it; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="Gcqy66JI"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="hn90K3it" Received: from pps.filterd (m0279873.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 63J6bhoh2470400 for ; Sun, 19 Apr 2026 13:27:03 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=U/luz5L2c9u 5OjLtskUToxTHzZy4xt3r13Mne57avzs=; b=Gcqy66JIO+iH8qeVT/NoT6hls2P CW369jyFfHBkH+/HfWik701/L6jHHYGdgsTAjSk8JlLdxI/iAh5unlkYqRf9c5s4 +vg9pKT6j2a0KGdbSNENg7XESxOe7S/bGEUMWyRbS2F1/vORYqiBwvlRsR0G9ir0 1hoMYhzsZGQ+7FPc2GrL0DKy+fDGt3Fs9SUlyB4lXt8M6nX803SrJNtwAy0X85iI 7v2jf+/ek9XS9PHZW2gNJfYdqVjiH2dqViW41Bn/U3HLAYXk/P7T8m+cAaREmkTD b5KDC9/JYQCScbwjOACTcpue4SDOjQjMYoGFeOHcPTtw1cD/oK4cYMY+lKw== Received: from mail-pj1-f70.google.com (mail-pj1-f70.google.com [209.85.216.70]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4dkyanjv16-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sun, 19 Apr 2026 13:27:03 +0000 (GMT) Received: by mail-pj1-f70.google.com with SMTP id 98e67ed59e1d1-35da97f6a6dso1912370a91.0 for ; Sun, 19 Apr 2026 06:27:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1776605222; x=1777210022; 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; bh=U/luz5L2c9u5OjLtskUToxTHzZy4xt3r13Mne57avzs=; b=hn90K3it7sQGldccEH0CLvrsGfebFSHm/Qu7+mH8yqhz1/u7LWzVaEKuJsFmzthclf XZJXMpj0E28WPVlLX5AOF5sX0aBxfMtYOh0n5dHcBc78mnQDdAMtDNZ86aJWZltg5GSP 6KcM5k88He7sx7RRCUVHsHQSQIZhN3vQneHGgUntH0BaWyvRtj5LqunJyMZ2dEVLJYdX 2WNZcNpswKFkLhPBPKefsDZPYY6x9laqSQUvjVkSl0M4ku/zf55CvLQIrwOeANUdQmKK MgJinlQsTfJ5JowNHoqalKSu5ouCZsPcilcCn8p1xDxnuXFpBzlyG2wwynkLm7XN40DP XjTQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776605222; x=1777210022; 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; bh=U/luz5L2c9u5OjLtskUToxTHzZy4xt3r13Mne57avzs=; b=HAYjhd7Hqqvv7m7+fLVpWG1sw17NEj4cQbbIh+5SB0J0oceegjeVtM8xzCkq17aQFL VXpNT1JArbKA0bZ7ptTsdK6yp8Y6RDxiqfuSvCY4n7yU0MyM5lB+b1+oMUnc2DzD+cvA moy9jngB30k11ecZaXEXyRpIAJK11Svxu2/0NH8Bdg0m/11jSksywP+4EypfDO0mFUxy 32VMUffTDb6MYcwzNJLiArnVoNrD0OQIwukamKSfOcp4tPx34s4z4bwqR8Nm7WCYc0Na VBBZzvzKkQ3cHGle60jQ7MV67W3CniaYB1gt0vCRSx3vWoWHoPSDAmTlU3kIGZZWwSUl MTyQ== X-Forwarded-Encrypted: i=1; AFNElJ9V6wtiOocjAzJTiisqPkcgDiVaUjnLU5SP4esfuTb9yb3bkHe4oAXpvi7ksoLz/dNGIbCmItIIVfZBpsA=@vger.kernel.org X-Gm-Message-State: AOJu0YzAOpiQDxqE4TkT2PlcWivgUUTtfnBndc6NZGGhiNAE7lgOuF10 PmWmythZ8OBMbUWgR507vUIRT4GM1vTGdnn2mCcXXqgaJA0UB0XU3724eZP6dAs8vh4WgeF0UKY DwFC/lN1mtKiPYH08vkWyhBxSy1v+a7XwvA05Y37uF8Sq0KEniJZzNFdqZ3w7B9JzkDA= X-Gm-Gg: AeBDiesgJNKPvmbAfv9cyxNzb2YiKcX1+ad7XQXuzN5tfPH8CWHYWobfAOsrSnX6X/j KaDZ0mqGLtL4906j5Akd7eVzBG/NvduB5Hjsm4ou7UV68/N8WM5cCZwOSOqxMXGM9wmpIcpgdgx Q3apKnVjHu6CpDg6ucbxQh8WvQk/09ZyP9B3RchOL6W6Hg0wq7YtikOkOEfs+z2g+t8KVegFCN6 Ocm13m436vsFG4QTvuZCm9u+Q1eHOnu7vehBmPtUgehTdXFylZdDK+juLNEE//ugX209Y3VNq+K omrnXfMqOZ2ZgzxYJRTVNG1lX6ZoLttwNurNSfQZGLBQOF6FvMoJ+zaoKM65fVn0+sCbZq6pFD1 9Cw4NHzZ5WiGIUXJCHnIzRf1BUGx0F5JuyBj4Hj0oSIA0QDrnf7WvQK57vEv7wTn33fvhx3w5km Iwdp8+mgc76STM6vgSQZwoLt8= X-Received: by 2002:a17:90b:5185:b0:35c:29ba:bf92 with SMTP id 98e67ed59e1d1-361403d5988mr10806655a91.5.1776605222427; Sun, 19 Apr 2026 06:27:02 -0700 (PDT) X-Received: by 2002:a17:90b:5185:b0:35c:29ba:bf92 with SMTP id 98e67ed59e1d1-361403d5988mr10806626a91.5.1776605221921; Sun, 19 Apr 2026 06:27:01 -0700 (PDT) Received: from zhonhan-gv.qualcomm.com (tpe-colo-wan-fw-bordernet.qualcomm.com. [103.229.16.4]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3613fbbb4f9sm4010342a91.6.2026.04.19.06.26.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Apr 2026 06:27:01 -0700 (PDT) From: Zhongqiu Han To: rafael@kernel.org, viresh.kumar@linaro.org Cc: venkatesh.pallipadi@intel.com, davej@redhat.com, trenn@suse.de, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, zhongqiu.han@oss.qualcomm.com Subject: [PATCH v3 1/2] cpufreq: governor: Fix data races on per-CPU idle/nice baselines Date: Sun, 19 Apr 2026 21:26:53 +0800 Message-ID: <20260419132655.3800673-2-zhongqiu.han@oss.qualcomm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com> References: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-GUID: oRshgfq6nEQQU6eUK45wSywpaFoIOT4Q X-Proofpoint-ORIG-GUID: oRshgfq6nEQQU6eUK45wSywpaFoIOT4Q X-Authority-Analysis: v=2.4 cv=SNFykuvH c=1 sm=1 tr=0 ts=69e4d827 cx=c_pps a=0uOsjrqzRL749jD1oC5vDA==:117 a=nuhDOHQX5FNHPW3J6Bj6AA==:17 a=A5OVakUREuEA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=rJkE3RaqiGZ5pbrm-msn:22 a=EUspDBNiAAAA:8 a=EhOh3lww-dzmNHTOE2sA:9 a=mQ_c8vxmzFEMiUWkPHU9:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDE5MDE0MyBTYWx0ZWRfX+fZdveW4c9CF QYGfUCECPkXjCkLhonj1tM8nUVUwtk4jf6+8Ing3DtSmnukvJkFMaQ2dA7RFKnVWEkvi0YQ1s39 ygE8lLY+XhOjNDS2CEp0E0zhbbIh/cCdOsM386t0zWzuDB4Gx06QcWhlHn1i1TiomSIntE4pq7U BuY+rNjtuv3B7OxgPvojUbX6m7xZ4WdhuHyH1KoZimxgdRmrrM7k9yRK/2yUyu5JnwYnlIC7KZI 8ps779N4bdjRwJtQMFyUOipc2WutdIkjINpceluyTi0KhBPD90zVmAPA7sxz99BkZ55fr+2tbdz v7GXR4l/OyjW+4kcogSMSmTKJfWXqJFsvxWEho/VRCllnxN3bOhzxKPjar3aMNHgCV0gElL8wF1 o7Hdfdv0/2JMaY2w/iidk3afuJIVW7elrqJgO+kV2mgmuT52F45AOSFYCpd1fDr/FFGtB2SvR1V LDR0y7/YjADt/jtb4kQ== X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-19_04,2026-04-17_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 clxscore=1015 impostorscore=0 phishscore=0 adultscore=0 malwarescore=0 bulkscore=0 suspectscore=0 lowpriorityscore=0 priorityscore=1501 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2604070000 definitions=main-2604190143 Content-Type: text/plain; charset="utf-8" gov_update_cpu_data() resets per-CPU prev_cpu_idle for every CPU in the governed domain, and conditionally resets prev_cpu_nice when ignore_nice_load is set. It is called from sysfs store callbacks (e.g. ignore_nice_load_store) which run under attr_set->update_lock, held by the surrounding governor_store(). Concurrently, dbs_work_handler() calls gov->gov_dbs_update() (which calls dbs_update()) under policy_dbs->update_mutex. dbs_update() both reads and writes the same prev_cpu_idle / prev_cpu_nice fields. The potential race path is: Path A (sysfs write, holds attr_set->update_lock only): governor_store() mutex_lock(&attr_set->update_lock) ignore_nice_load_store() dbs_data->ignore_nice_load =3D input gov_update_cpu_data(dbs_data) list_for_each_entry(policy_dbs, ...) for_each_cpu(j, ...) j_cdbs->prev_cpu_idle =3D get_cpu_idle_time(...) /* write */ j_cdbs->prev_cpu_nice =3D kcpustat_field(...) /* write */ mutex_unlock(&attr_set->update_lock) Path B (work queue, holds policy_dbs->update_mutex only): dbs_work_handler() mutex_lock(&policy_dbs->update_mutex) gov->gov_dbs_update(policy) dbs_update() for_each_cpu(j, policy->cpus) idle_time =3D cur - j_cdbs->prev_cpu_idle /* read */ j_cdbs->prev_cpu_idle =3D cur_idle_time /* write */ idle_time +=3D cur_nice - j_cdbs->prev_cpu_nice /* read */ j_cdbs->prev_cpu_nice =3D cur_nice /* write */ mutex_unlock(&policy_dbs->update_mutex) Because attr_set->update_lock and policy_dbs->update_mutex are two completely independent locks, the two paths are not mutually exclusive. This results in a data race on cpu_dbs_info.prev_cpu_idle and cpu_dbs_info.prev_cpu_nice. Fix this by also acquiring policy_dbs->update_mutex in gov_update_cpu_data() for each policy, so that path A participates in the mutual exclusion already established by dbs_work_handler(). Also update the function comment to accurately reflect the two-level locking contract. Additionally, cpufreq_dbs_governor_start() initializes prev_cpu_idle using io_busy read from dbs_data->io_is_busy without holding policy_dbs->update_mutex. A concurrent io_is_busy_store() can update io_is_busy and call gov_update_cpu_data(), which writes prev_cpu_idle with the new value under the mutex. cpufreq_dbs_governor_start() then overwrites prev_cpu_idle with the stale io_busy value, leaving the baseline inconsistent with the tunable. Fix this by reading io_busy inside the mutex. The root of this race dates back to the original ondemand/conservative governors. Before commit ee88415caf73 ("[CPUFREQ] Cleanup locking in conservative governor") and commit 5a75c82828e7 ("[CPUFREQ] Cleanup locking in ondemand governor"), all accesses to prev_cpu_idle and prev_cpu_nice in cpufreq_governor_dbs() (path X), store_ignore_nice_load() /io_is_busy_store() (path Y), and do_dbs_timer() (path Z) were serialised by the same dbs_mutex, so no race existed. Those two commits switched do_dbs_timer() from dbs_mutex to a per-policy/per-cpu timer_mutex to reduce lock contention, but left path Y (store) still holding dbs_mutex. As a result, path Y (store) and path Z (do_dbs_timer) no longer shared a common lock, introducing a potential race on prev_cpu_idle/prev_cpu_nice between path Y (store) and dbs_check_cpu(). Commit 326c86deaed54a ("[CPUFREQ] Remove unneeded locks") then removed dbs_mutex from store_ignore_nice_load()/io_is_busy_store() entirely, introducing an additional potential race between path Y (now lockless) and cpufreq_governor_dbs() (path X, still holding dbs_mutex), while the race between path Y and path Z remained. Fixes: ee88415caf736b ("[CPUFREQ] Cleanup locking in conservative governor") Fixes: 5a75c82828e7c0 ("[CPUFREQ] Cleanup locking in ondemand governor") Fixes: 326c86deaed54a ("[CPUFREQ] Remove unneeded locks") Signed-off-by: Zhongqiu Han --- drivers/cpufreq/cpufreq_governor.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_g= overnor.c index 86f35e451914..fc6f705c5a9c 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -90,7 +90,8 @@ EXPORT_SYMBOL_GPL(sampling_rate_store); * (that may be a single policy or a bunch of them if governor tunables are * system-wide). * - * Call under the @dbs_data mutex. + * Call under the @dbs_data->attr_set.update_lock. The per-policy + * update_mutex is acquired and released internally for each policy. */ void gov_update_cpu_data(struct dbs_data *dbs_data) { @@ -99,6 +100,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data) list_for_each_entry(policy_dbs, &dbs_data->attr_set.policy_list, list) { unsigned int j; =20 + mutex_lock(&policy_dbs->update_mutex); for_each_cpu(j, policy_dbs->policy->cpus) { struct cpu_dbs_info *j_cdbs =3D &per_cpu(cpu_dbs, j); =20 @@ -107,6 +109,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data) if (dbs_data->ignore_nice_load) j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NIC= E, j); } + mutex_unlock(&policy_dbs->update_mutex); } } EXPORT_SYMBOL_GPL(gov_update_cpu_data); @@ -527,8 +530,9 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *p= olicy) =20 sampling_rate =3D dbs_data->sampling_rate; ignore_nice =3D dbs_data->ignore_nice_load; - io_busy =3D dbs_data->io_is_busy; =20 + mutex_lock(&policy_dbs->update_mutex); + io_busy =3D dbs_data->io_is_busy; for_each_cpu(j, policy->cpus) { struct cpu_dbs_info *j_cdbs =3D &per_cpu(cpu_dbs, j); =20 @@ -541,6 +545,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *p= olicy) if (ignore_nice) j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE= , j); } + mutex_unlock(&policy_dbs->update_mutex); =20 gov->start(policy); =20 --=20 2.43.0 From nobody Tue Jun 16 11:27:42 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C8745350D58 for ; Sun, 19 Apr 2026 13:27:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776605228; cv=none; b=qcLVVYDChin2MMCtk6DuAsuzus+tDMEYMKo9Hc2+Lh6A7h7HLqcGzMjEUBVj1n7b64pC+uOeYjkwZe+7yhxMHF386FJ4aWUAEIiSax2MKmIzN0PkJjB6xXrlVxh/ixqNbX27XTLqLYRPf2p6BMZ/y0pr+KDjAsKGQhwRI8FltSw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1776605228; c=relaxed/simple; bh=SqYYwagzKgUXaXdUUT/mLpbwszzQTSsSb/97J17FTjA=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=bIB3TAI42fS8kcFG6gBbQ4Fpl1xOm5tTg7itL12nlr/nyGExVEZOqc8bxHRaclmnLtgJ2Jf2Ey1bbDkBdF62SSW8zhkcNYGMaCbfxcgZEJD0vYJtXAPZxqH9OUiMCxW4kT9eC34aKMID2I1/yvgKNXuXUPzCnozgJct45Y4qTSk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=l9QbBgRr; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=hmK3kouW; arc=none smtp.client-ip=205.220.168.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="l9QbBgRr"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="hmK3kouW" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 63J899CF2798243 for ; Sun, 19 Apr 2026 13:27:06 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:in-reply-to:message-id :mime-version:references:subject:to; s=qcppdkim1; bh=jlG38YObrOd rmclhtB1ZdTwbzfWyw6aRM/BZaBhSwgg=; b=l9QbBgRrPvt4/zhBfsYtpP3g4pI yyVbcu9mBvoLGPUFyff9c0hgtKMSktrTfkAQRs2Ru+noMlTyIRfTuUQUtNKcWdn2 4MWJXTMBoJHNaYxcedKZwwg5dAu50fxXWqSflDb4kNqnnLkCdy9/JQjm4CwY9eaI YZsFay5pHiw/b0LN+ueqfI4jPMNErm5zD9F4Jp5l99DIk6gvNQoRi1yFzq1A+xtJ x0c3xGig7IAgjB0GFx1VvQfiPmMqmBRL88+qK4GCItempovFt/DYUCYbuvmBLRq7 Ix2k9z4UUaiVV932kcxSzCy32hbOBfe5taGkfD2+M6HlzyWmqrxHnILnDGQ== Received: from mail-pj1-f72.google.com (mail-pj1-f72.google.com [209.85.216.72]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4dm261tjt8-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Sun, 19 Apr 2026 13:27:05 +0000 (GMT) Received: by mail-pj1-f72.google.com with SMTP id 98e67ed59e1d1-35e56ed5d5bso3515013a91.0 for ; Sun, 19 Apr 2026 06:27:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1776605225; x=1777210025; 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; bh=jlG38YObrOdrmclhtB1ZdTwbzfWyw6aRM/BZaBhSwgg=; b=hmK3kouWui0nu7teHj50NcJRwX50NISb05/Kljs03r7wdSTVUxqz0EEM7acUlpXJ0/ wCjCh2ew/IdTDn9S9KTgLOTxtON6+6xtrqp+ImuNxhH6tZqS/7M5XRi4uxwOK4rk5k/s pZv9Wb5mSAT0Z7IcTM4wgYA6V6x4xEtmcSHHyGX51ms2ZbvtRhFFDbk4arUUDjPoVSF+ gnjEsYHNQExGjcGpSRcaxBomqIfi2dbBboCEqBi3G4dCajEz2Ol8CdzPh9lPEqelTGez WOdtcHtbjUeDu9keTIYDnTu2V8ZTirwliOvIiZjB4Xl7fRsbwpN3BIYO+VFyKQo8hJqx Y4cA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1776605225; x=1777210025; 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; bh=jlG38YObrOdrmclhtB1ZdTwbzfWyw6aRM/BZaBhSwgg=; b=Or6zjVjXU1c18WDW430180uC5UMh5zouTNow3BZ2pFn8bVnCRLqDwVmNXSEUXW+fCg 75v04RTg5A2VTLgwJWAPyz4cYrBTjkQrfO9IAsniUUJqzHl931Ek0dMgAO0rClz7pwy3 T1751CJlKtwJG9M2KIhQlb9YRMMGNdfVP+XSDSbKW/mWVuT3hi187cjH5245LRszftge b44OT4EcBPDaeHc64mQKGRB86Kuw4CMxf8zzeHAS0hKWM1FdltE9w1Un33MRvw6b6C1J 3WVF+piMmZuaxDc0tKcu0Bjah1sNR1h8OdAHWGWLcYIUOxsT03DwC6/yxTmz/1R/gXLK OI7Q== X-Forwarded-Encrypted: i=1; AFNElJ/i0t337NGuNgRWVdnqrZ8/vMQeUOUmR9xisEAFIqype5izvwotrAPmAymoIvULBQvkRpxp6Wc0SBuomQU=@vger.kernel.org X-Gm-Message-State: AOJu0YwzaJStChGfQJRq5nRI8bcX0ZB+1vpjtlhAUSPm8J+vk9SGzvhb 323K3m0aosuQAY+Z/CLRwQl1OG6dXjZ/HTqCxZbUVgPTdzeI1gtIbJC7lCQbuJkuPGDrVLOIp/Z qqbyxjOsgbvtHX+7PNrVehhf02t3bEbjLk8asUHcpdZCb3N2JJCLV+GnBHUlvLko872Q= X-Gm-Gg: AeBDieuOMpchUBJrxpjDl7dRIjENbCEMd1R53hRJy+bWxJVEarRYa/HV+qtcrcHanJZ +dGdF/t0iOVwMQj8NTBmo6AIGzQKcEyEgDTLRs5Y/kZnixfcu3Un8BlfZTeR8t6F22w177a2PPK lrswewdjHwBja5G/gcJAb/KRZ+s+AwON6QL6IRI8kLBjK7m+Tu0i/mzrwC6lDNXJ9lNd3GO8pRm NyExEyfbcRqg2Q9NfNed0+unmxSP86JVprquc6kO60wGfmtrupTvP9RH53lSTcbDCeak1SmjPrQ 2Ggki3uWJE3049TjH6n3a+0aKHk4lC8yI89aqctPfLy1Kh3PlO7JvTWk+7vKDmuRkOPxb9br7fa TjykkSewOtdWruFjwSFpIU1z+gabdg+LaBj6xNswyC1kqbaKz6t7DXz8tQpSXi+icM74RYhBmzq ksZXGfgpxW6SciLa8prJZppFg= X-Received: by 2002:a17:90b:4b83:b0:356:21e9:73ff with SMTP id 98e67ed59e1d1-361402ebfebmr8081197a91.11.1776605225179; Sun, 19 Apr 2026 06:27:05 -0700 (PDT) X-Received: by 2002:a17:90b:4b83:b0:356:21e9:73ff with SMTP id 98e67ed59e1d1-361402ebfebmr8081174a91.11.1776605224617; Sun, 19 Apr 2026 06:27:04 -0700 (PDT) Received: from zhonhan-gv.qualcomm.com (tpe-colo-wan-fw-bordernet.qualcomm.com. [103.229.16.4]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3613fbbb4f9sm4010342a91.6.2026.04.19.06.27.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sun, 19 Apr 2026 06:27:04 -0700 (PDT) From: Zhongqiu Han To: rafael@kernel.org, viresh.kumar@linaro.org Cc: venkatesh.pallipadi@intel.com, davej@redhat.com, trenn@suse.de, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, zhongqiu.han@oss.qualcomm.com Subject: [PATCH v3 2/2] cpufreq: governor: Fix stale prev_cpu_nice spike when enabling ignore_nice_load Date: Sun, 19 Apr 2026 21:26:54 +0800 Message-ID: <20260419132655.3800673-3-zhongqiu.han@oss.qualcomm.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com> References: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDE5MDE0MyBTYWx0ZWRfX+2lrmebKKpo6 6JpYZIcBJQ1J4oS0151gEWv/VJCSYUsAcHaR6+jLikdI/HuispR9vKnRMZ+O8QkqtMmkAS04u7m cECvFgjIvfonndP0nPcCV4lbNJtSKIw6VG7O6Dz8D11rOFoPgCPk9M3bL8WFq3yde+ltiZ1qycf jiTqk8vNXQhFnhV+NR2qcc0ZUjPkFLnOb/XTZiS0EL4mHgj4J3Wq4yuiIO+b87pRLZ26a1bVfV9 LWCjViFfNQloZtWv7QbHK6gJlitDAxpdZG0JpOOE/ETmIVsmz9nSvFGOZFj8IMyKrJ7YVr0HSjc wRNoj85MrEwHkwUEx5zqaM+KY3ahS9NhH4x66P65LwfGElfV6f6Ls+vYSzF4ACv+NA1fuPk4xOd MtsuJhF/VunveAyzV0v6IanRo+qdamevPjF5vsddAeowDIB6wuqFsahoE1Luhd/6dAZUPO+iMfv 9fv4HIjU/EqR1sHN1uQ== X-Authority-Analysis: v=2.4 cv=dcywG3Xe c=1 sm=1 tr=0 ts=69e4d82a cx=c_pps a=RP+M6JBNLl+fLTcSJhASfg==:117 a=nuhDOHQX5FNHPW3J6Bj6AA==:17 a=A5OVakUREuEA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yOCtJkima9RkubShWh1s:22 a=EUspDBNiAAAA:8 a=RougvbfpsDdIUb9cXJ0A:9 a=iS9zxrgQBfv6-_F4QbHw:22 X-Proofpoint-ORIG-GUID: EH3leKZ8fP-sjJtCnZH4r1L-c314nX1P X-Proofpoint-GUID: EH3leKZ8fP-sjJtCnZH4r1L-c314nX1P X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-19_04,2026-04-17_04,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 adultscore=0 bulkscore=0 clxscore=1015 impostorscore=0 lowpriorityscore=0 suspectscore=0 phishscore=0 malwarescore=0 priorityscore=1501 spamscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2604070000 definitions=main-2604190143 Content-Type: text/plain; charset="utf-8" When ignore_nice_load is toggled from 0 to 1 via sysfs, dbs_update() may run concurrently and observe the new tunable value while prev_cpu_nice still holds a stale baseline, producing a spurious massive idle_time that results in an incorrect CPU load value. The race can be illustrated with two concurrent paths: Path A (sysfs write, holds attr_set->update_lock): governor_store() mutex_lock(&attr_set->update_lock) ignore_nice_load_store() dbs_data->ignore_nice_load =3D 1 /* (A1) */ gov_update_cpu_data(dbs_data) mutex_lock(&policy_dbs->update_mutex) /* (A2) */ j_cdbs->prev_cpu_nice =3D kcpustat_field(...) mutex_unlock(&policy_dbs->update_mutex) mutex_unlock(&attr_set->update_lock) Path B (work queue, wins the race between A1 and A2): dbs_work_handler() mutex_lock(&policy_dbs->update_mutex) /* acquired before A2 */ dbs_update() ignore_nice =3D dbs_data->ignore_nice_load /* sees new value: 1 */ cur_nice =3D kcpustat_field(...) idle_time +=3D div_u64(cur_nice - j_cdbs->prev_cpu_nice, ..) /* stale */ j_cdbs->prev_cpu_nice =3D cur_nice mutex_unlock(&policy_dbs->update_mutex) Fix this by unconditionally sampling cur_nice and advancing prev_cpu_nice in dbs_update() on every call, regardless of ignore_nice. With prev_cpu_nice always reflecting the most recent sample, enabling ignore_nice_load can never produce a stale-baseline spike: the delta will always be the nice time accumulated in the last sampling interval, not since boot. The additional kcpustat_field() call per CPU per sample is negligible given that the sampling path already reads idle and load accounting. To keep prev_cpu_nice handling consistent with the always-tracking semantics introduced above: - gov_update_cpu_data() unconditionally resets prev_cpu_nice alongside prev_cpu_idle, so both baselines share the same timestamp when io_is_busy changes. This prevents an interval mismatch between idle_time and nice_delta on the next dbs_update() when ignore_nice_load is enabled. - cpufreq_dbs_governor_start() unconditionally initializes prev_cpu_nice so the baseline is always valid from the first dbs_update() call; remove the ignore_nice guard and the now-unused ignore_nice variable. Fixes: ee88415caf736b ("[CPUFREQ] Cleanup locking in conservative governor") Fixes: 5a75c82828e7c0 ("[CPUFREQ] Cleanup locking in ondemand governor") Fixes: 326c86deaed54a ("[CPUFREQ] Remove unneeded locks") Signed-off-by: Zhongqiu Han --- drivers/cpufreq/cpufreq_governor.c | 33 +++++++++++++++++++----------- 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_g= overnor.c index fc6f705c5a9c..8a85bd32defe 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -92,6 +92,12 @@ EXPORT_SYMBOL_GPL(sampling_rate_store); * * Call under the @dbs_data->attr_set.update_lock. The per-policy * update_mutex is acquired and released internally for each policy. + * + * Note: prev_cpu_nice is reset here unconditionally alongside prev_cpu_id= le. + * When io_is_busy changes, both baselines must be advanced to the same + * timestamp so that the next dbs_update() computes idle_time and nice_del= ta + * over the same interval, preventing an artificially inflated idle_time w= hen + * ignore_nice_load is enabled. */ void gov_update_cpu_data(struct dbs_data *dbs_data) { @@ -106,8 +112,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data) =20 j_cdbs->prev_cpu_idle =3D get_cpu_idle_time(j, &j_cdbs->prev_update_tim= e, dbs_data->io_is_busy); - if (dbs_data->ignore_nice_load) - j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NIC= E, j); + j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE= , j); } mutex_unlock(&policy_dbs->update_mutex); } @@ -121,6 +126,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy) unsigned int ignore_nice =3D dbs_data->ignore_nice_load; unsigned int max_load =3D 0, idle_periods =3D UINT_MAX; unsigned int sampling_rate, io_busy, j; + u64 cur_nice; =20 /* * Sometimes governors may use an additional multiplier to increase @@ -167,12 +173,18 @@ unsigned int dbs_update(struct cpufreq_policy *policy) =20 j_cdbs->prev_cpu_idle =3D cur_idle_time; =20 - if (ignore_nice) { - u64 cur_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j); - + /* + * Always sample cur_nice and advance prev_cpu_nice, regardless + * of ignore_nice. This keeps prev_cpu_nice current so that + * enabling ignore_nice_load via sysfs never produces a + * stale-baseline spike (the delta will be at most one sampling + * interval of accumulated nice time, not since boot). + */ + cur_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j); + if (ignore_nice) idle_time +=3D div_u64(cur_nice - j_cdbs->prev_cpu_nice, NSEC_PER_USEC); - j_cdbs->prev_cpu_nice =3D cur_nice; - } + + j_cdbs->prev_cpu_nice =3D cur_nice; =20 if (unlikely(!time_elapsed)) { /* @@ -519,7 +531,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *p= olicy) struct dbs_governor *gov =3D dbs_governor_of(policy); struct policy_dbs_info *policy_dbs =3D policy->governor_data; struct dbs_data *dbs_data =3D policy_dbs->dbs_data; - unsigned int sampling_rate, ignore_nice, j; + unsigned int sampling_rate, j; unsigned int io_busy; =20 if (!policy->cur) @@ -529,7 +541,6 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *p= olicy) policy_dbs->rate_mult =3D 1; =20 sampling_rate =3D dbs_data->sampling_rate; - ignore_nice =3D dbs_data->ignore_nice_load; =20 mutex_lock(&policy_dbs->update_mutex); io_busy =3D dbs_data->io_is_busy; @@ -541,9 +552,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *p= olicy) * Make the first invocation of dbs_update() compute the load. */ j_cdbs->prev_load =3D 0; - - if (ignore_nice) - j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE= , j); + j_cdbs->prev_cpu_nice =3D kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE,= j); } mutex_unlock(&policy_dbs->update_mutex); =20 --=20 2.43.0