hulk inclusion category: bugfix bugzilla: https://atomgit.com/openeuler/kernel/issues/8423 -------------------------------- Introduce a throttled flag in cfs_rq to refine group enqueue logic in the presence of throttling, ensuring correctness in both flat and cgroup-enabled (CONFIG_CGROUP_XCU) scheduling hierarchies: - When a group is unthrottled, only update its throttled state, do not immediately enqueue it. Enqueuing is deferred until an xse is actually added to the group. This prevents enqueuing empty groups, which could otherwise cause the scheduler to pick a null or invalid xse and trigger runtime anomalies. - During upward enqueue traversal, stop as soon as a throttled cfs_rq is encountered. This avoids enqueuing group xsched entity that are still under throttling, preserving scheduler invariants. This change enhances scheduler robustness and simplifies throttling logic across configurations. Fixes: 8952ea1a5fb9 ("xsched: fix task stall when quota is disabled") Signed-off-by: Liu Kai <liukai284@huawei.com> --- include/linux/xsched.h | 10 ++++++++++ kernel/xsched/cfs.c | 10 +++++++++- kernel/xsched/cfs_quota.c | 39 +++++++++++++++++++++++++++------------ 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/include/linux/xsched.h b/include/linux/xsched.h index 09a5760591f9..76b4ce815870 100644 --- a/include/linux/xsched.h +++ b/include/linux/xsched.h @@ -83,6 +83,8 @@ struct xsched_rq_cfs { unsigned int load; u64 min_xruntime; struct rb_root_cached ctx_timeline; + + bool throttled; }; /* Base XSched runqueue object structure that contains both mutual and @@ -327,6 +329,14 @@ xse_this_grp(struct xsched_entity_cfs *xse_cfs) { return xse_cfs ? xse_this_grp_xcu(xse_cfs)->self : NULL; } + +static inline bool xsched_entity_throttled(struct xsched_entity *xse) +{ + struct xsched_group_xcu_priv *grp_xcu = + container_of(xse, struct xsched_group_xcu_priv, xse); + + return grp_xcu->cfs_rq->throttled; +} #else #define xsched_cfs_rq_of(xse) (&((xse)->xcu->xrq.cfs)) diff --git a/kernel/xsched/cfs.c b/kernel/xsched/cfs.c index df843c06e748..635e90b9afa1 100644 --- a/kernel/xsched/cfs.c +++ b/kernel/xsched/cfs.c @@ -150,11 +150,19 @@ static void enqueue_ctx_fair(struct xsched_entity *xse, struct xsched_cu *xcu) struct xsched_entity *child = xse; for_each_xse(child) { + /* + * Terminate upward traversal of parent groups if + * Xse is already enqueued or Group is throttled. + */ if (child->on_rq) break; - rq = xsched_cfs_rq_of(child); +#ifdef CONFIG_CGROUP_XCU + if (child->is_group && xsched_entity_throttled(child)) + break; +#endif + rq = xsched_cfs_rq_of(child); place_xsched_entity(rq, child); child->on_rq = true; rq->nr_running++; diff --git a/kernel/xsched/cfs_quota.c b/kernel/xsched/cfs_quota.c index bdbd2330e1b3..dbf6f88e3f07 100644 --- a/kernel/xsched/cfs_quota.c +++ b/kernel/xsched/cfs_quota.c @@ -29,6 +29,10 @@ static void xsched_group_throttle(struct xsched_group *xg, struct xsched_cu *xcu lockdep_assert_held(&xcu->xcu_lock); + if (xg->perxcu_priv[xcu_id].cfs_rq->throttled) + return; + + xg->perxcu_priv[xcu_id].cfs_rq->throttled = true; xg->perxcu_priv[xcu_id].nr_throttled++; xg->perxcu_priv[xcu_id].start_throttled_time = now; @@ -43,28 +47,39 @@ static void xsched_group_throttle(struct xsched_group *xg, struct xsched_cu *xcu static void xsched_group_unthrottle(struct xsched_group *xg) { - uint32_t id; struct xsched_cu *xcu; + ktime_t now = ktime_get(); + int id; for_each_active_xcu(xcu, id) { mutex_lock(&xcu->xcu_lock); - if (!xg || READ_ONCE(xg->is_offline) || - READ_ONCE(xg->sched_class) != XSCHED_TYPE_CFS) { + + if (!xg || READ_ONCE(xg->is_offline)) { mutex_unlock(&xcu->xcu_lock); return; } - if (!READ_ONCE(xg->perxcu_priv[id].xse.on_rq)) { - enqueue_ctx(&xg->perxcu_priv[id].xse, xcu); - wake_up_interruptible(&xcu->wq_xcu_idle); - if (xg->perxcu_priv[id].start_throttled_time != 0) { - xg->perxcu_priv[id].throttled_time += - ktime_to_ns(ktime_sub(ktime_get(), - xg->perxcu_priv[id].start_throttled_time)); + if (!xg->perxcu_priv[id].cfs_rq || + !xg->perxcu_priv[id].cfs_rq->throttled) { + mutex_unlock(&xcu->xcu_lock); + continue; + } - xg->perxcu_priv[id].start_throttled_time = 0; - } + /* + * Avoid inserting empty groups into the rbtree; + * only mark them as throttled. + */ + xg->perxcu_priv[id].cfs_rq->throttled = false; + xg->perxcu_priv[id].throttled_time += + ktime_to_ns(ktime_sub(now, + xg->perxcu_priv[id].start_throttled_time)); + xg->perxcu_priv[id].start_throttled_time = 0; + + if (xg->perxcu_priv[id].cfs_rq->nr_running > 0) { + enqueue_ctx(&xg->perxcu_priv[id].xse, xcu); + wake_up_interruptible(&xcu->wq_xcu_idle); } + mutex_unlock(&xcu->xcu_lock); } } -- 2.34.1