From: kernel test robot <lkp@intel.com>
To: Tejun Heo <tj@kernel.org>
Cc: llvm@lists.linux.dev, oe-kbuild-all@lists.linux.dev,
Andrea Righi <arighi@nvidia.com>
Subject: [linux-next:master 5440/7971] kernel/sched/ext.c:6517:2: error: call to undeclared function 'cgroup_put'; ISO C99 and later do not support implicit function declarations
Date: Sat, 21 Mar 2026 09:37:13 +0800 [thread overview]
Message-ID: <202603210903.IrKhPd6k-lkp@intel.com> (raw)
tree: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git master
head: 785f0eb2f85decbe7c1ef9ae922931f0194ffc2e
commit: 618a9db0158b1c51fd33822cf804f5a09f829837 [5440/7971] sched_ext: Use kobject_put() for kobject_init_and_add() failure in scx_alloc_and_add_sched()
config: x86_64-buildonly-randconfig-004-20260321 (https://download.01.org/0day-ci/archive/20260321/202603210903.IrKhPd6k-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260321/202603210903.IrKhPd6k-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603210903.IrKhPd6k-lkp@intel.com/
All errors (new ones prefixed by >>):
In file included from kernel/sched/build_policy.c:62:
>> kernel/sched/ext.c:6517:2: error: call to undeclared function 'cgroup_put'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
6517 | cgroup_put(cgrp);
| ^
kernel/sched/ext.c:6497:1: warning: unused label 'err_stop_helper' [-Wunused-label]
6497 | err_stop_helper:
| ^~~~~~~~~~~~~~~~
>> kernel/sched/ext.c:6606:2: error: call to undeclared function 'cgroup_get'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
6606 | cgroup_get(cgrp);
| ^
1 warning and 2 errors generated.
vim +/cgroup_put +6517 kernel/sched/ext.c
6355
6356 /*
6357 * Allocate and initialize a new scx_sched. @cgrp's reference is always
6358 * consumed whether the function succeeds or fails.
6359 */
6360 static struct scx_sched *scx_alloc_and_add_sched(struct sched_ext_ops *ops,
6361 struct cgroup *cgrp,
6362 struct scx_sched *parent)
6363 {
6364 struct scx_sched *sch;
6365 s32 level = parent ? parent->level + 1 : 0;
6366 s32 node, cpu, ret, bypass_fail_cpu = nr_cpu_ids;
6367
6368 sch = kzalloc_flex(*sch, ancestors, level);
6369 if (!sch) {
6370 ret = -ENOMEM;
6371 goto err_put_cgrp;
6372 }
6373
6374 sch->exit_info = alloc_exit_info(ops->exit_dump_len);
6375 if (!sch->exit_info) {
6376 ret = -ENOMEM;
6377 goto err_free_sch;
6378 }
6379
6380 ret = rhashtable_init(&sch->dsq_hash, &dsq_hash_params);
6381 if (ret < 0)
6382 goto err_free_ei;
6383
6384 sch->pnode = kzalloc_objs(sch->pnode[0], nr_node_ids);
6385 if (!sch->pnode) {
6386 ret = -ENOMEM;
6387 goto err_free_hash;
6388 }
6389
6390 for_each_node_state(node, N_POSSIBLE) {
6391 sch->pnode[node] = alloc_pnode(sch, node);
6392 if (!sch->pnode[node]) {
6393 ret = -ENOMEM;
6394 goto err_free_pnode;
6395 }
6396 }
6397
6398 sch->dsp_max_batch = ops->dispatch_max_batch ?: SCX_DSP_DFL_MAX_BATCH;
6399 sch->pcpu = __alloc_percpu(struct_size_t(struct scx_sched_pcpu,
6400 dsp_ctx.buf, sch->dsp_max_batch),
6401 __alignof__(struct scx_sched_pcpu));
6402 if (!sch->pcpu) {
6403 ret = -ENOMEM;
6404 goto err_free_pnode;
6405 }
6406
6407 for_each_possible_cpu(cpu) {
6408 ret = init_dsq(bypass_dsq(sch, cpu), SCX_DSQ_BYPASS, sch);
6409 if (ret) {
6410 bypass_fail_cpu = cpu;
6411 goto err_free_pcpu;
6412 }
6413 }
6414
6415 for_each_possible_cpu(cpu) {
6416 struct scx_sched_pcpu *pcpu = per_cpu_ptr(sch->pcpu, cpu);
6417
6418 pcpu->sch = sch;
6419 INIT_LIST_HEAD(&pcpu->deferred_reenq_local.node);
6420 }
6421
6422 sch->helper = kthread_run_worker(0, "sched_ext_helper");
6423 if (IS_ERR(sch->helper)) {
6424 ret = PTR_ERR(sch->helper);
6425 goto err_free_pcpu;
6426 }
6427
6428 sched_set_fifo(sch->helper->task);
6429
6430 if (parent)
6431 memcpy(sch->ancestors, parent->ancestors,
6432 level * sizeof(parent->ancestors[0]));
6433 sch->ancestors[level] = sch;
6434 sch->level = level;
6435
6436 if (ops->timeout_ms)
6437 sch->watchdog_timeout = msecs_to_jiffies(ops->timeout_ms);
6438 else
6439 sch->watchdog_timeout = SCX_WATCHDOG_MAX_TIMEOUT;
6440
6441 sch->slice_dfl = SCX_SLICE_DFL;
6442 atomic_set(&sch->exit_kind, SCX_EXIT_NONE);
6443 init_irq_work(&sch->disable_irq_work, scx_disable_irq_workfn);
6444 kthread_init_work(&sch->disable_work, scx_disable_workfn);
6445 timer_setup(&sch->bypass_lb_timer, scx_bypass_lb_timerfn, 0);
6446 sch->ops = *ops;
6447 rcu_assign_pointer(ops->priv, sch);
6448
6449 sch->kobj.kset = scx_kset;
6450
6451 #ifdef CONFIG_EXT_SUB_SCHED
6452 char *buf = kzalloc(PATH_MAX, GFP_KERNEL);
6453 if (!buf) {
6454 ret = -ENOMEM;
6455 goto err_stop_helper;
6456 }
6457 cgroup_path(cgrp, buf, PATH_MAX);
6458 sch->cgrp_path = kstrdup(buf, GFP_KERNEL);
6459 kfree(buf);
6460 if (!sch->cgrp_path) {
6461 ret = -ENOMEM;
6462 goto err_stop_helper;
6463 }
6464
6465 sch->cgrp = cgrp;
6466 INIT_LIST_HEAD(&sch->children);
6467 INIT_LIST_HEAD(&sch->sibling);
6468
6469 if (parent)
6470 ret = kobject_init_and_add(&sch->kobj, &scx_ktype,
6471 &parent->sub_kset->kobj,
6472 "sub-%llu", cgroup_id(cgrp));
6473 else
6474 ret = kobject_init_and_add(&sch->kobj, &scx_ktype, NULL, "root");
6475
6476 if (ret < 0) {
6477 kobject_put(&sch->kobj);
6478 return ERR_PTR(ret);
6479 }
6480
6481 if (ops->sub_attach) {
6482 sch->sub_kset = kset_create_and_add("sub", NULL, &sch->kobj);
6483 if (!sch->sub_kset) {
6484 kobject_put(&sch->kobj);
6485 return ERR_PTR(-ENOMEM);
6486 }
6487 }
6488 #else /* CONFIG_EXT_SUB_SCHED */
6489 ret = kobject_init_and_add(&sch->kobj, &scx_ktype, NULL, "root");
6490 if (ret < 0) {
6491 kobject_put(&sch->kobj);
6492 return ERR_PTR(ret);
6493 }
6494 #endif /* CONFIG_EXT_SUB_SCHED */
6495 return sch;
6496
6497 err_stop_helper:
6498 kthread_destroy_worker(sch->helper);
6499 err_free_pcpu:
6500 for_each_possible_cpu(cpu) {
6501 if (cpu == bypass_fail_cpu)
6502 break;
6503 exit_dsq(bypass_dsq(sch, cpu));
6504 }
6505 free_percpu(sch->pcpu);
6506 err_free_pnode:
6507 for_each_node_state(node, N_POSSIBLE)
6508 free_pnode(sch->pnode[node]);
6509 kfree(sch->pnode);
6510 err_free_hash:
6511 rhashtable_free_and_destroy(&sch->dsq_hash, NULL, NULL);
6512 err_free_ei:
6513 free_exit_info(sch->exit_info);
6514 err_free_sch:
6515 kfree(sch);
6516 err_put_cgrp:
> 6517 cgroup_put(cgrp);
6518 return ERR_PTR(ret);
6519 }
6520
6521 static int check_hotplug_seq(struct scx_sched *sch,
6522 const struct sched_ext_ops *ops)
6523 {
6524 unsigned long long global_hotplug_seq;
6525
6526 /*
6527 * If a hotplug event has occurred between when a scheduler was
6528 * initialized, and when we were able to attach, exit and notify user
6529 * space about it.
6530 */
6531 if (ops->hotplug_seq) {
6532 global_hotplug_seq = atomic_long_read(&scx_hotplug_seq);
6533 if (ops->hotplug_seq != global_hotplug_seq) {
6534 scx_exit(sch, SCX_EXIT_UNREG_KERN,
6535 SCX_ECODE_ACT_RESTART | SCX_ECODE_RSN_HOTPLUG,
6536 "expected hotplug seq %llu did not match actual %llu",
6537 ops->hotplug_seq, global_hotplug_seq);
6538 return -EBUSY;
6539 }
6540 }
6541
6542 return 0;
6543 }
6544
6545 static int validate_ops(struct scx_sched *sch, const struct sched_ext_ops *ops)
6546 {
6547 /*
6548 * It doesn't make sense to specify the SCX_OPS_ENQ_LAST flag if the
6549 * ops.enqueue() callback isn't implemented.
6550 */
6551 if ((ops->flags & SCX_OPS_ENQ_LAST) && !ops->enqueue) {
6552 scx_error(sch, "SCX_OPS_ENQ_LAST requires ops.enqueue() to be implemented");
6553 return -EINVAL;
6554 }
6555
6556 /*
6557 * SCX_OPS_BUILTIN_IDLE_PER_NODE requires built-in CPU idle
6558 * selection policy to be enabled.
6559 */
6560 if ((ops->flags & SCX_OPS_BUILTIN_IDLE_PER_NODE) &&
6561 (ops->update_idle && !(ops->flags & SCX_OPS_KEEP_BUILTIN_IDLE))) {
6562 scx_error(sch, "SCX_OPS_BUILTIN_IDLE_PER_NODE requires CPU idle selection enabled");
6563 return -EINVAL;
6564 }
6565
6566 if (ops->cpu_acquire || ops->cpu_release)
6567 pr_warn("ops->cpu_acquire/release() are deprecated, use sched_switch TP instead\n");
6568
6569 return 0;
6570 }
6571
6572 /*
6573 * scx_enable() is offloaded to a dedicated system-wide RT kthread to avoid
6574 * starvation. During the READY -> ENABLED task switching loop, the calling
6575 * thread's sched_class gets switched from fair to ext. As fair has higher
6576 * priority than ext, the calling thread can be indefinitely starved under
6577 * fair-class saturation, leading to a system hang.
6578 */
6579 struct scx_enable_cmd {
6580 struct kthread_work work;
6581 struct sched_ext_ops *ops;
6582 int ret;
6583 };
6584
6585 static void scx_root_enable_workfn(struct kthread_work *work)
6586 {
6587 struct scx_enable_cmd *cmd = container_of(work, struct scx_enable_cmd, work);
6588 struct sched_ext_ops *ops = cmd->ops;
6589 struct cgroup *cgrp = root_cgroup();
6590 struct scx_sched *sch;
6591 struct scx_task_iter sti;
6592 struct task_struct *p;
6593 int i, cpu, ret;
6594
6595 mutex_lock(&scx_enable_mutex);
6596
6597 if (scx_enable_state() != SCX_DISABLED) {
6598 ret = -EBUSY;
6599 goto err_unlock;
6600 }
6601
6602 ret = alloc_kick_syncs();
6603 if (ret)
6604 goto err_unlock;
6605
> 6606 cgroup_get(cgrp);
6607 sch = scx_alloc_and_add_sched(ops, cgrp, NULL);
6608 if (IS_ERR(sch)) {
6609 ret = PTR_ERR(sch);
6610 goto err_free_ksyncs;
6611 }
6612
6613 /*
6614 * Transition to ENABLING and clear exit info to arm the disable path.
6615 * Failure triggers full disabling from here on.
6616 */
6617 WARN_ON_ONCE(scx_set_enable_state(SCX_ENABLING) != SCX_DISABLED);
6618 WARN_ON_ONCE(scx_root);
6619
6620 atomic_long_set(&scx_nr_rejected, 0);
6621
6622 for_each_possible_cpu(cpu) {
6623 struct rq *rq = cpu_rq(cpu);
6624
6625 rq->scx.local_dsq.sched = sch;
6626 rq->scx.cpuperf_target = SCX_CPUPERF_ONE;
6627 }
6628
6629 /*
6630 * Keep CPUs stable during enable so that the BPF scheduler can track
6631 * online CPUs by watching ->on/offline_cpu() after ->init().
6632 */
6633 cpus_read_lock();
6634
6635 /*
6636 * Make the scheduler instance visible. Must be inside cpus_read_lock().
6637 * See handle_hotplug().
6638 */
6639 rcu_assign_pointer(scx_root, sch);
6640
6641 ret = scx_link_sched(sch);
6642 if (ret)
6643 goto err_disable;
6644
6645 scx_idle_enable(ops);
6646
6647 if (sch->ops.init) {
6648 ret = SCX_CALL_OP_RET(sch, SCX_KF_UNLOCKED, init, NULL);
6649 if (ret) {
6650 ret = ops_sanitize_err(sch, "init", ret);
6651 cpus_read_unlock();
6652 scx_error(sch, "ops.init() failed (%d)", ret);
6653 goto err_disable;
6654 }
6655 sch->exit_info->flags |= SCX_EFLAG_INITIALIZED;
6656 }
6657
6658 for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++)
6659 if (((void (**)(void))ops)[i])
6660 set_bit(i, sch->has_op);
6661
6662 ret = check_hotplug_seq(sch, ops);
6663 if (ret) {
6664 cpus_read_unlock();
6665 goto err_disable;
6666 }
6667 scx_idle_update_selcpu_topology(ops);
6668
6669 cpus_read_unlock();
6670
6671 ret = validate_ops(sch, ops);
6672 if (ret)
6673 goto err_disable;
6674
6675 /*
6676 * Once __scx_enabled is set, %current can be switched to SCX anytime.
6677 * This can lead to stalls as some BPF schedulers (e.g. userspace
6678 * scheduling) may not function correctly before all tasks are switched.
6679 * Init in bypass mode to guarantee forward progress.
6680 */
6681 scx_bypass(sch, true);
6682
6683 for (i = SCX_OPI_NORMAL_BEGIN; i < SCX_OPI_NORMAL_END; i++)
6684 if (((void (**)(void))ops)[i])
6685 set_bit(i, sch->has_op);
6686
6687 if (sch->ops.cpu_acquire || sch->ops.cpu_release)
6688 sch->ops.flags |= SCX_OPS_HAS_CPU_PREEMPT;
6689
6690 /*
6691 * Lock out forks, cgroup on/offlining and moves before opening the
6692 * floodgate so that they don't wander into the operations prematurely.
6693 */
6694 percpu_down_write(&scx_fork_rwsem);
6695
6696 WARN_ON_ONCE(scx_init_task_enabled);
6697 scx_init_task_enabled = true;
6698
6699 /*
6700 * Enable ops for every task. Fork is excluded by scx_fork_rwsem
6701 * preventing new tasks from being added. No need to exclude tasks
6702 * leaving as sched_ext_free() can handle both prepped and enabled
6703 * tasks. Prep all tasks first and then enable them with preemption
6704 * disabled.
6705 *
6706 * All cgroups should be initialized before scx_init_task() so that the
6707 * BPF scheduler can reliably track each task's cgroup membership from
6708 * scx_init_task(). Lock out cgroup on/offlining and task migrations
6709 * while tasks are being initialized so that scx_cgroup_can_attach()
6710 * never sees uninitialized tasks.
6711 */
6712 scx_cgroup_lock();
6713 set_cgroup_sched(sch_cgroup(sch), sch);
6714 ret = scx_cgroup_init(sch);
6715 if (ret)
6716 goto err_disable_unlock_all;
6717
6718 scx_task_iter_start(&sti, NULL);
6719 while ((p = scx_task_iter_next_locked(&sti))) {
6720 /*
6721 * @p may already be dead, have lost all its usages counts and
6722 * be waiting for RCU grace period before being freed. @p can't
6723 * be initialized for SCX in such cases and should be ignored.
6724 */
6725 if (!tryget_task_struct(p))
6726 continue;
6727
6728 scx_task_iter_unlock(&sti);
6729
6730 ret = scx_init_task(sch, p, false);
6731 if (ret) {
6732 put_task_struct(p);
6733 scx_task_iter_stop(&sti);
6734 scx_error(sch, "ops.init_task() failed (%d) for %s[%d]",
6735 ret, p->comm, p->pid);
6736 goto err_disable_unlock_all;
6737 }
6738
6739 scx_set_task_sched(p, sch);
6740 scx_set_task_state(p, SCX_TASK_READY);
6741
6742 put_task_struct(p);
6743 }
6744 scx_task_iter_stop(&sti);
6745 scx_cgroup_unlock();
6746 percpu_up_write(&scx_fork_rwsem);
6747
6748 /*
6749 * All tasks are READY. It's safe to turn on scx_enabled() and switch
6750 * all eligible tasks.
6751 */
6752 WRITE_ONCE(scx_switching_all, !(ops->flags & SCX_OPS_SWITCH_PARTIAL));
6753 static_branch_enable(&__scx_enabled);
6754
6755 /*
6756 * We're fully committed and can't fail. The task READY -> ENABLED
6757 * transitions here are synchronized against sched_ext_free() through
6758 * scx_tasks_lock.
6759 */
6760 percpu_down_write(&scx_fork_rwsem);
6761 scx_task_iter_start(&sti, NULL);
6762 while ((p = scx_task_iter_next_locked(&sti))) {
6763 unsigned int queue_flags = DEQUEUE_SAVE | DEQUEUE_MOVE;
6764 const struct sched_class *old_class = p->sched_class;
6765 const struct sched_class *new_class = scx_setscheduler_class(p);
6766
6767 if (scx_get_task_state(p) != SCX_TASK_READY)
6768 continue;
6769
6770 if (old_class != new_class)
6771 queue_flags |= DEQUEUE_CLASS;
6772
6773 scoped_guard (sched_change, p, queue_flags) {
6774 p->scx.slice = READ_ONCE(sch->slice_dfl);
6775 p->sched_class = new_class;
6776 }
6777 }
6778 scx_task_iter_stop(&sti);
6779 percpu_up_write(&scx_fork_rwsem);
6780
6781 scx_bypass(sch, false);
6782
6783 if (!scx_tryset_enable_state(SCX_ENABLED, SCX_ENABLING)) {
6784 WARN_ON_ONCE(atomic_read(&sch->exit_kind) == SCX_EXIT_NONE);
6785 goto err_disable;
6786 }
6787
6788 if (!(ops->flags & SCX_OPS_SWITCH_PARTIAL))
6789 static_branch_enable(&__scx_switched_all);
6790
6791 pr_info("sched_ext: BPF scheduler \"%s\" enabled%s\n",
6792 sch->ops.name, scx_switched_all() ? "" : " (partial)");
6793 kobject_uevent(&sch->kobj, KOBJ_ADD);
6794 mutex_unlock(&scx_enable_mutex);
6795
6796 atomic_long_inc(&scx_enable_seq);
6797
6798 cmd->ret = 0;
6799 return;
6800
6801 err_free_ksyncs:
6802 free_kick_syncs();
6803 err_unlock:
6804 mutex_unlock(&scx_enable_mutex);
6805 cmd->ret = ret;
6806 return;
6807
6808 err_disable_unlock_all:
6809 scx_cgroup_unlock();
6810 percpu_up_write(&scx_fork_rwsem);
6811 /* we'll soon enter disable path, keep bypass on */
6812 err_disable:
6813 mutex_unlock(&scx_enable_mutex);
6814 /*
6815 * Returning an error code here would not pass all the error information
6816 * to userspace. Record errno using scx_error() for cases scx_error()
6817 * wasn't already invoked and exit indicating success so that the error
6818 * is notified through ops.exit() with all the details.
6819 *
6820 * Flush scx_disable_work to ensure that error is reported before init
6821 * completion. sch's base reference will be put by bpf_scx_unreg().
6822 */
6823 scx_error(sch, "scx_root_enable() failed (%d)", ret);
6824 kthread_flush_work(&sch->disable_work);
6825 cmd->ret = 0;
6826 }
6827
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
reply other threads:[~2026-03-21 1:37 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=202603210903.IrKhPd6k-lkp@intel.com \
--to=lkp@intel.com \
--cc=arighi@nvidia.com \
--cc=llvm@lists.linux.dev \
--cc=oe-kbuild-all@lists.linux.dev \
--cc=tj@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox