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 | if (sch->sub_kset) | 5735 | if (sch->sub_kset) |
| 5736 | kobject_del(&sch->sub_kset->kobj); | 5736 | kobject_del(&sch->sub_kset->kobj); |
| 5737 | #endif | 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 | free_kick_syncs(); | 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 | * disable. Released in scx_sched_free_rcu_work(). | 6456 | * disable. Released in scx_sched_free_rcu_work(). |
| 6455 | */ | 6457 | */ |
| 6456 | kobject_get(&parent->kobj); | 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 | #endif /* CONFIG_EXT_SUB_SCHED */ | 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 | * Consume the arena_map ref bpf_scx_reg_cid() took. Defer to here so | 6469 | * Consume the arena_map ref bpf_scx_reg_cid() took. Defer to here so |
| 6489 | * earlier failure paths leave cmd->arena_map set and bpf_scx_reg_cid | 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 | return ERR_PTR(ret); | 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 | static int check_hotplug_seq(struct scx_sched *sch, | 6555 | static int check_hotplug_seq(struct scx_sched *sch, |
| 6545 | const struct sched_ext_ops *ops) | 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 | sch->exit_info->flags |= SCX_EFLAG_INITIALIZED; | 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 | for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++) | 6783 | for (i = SCX_OPI_CPU_HOTPLUG_BEGIN; i < SCX_OPI_CPU_HOTPLUG_END; i++) |
| 6767 | if (((void (**)(void))ops)[i]) | 6784 | if (((void (**)(void))ops)[i]) |
| 6768 | set_bit(i, sch->has_op); | 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 | struct cgroup *cgrp, | 1690 | struct cgroup *cgrp, |
| 1691 | struct scx_sched *parent); | 1691 | struct scx_sched *parent); |
| 1692 | int scx_validate_ops(struct scx_sched *sch, const struct sched_ext_ops *ops); | 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 | extern raw_spinlock_t scx_sched_lock; | 1695 | extern raw_spinlock_t scx_sched_lock; |
| 1695 | extern struct mutex scx_enable_mutex; | 1696 | extern struct mutex scx_enable_mutex; |
| @@ -270,7 +270,9 @@ void scx_sub_disable(struct scx_sched *sch) · 269 unmodified lines | |||
| 270 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); | 270 | SCX_CALL_OP(sch, exit, NULL, sch->exit_info); |
| 271 | if (sch->sub_kset) | 271 | if (sch->sub_kset) |
| 272 | kobject_del(&sch->sub_kset->kobj); | 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 | /* verify that a scheduler can be attached to @cgrp and return the parent */ | 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 | if (ret) | 365 | if (ret) |
| 364 | goto err_disable; | 366 | goto err_disable; |
| 365 | 367 | ||
| 368 | ret = scx_sched_sysfs_add(sch); | ||
| 369 | if (ret) | ||
| 370 | goto err_disable; | ||
| 371 | |||
| 366 | if (sch->level >= SCX_SUB_MAX_DEPTH) { | 372 | if (sch->level >= SCX_SUB_MAX_DEPTH) { |
| 367 | scx_error(sch, "max nesting depth %d violated", | 373 | scx_error(sch, "max nesting depth %d violated", |
| 368 | SCX_SUB_MAX_DEPTH); | 374 | SCX_SUB_MAX_DEPTH); |