Split kobject_init_and_add() in scx_alloc_and_add_sched(): only kobject_init() runs there. A new scx_sched_sysfs_add() helper does kobject_add() (and creates sub_kset when the scheduler implements ops.sub_attach), called by both enable workfns once @sch is linked and its sysfs-visible state is initialized. Prep so a future caps attribute can rely on @sch being fully built by the time it's sysfs-visible. Add early enough that a stall later in enable still leaves sysfs inspectable.
Showing the changes to kernel (3 of 3 files). Show all
Unified · Split
| @@ -5735,7 +5735,9 @@ static void scx_root_disable(struct scx_sched *sch) · 5734 unmodified lines | ||
| 5735 | 5735 | if (sch->sub_kset) |
| 5736 | 5736 | kobject_del(&sch->sub_kset->kobj); |
| 5737 | 5737 | #endif |
| 5738 | − kobject_del(&sch->kobj); | |
| 5738 | + /* not added if enable failed before scx_sched_sysfs_add() */ | |
| 5739 | + if (sch->kobj.state_in_sysfs) | |
| 5740 | + kobject_del(&sch->kobj); | |
| 5739 | 5741 | |
| 5740 | 5742 | free_kick_syncs(); |
| 5741 | 5743 | |
| @@ -6454,36 +6456,15 @@ struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 712 unmodified lines | ||
| 6454 | 6456 | * disable. Released in scx_sched_free_rcu_work(). |
| 6455 | 6457 | */ |
| 6456 | 6458 | kobject_get(&parent->kobj); |
| 6457 | − ret = kobject_init_and_add(&sch->kobj, &scx_ktype, | |
| 6458 | − &parent->sub_kset->kobj, | |
| 6459 | − "sub-%llu", cgroup_id(cgrp)); | |
| 6460 | − } else { | |
| 6461 | − ret = kobject_init_and_add(&sch->kobj, &scx_ktype, NULL, "root"); | |
| 6462 | − } | |
| 6463 | − | |
| 6464 | − if (ret < 0) { | |
| 6465 | − RCU_INIT_POINTER(ops->priv, NULL); | |
| 6466 | − kobject_put(&sch->kobj); | |
| 6467 | − return ERR_PTR(ret); | |
| 6468 | − } | |
| 6469 | − | |
| 6470 | − if (ops->sub_attach) { | |
| 6471 | − sch->sub_kset = kset_create_and_add("sub", NULL, &sch->kobj); | |
| 6472 | − if (!sch->sub_kset) { | |
| 6473 | − RCU_INIT_POINTER(ops->priv, NULL); | |
| 6474 | − kobject_put(&sch->kobj); | |
| 6475 | − return ERR_PTR(-ENOMEM); | |
| 6476 | − } | |
| 6477 | − } | |
| 6478 | −#else /* CONFIG_EXT_SUB_SCHED */ | |
| 6479 | − ret = kobject_init_and_add(&sch->kobj, &scx_ktype, NULL, "root"); | |
| 6480 | − if (ret < 0) { | |
| 6481 | − RCU_INIT_POINTER(ops->priv, NULL); | |
| 6482 | − kobject_put(&sch->kobj); | |
| 6483 | − return ERR_PTR(ret); | |
| 6484 | 6459 | } |
| 6485 | 6460 | #endif /* CONFIG_EXT_SUB_SCHED */ |
| 6486 | 6461 | |
| 6462 | + /* | |
| 6463 | + * Init the kobj but don't add to sysfs yet. The enable path calls | |
| 6464 | + * scx_sched_sysfs_add() once @sch's sysfs-visible state is initialized. | |
| 6465 | + */ | |
| 6466 | + kobject_init(&sch->kobj, &scx_ktype); | |
| 6467 | + | |
| 6487 | 6468 | /* |
| 6488 | 6469 | * Consume the arena_map ref bpf_scx_reg_cid() took. Defer to here so |
| 6489 | 6470 | * earlier failure paths leave cmd->arena_map set and bpf_scx_reg_cid |
| @@ -6541,6 +6522,36 @@ err_put_cgrp: · 51 unmodified lines | ||
| 6541 | 6522 | return ERR_PTR(ret); |
| 6542 | 6523 | } |
| 6543 | 6524 | |
| 6525 | +/* | |
| 6526 | + * Add @sch's kobject to sysfs, and create its sub_kset if the scheduler | |
| 6527 | + * implements ops.sub_attach. Called by the enable workfns once @sch's | |
| 6528 | + * sysfs-visible state is initialized. | |
| 6529 | + */ | |
| 6530 | +int scx_sched_sysfs_add(struct scx_sched *sch) | |
| 6531 | +{ | |
| 6532 | +#ifdef CONFIG_EXT_SUB_SCHED | |
| 6533 | + struct scx_sched *parent = scx_parent(sch); | |
| 6534 | + int ret; | |
| 6535 | + | |
| 6536 | + if (parent) | |
| 6537 | + ret = kobject_add(&sch->kobj, &parent->sub_kset->kobj, | |
| 6538 | + "sub-%llu", cgroup_id(sch_cgroup(sch))); | |
| 6539 | + else | |
| 6540 | + ret = kobject_add(&sch->kobj, NULL, "root"); | |
| 6541 | + if (ret < 0) | |
| 6542 | + return ret; | |
| 6543 | + | |
| 6544 | + if (sch->ops.sub_attach) { | |
| 6545 | + sch->sub_kset = kset_create_and_add("sub", NULL, &sch->kobj); | |
| 6546 | + if (!sch->sub_kset) | |
| 6547 | + return -ENOMEM; | |
| 6548 | + } | |
| 6549 | + return 0; | |
| 6550 | +#else | |
| 6551 | + return kobject_add(&sch->kobj, NULL, "root"); | |
| 6552 | +#endif | |
| 6553 | +} | |
| 6554 | + | |
| 6544 | 6555 | static int check_hotplug_seq(struct scx_sched *sch, |
| 6545 | 6556 | const struct sched_ext_ops *ops) |
| 6546 | 6557 | { |
| @@ -6763,6 +6774,12 @@ static void scx_root_enable_workfn(struct kthread_work *work) · 216 unmodified lines | ||
| 6763 | 6774 | sch->exit_info->flags |= SCX_EFLAG_INITIALIZED; |
| 6764 | 6775 | } |
| 6765 | 6776 | |
| 6777 | + ret = scx_sched_sysfs_add(sch); | |
| 6778 | + if (ret) { | |
| 6779 | + cpus_read_unlock(); | |
| 6780 | + goto err_disable; | |
| 6781 | + } | |
| 6782 | + | |
| 6766 | 6783 | for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++) |
| 6767 | 6784 | if (((void (**)(void))ops)[i]) |
| 6768 | 6785 | set_bit(i, sch->has_op); |
| @@ -1690,6 +1690,7 @@ struct scx_sched *scx_alloc_and_add_sched(struct scx_enable_cmd *cmd, · 1689 unmodified lines | ||
| 1690 | 1690 | struct cgroup *cgrp, |
| 1691 | 1691 | struct scx_sched *parent); |
| 1692 | 1692 | int scx_validate_ops(struct scx_sched *sch, const struct sched_ext_ops *ops); |
| 1693 | +int scx_sched_sysfs_add(struct scx_sched *sch); | |
| 1693 | 1694 | |
| 1694 | 1695 | extern raw_spinlock_t scx_sched_lock; |
| 1695 | 1696 | extern struct mutex scx_enable_mutex; |
| @@ -270,7 +270,9 @@ void scx_sub_disable(struct scx_sched *sch) · 269 unmodified lines | ||
| 270 | 270 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); |
| 271 | 271 | if (sch->sub_kset) |
| 272 | 272 | kobject_del(&sch->sub_kset->kobj); |
| 273 | − kobject_del(&sch->kobj); | |
| 273 | + /* not added if enable failed before scx_sched_sysfs_add() */ | |
| 274 | + if (sch->kobj.state_in_sysfs) | |
| 275 | + kobject_del(&sch->kobj); | |
| 274 | 276 | } |
| 275 | 277 | |
| 276 | 278 | /* verify that a scheduler can be attached to @cgrp and return the parent */ |
| @@ -363,6 +365,10 @@ void scx_sub_enable_workfn(struct kthread_work *work) · 86 unmodified lines | ||
| 363 | 365 | if (ret) |
| 364 | 366 | goto err_disable; |
| 365 | 367 | |
| 368 | + ret = scx_sched_sysfs_add(sch); | |
| 369 | + if (ret) | |
| 370 | + goto err_disable; | |
| 371 | + | |
| 366 | 372 | if (sch->level >= SCX_SUB_MAX_DEPTH) { |
| 367 | 373 | scx_error(sch, "max nesting depth %d violated", |
| 368 | 374 | SCX_SUB_MAX_DEPTH); |