| @@ -259,8 +259,6 @@ __printf(5, 6) bool __scx_exit(struct scx_sched *sch, · 258 unmodified lines |
| 259 | return ret; | 259 | return ret; |
| 260 | } | 260 | } |
| 261 | | 261 | |
| 262 | #define SCX_HAS_OP(sch, op) test_bit(SCX_OP_IDX(op), (sch)->has_op) | | |
| 263 | | | |
| 264 | static long jiffies_delta_msecs(unsigned long at, unsigned long now) | 262 | static long jiffies_delta_msecs(unsigned long at, unsigned long now) |
| 265 | { | 263 | { |
| 266 | if (time_after(at, now)) | 264 | if (time_after(at, now)) |
| @@ -275,20 +273,6 @@ static bool u32_before(u32 a, u32 b) · 8 unmodified lines |
| 275 | } | 273 | } |
| 276 | | 274 | |
| 277 | #ifdef CONFIG_EXT_SUB_SCHED | 275 | #ifdef CONFIG_EXT_SUB_SCHED |
| 278 | /** | | |
| 279 | * scx_parent - Find the parent sched | | |
| 280 | * @sch: sched to find the parent of | | |
| 281 | * | | |
| 282 | * Returns the parent scheduler or %NULL if @sch is root. | | |
| 283 | */ | | |
| 284 | static struct scx_sched *scx_parent(struct scx_sched *sch) | | |
| 285 | { | | |
| 286 | if (sch->level) | | |
| 287 | return sch->ancestors[sch->level - 1]; | | |
| 288 | else | | |
| 289 | return NULL; | | |
| 290 | } | | |
| 291 | | | |
| 292 | /** | 276 | /** |
| 293 | * scx_next_descendant_pre - find the next descendant for pre-order walk | 277 | * scx_next_descendant_pre - find the next descendant for pre-order walk |
| 294 | * @pos: the current position (%NULL to initiate traversal) | 278 | * @pos: the current position (%NULL to initiate traversal) |
| @@ -336,7 +320,6 @@ static void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch) · 41 unmodified lines |
| 336 | rcu_assign_pointer(p->scx.sched, sch); | 320 | rcu_assign_pointer(p->scx.sched, sch); |
| 337 | } | 321 | } |
| 338 | #else /* CONFIG_EXT_SUB_SCHED */ | 322 | #else /* CONFIG_EXT_SUB_SCHED */ |
| 339 | static inline struct scx_sched *scx_parent(struct scx_sched *sch) { return NULL; } | | |
| 340 | static inline struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sched *root) { return pos ? NULL : root; } | 323 | static inline struct scx_sched *scx_next_descendant_pre(struct scx_sched *pos, struct scx_sched *root) { return pos ? NULL : root; } |
| 341 | static inline void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch) {} | 324 | static inline void scx_set_task_sched(struct task_struct *p, struct scx_sched *sch) {} |
| 342 | #endif /* CONFIG_EXT_SUB_SCHED */ | 325 | #endif /* CONFIG_EXT_SUB_SCHED */ |
| @@ -496,123 +479,12 @@ static bool rq_is_open(struct rq *rq, u64 enq_flags) · 153 unmodified lines |
| 496 | */ | 479 | */ |
| 497 | DEFINE_PER_CPU(struct rq *, scx_locked_rq_state); | 480 | DEFINE_PER_CPU(struct rq *, scx_locked_rq_state); |
| 498 | | 481 | |
| 499 | static inline void update_locked_rq(struct rq *rq) | | |
| 500 | { | | |
| 501 | /* | | |
| 502 | * Check whether @rq is actually locked. This can help expose bugs | | |
| 503 | * or incorrect assumptions about the context in which a kfunc or | | |
| 504 | * callback is executed. | | |
| 505 | */ | | |
| 506 | if (rq) | | |
| 507 | lockdep_assert_rq_held(rq); | | |
| 508 | __this_cpu_write(scx_locked_rq_state, rq); | | |
| 509 | } | | |
| 510 | | | |
| 511 | /* | | |
| 512 | * SCX ops can recurse via scx_bpf_sub_dispatch() - the inner call must not | | |
| 513 | * clobber the outer's scx_locked_rq_state. Save it on entry, restore on exit. | | |
| 514 | */ | | |
| 515 | #define SCX_CALL_OP(sch, op, locked_rq, args...) \ | | |
| 516 | do { \ | | |
| 517 | struct rq *__prev_locked_rq; \ | | |
| 518 | \ | | |
| 519 | if (locked_rq) { \ | | |
| 520 | __prev_locked_rq = scx_locked_rq(); \ | | |
| 521 | update_locked_rq(locked_rq); \ | | |
| 522 | } \ | | |
| 523 | (sch)->ops.op(args); \ | | |
| 524 | if (locked_rq) \ | | |
| 525 | update_locked_rq(__prev_locked_rq); \ | | |
| 526 | } while (0) | | |
| 527 | | | |
| 528 | /* | 482 | /* |
| 529 | * Flipped on enable per sch->is_cid_type. Declared in internal.h so | 483 | * Flipped on enable per sch->is_cid_type. Declared in internal.h so |
| 530 | * subsystem inlines can read it. | 484 | * subsystem inlines can read it. |
| 531 | */ | 485 | */ |
| 532 | DEFINE_STATIC_KEY_FALSE(__scx_is_cid_type); | 486 | DEFINE_STATIC_KEY_FALSE(__scx_is_cid_type); |
| 533 | | 487 | |
| 534 | /* | | |
| 535 | * scx_cpu_arg() wraps a cpu arg being handed to an SCX op. For cid-form | | |
| 536 | * schedulers it resolves to the matching cid; for cpu-form it passes @cpu | | |
| 537 | * through. scx_cpu_ret() is the inverse for a cpu/cid returned from an op | | |
| 538 | * (currently only ops.select_cpu); it validates the BPF-supplied cid and | | |
| 539 | * triggers scx_error() on @sch if invalid. | | |
| 540 | */ | | |
| 541 | static s32 scx_cpu_arg(s32 cpu) | | |
| 542 | { | | |
| 543 | if (scx_is_cid_type()) | | |
| 544 | return __scx_cpu_to_cid(cpu); | | |
| 545 | return cpu; | | |
| 546 | } | | |
| 547 | | | |
| 548 | static s32 scx_cpu_ret(struct scx_sched *sch, s32 cpu_or_cid) | | |
| 549 | { | | |
| 550 | if (cpu_or_cid < 0 || !scx_is_cid_type()) | | |
| 551 | return cpu_or_cid; | | |
| 552 | return scx_cid_to_cpu(sch, cpu_or_cid); | | |
| 553 | } | | |
| 554 | | | |
| 555 | #define SCX_CALL_OP_RET(sch, op, locked_rq, args...) \ | | |
| 556 | ({ \ | | |
| 557 | struct rq *__prev_locked_rq; \ | | |
| 558 | __typeof__((sch)->ops.op(args)) __ret; \ | | |
| 559 | \ | | |
| 560 | if (locked_rq) { \ | | |
| 561 | __prev_locked_rq = scx_locked_rq(); \ | | |
| 562 | update_locked_rq(locked_rq); \ | | |
| 563 | } \ | | |
| 564 | __ret = (sch)->ops.op(args); \ | | |
| 565 | if (locked_rq) \ | | |
| 566 | update_locked_rq(__prev_locked_rq); \ | | |
| 567 | __ret; \ | | |
| 568 | }) | | |
| 569 | | | |
| 570 | /* | | |
| 571 | * SCX_CALL_OP_TASK*() invokes an SCX op that takes one or two task arguments | | |
| 572 | * and records them in current->scx.kf_tasks[] for the duration of the call. A | | |
| 573 | * kfunc invoked from inside such an op can then use | | |
| 574 | * scx_kf_arg_task_ok() to verify that its task argument is one of | | |
| 575 | * those subject tasks. | | |
| 576 | * | | |
| 577 | * Every SCX_CALL_OP_TASK*() call site invokes its op with @p's rq lock held - | | |
| 578 | * either via the @locked_rq argument here, or (for ops.select_cpu()) via @p's | | |
| 579 | * pi_lock held by try_to_wake_up() with rq tracking via scx_rq.in_select_cpu. | | |
| 580 | * So if kf_tasks[] is set, @p's scheduler-protected fields are stable. | | |
| 581 | * | | |
| 582 | * kf_tasks[] can not stack, so task-based SCX ops must not nest. The | | |
| 583 | * WARN_ON_ONCE() in each macro catches a re-entry of any of the three variants | | |
| 584 | * while a previous one is still in progress. | | |
| 585 | */ | | |
| 586 | #define SCX_CALL_OP_TASK(sch, op, locked_rq, task, args...) \ | | |
| 587 | do { \ | | |
| 588 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | | |
| 589 | current->scx.kf_tasks[0] = task; \ | | |
| 590 | SCX_CALL_OP((sch), op, locked_rq, task, ##args); \ | | |
| 591 | current->scx.kf_tasks[0] = NULL; \ | | |
| 592 | } while (0) | | |
| 593 | | | |
| 594 | #define SCX_CALL_OP_TASK_RET(sch, op, locked_rq, task, args...) \ | | |
| 595 | ({ \ | | |
| 596 | __typeof__((sch)->ops.op(task, ##args)) __ret; \ | | |
| 597 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | | |
| 598 | current->scx.kf_tasks[0] = task; \ | | |
| 599 | __ret = SCX_CALL_OP_RET((sch), op, locked_rq, task, ##args); \ | | |
| 600 | current->scx.kf_tasks[0] = NULL; \ | | |
| 601 | __ret; \ | | |
| 602 | }) | | |
| 603 | | | |
| 604 | #define SCX_CALL_OP_2TASKS_RET(sch, op, locked_rq, task0, task1, args...) \ | | |
| 605 | ({ \ | | |
| 606 | __typeof__((sch)->ops.op(task0, task1, ##args)) __ret; \ | | |
| 607 | WARN_ON_ONCE(current->scx.kf_tasks[0]); \ | | |
| 608 | current->scx.kf_tasks[0] = task0; \ | | |
| 609 | current->scx.kf_tasks[1] = task1; \ | | |
| 610 | __ret = SCX_CALL_OP_RET((sch), op, locked_rq, task0, task1, ##args); \ | | |
| 611 | current->scx.kf_tasks[0] = NULL; \ | | |
| 612 | current->scx.kf_tasks[1] = NULL; \ | | |
| 613 | __ret; \ | | |
| 614 | }) | | |
| 615 | | | |
| 616 | /** | 488 | /** |
| 617 | * scx_call_op_set_cpumask - invoke ops.set_cpumask / ops_cid.set_cmask for @task | 489 | * scx_call_op_set_cpumask - invoke ops.set_cpumask / ops_cid.set_cmask for @task |
| 618 | * @sch: scx_sched being invoked | 490 | * @sch: scx_sched being invoked |
| @@ -651,19 +523,6 @@ static inline void scx_call_op_set_cpumask(struct scx_sched *sch, struct rq *rq, · 32 unmodified lines |
| 651 | current->scx.kf_tasks[0] = NULL; | 523 | current->scx.kf_tasks[0] = NULL; |
| 652 | } | 524 | } |
| 653 | | 525 | |
| 654 | /* see SCX_CALL_OP_TASK() */ | | |
| 655 | static __always_inline bool scx_kf_arg_task_ok(struct scx_sched *sch, | | |
| 656 | struct task_struct *p) | | |
| 657 | { | | |
| 658 | if (unlikely((p != current->scx.kf_tasks[0] && | | |
| 659 | p != current->scx.kf_tasks[1]))) { | | |
| 660 | scx_error(sch, "called on a task not being operated on"); | | |
| 661 | return false; | | |
| 662 | } | | |
| 663 | | | |
| 664 | return true; | | |
| 665 | } | | |
| 666 | | | |
| 667 | enum scx_dsq_iter_flags { | 526 | enum scx_dsq_iter_flags { |
| 668 | /* iterate in the reverse dispatch order */ | 527 | /* iterate in the reverse dispatch order */ |
| 669 | SCX_DSQ_ITER_REV = 1U << 16, | 528 | SCX_DSQ_ITER_REV = 1U << 16, |