From 0d6526f82c3cdefcca47f73f5fc08dc6f335eac6 Mon Sep 17 00:00:00 2001 From: Tim Chen Date: Mon, 21 Sep 2026 17:37:22 -0700 Subject: sched/cache: Keep nr_pref_llc_running in the runnable domain, to fix LLC mis-scheduling bug alb_break_llc() decides whether to break LLC preference during active load balance. It does so by testing that every runnable fair task on the source rq prefers its LLC: env->src_rq->nr_pref_llc_running == env->src_rq->cfs.h_nr_runnable But the two counters cover different sets. nr_pref_llc_running is updated in account_llc_enqueue()/account_llc_dequeue(), next to cfs_rq->nr_queued, so it follows queued tasks. h_nr_runnable is updated in set_delayed()/ clear_delayed() and drops delay-dequeued tasks. So under DELAY_DEQUEUE, a preferring task that goes to sleep stays counted in nr_pref_llc_running while h_nr_runnable falls. The equality then breaks, alb_break_llc() returns false, and active balance is free to pull a task off its preferred LLC. Active balance only moves runnable tasks, and this is the only LLC check it consults: once the stopper runs, LBF_ACTIVE_LB skips the per-task test in can_migrate_task(). The runnable set is the one we want. Fix it on the counter side. A task should be counted in nr_pref_llc_running exactly while it is both queued on its preferred LLC (pref_llc_queued) and runnable (!sched_delayed). Define that membership once in task_pref_llc_runnable(), and adjust the counter only through pref_llc_running_inc()/pref_llc_running_dec() from the four sites that change either input: account_llc_enqueue(), account_llc_dequeue(), set_delayed() and clear_delayed(). Gating every update on the same predicate keeps the delay, wake and dequeue paths from double-counting or underflowing; see the comments at those sites for the ordering. nr_llc_running and sd->llc_counts are not touched and stay on queued semantics. Fixes: 714059f79ff0 ("sched/cache: Handle moving single tasks to/from their preferred LLC") Closes: https://lore.kernel.org/lkml/20260827135000.735138-1-zhanxusheng@xiaomi.com/ Reported-by: Zhan Xusheng Suggested-by: Chen Yu Signed-off-by: Tim Chen Signed-off-by: Peter Zijlstra (Intel) Signed-off-by: Ingo Molnar Reviewed-by: Kayra Cizmeci Cc: # v7.2.x Link: https://patch.msgid.link/06af61afedac32e6477f57feb4d658f6c411c3af.1790035273.git.tim.c.chen@linux.intel.com --- include/drm/drm_accel.h | 85 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 include/drm/drm_accel.h (limited to 'include/drm/drm_accel.h') diff --git a/include/drm/drm_accel.h b/include/drm/drm_accel.h new file mode 100644 index 000000000..20a665ec6 --- /dev/null +++ b/include/drm/drm_accel.h @@ -0,0 +1,85 @@ +/* SPDX-License-Identifier: GPL-2.0 + * + * Copyright 2022 HabanaLabs, Ltd. + * All Rights Reserved. + * + */ + +#ifndef DRM_ACCEL_H_ +#define DRM_ACCEL_H_ + +#include + +#define ACCEL_MAJOR 261 +#define ACCEL_MAX_MINORS 256 + +/** + * DRM_ACCEL_FOPS - Default drm accelerators file operations + * + * This macro provides a shorthand for setting the accelerator file ops in the + * &file_operations structure. If all you need are the default ops, use + * DEFINE_DRM_ACCEL_FOPS instead. + */ +#define DRM_ACCEL_FOPS \ + .open = accel_open,\ + .release = drm_release,\ + .unlocked_ioctl = drm_ioctl,\ + .compat_ioctl = drm_compat_ioctl,\ + .poll = drm_poll,\ + .read = drm_read,\ + .llseek = noop_llseek, \ + .mmap = drm_gem_mmap, \ + .fop_flags = FOP_UNSIGNED_OFFSET + +/** + * DEFINE_DRM_ACCEL_FOPS() - macro to generate file operations for accelerators drivers + * @name: name for the generated structure + * + * This macro autogenerates a suitable &struct file_operations for accelerators based + * drivers, which can be assigned to &drm_driver.fops. Note that this structure + * cannot be shared between drivers, because it contains a reference to the + * current module using THIS_MODULE. + * + * Note that the declaration is already marked as static - if you need a + * non-static version of this you're probably doing it wrong and will break the + * THIS_MODULE reference by accident. + */ +#define DEFINE_DRM_ACCEL_FOPS(name) \ + static const struct file_operations name = {\ + .owner = THIS_MODULE,\ + DRM_ACCEL_FOPS,\ + } + +#if IS_ENABLED(CONFIG_DRM_ACCEL) + +extern struct xarray accel_minors_xa; + +void accel_core_exit(void); +int accel_core_init(void); +void accel_set_device_instance_params(struct device *kdev, int index); +int accel_open(struct inode *inode, struct file *filp); +void accel_debugfs_register(struct drm_device *dev); + +#else + +static inline void accel_core_exit(void) +{ +} + +static inline int __init accel_core_init(void) +{ + /* Return 0 to allow drm_core_init to complete successfully */ + return 0; +} + +static inline void accel_set_device_instance_params(struct device *kdev, int index) +{ +} + +static inline void accel_debugfs_register(struct drm_device *dev) +{ +} + +#endif /* IS_ENABLED(CONFIG_DRM_ACCEL) */ + +#endif /* DRM_ACCEL_H_ */ -- cgit v1.3.1