| @@ -196,9 +196,6 @@ static const struct rhashtable_params dsq_hash_params = { · 195 unmodified lines |
| 196 | | 196 | |
| 197 | static LLIST_HEAD(dsqs_to_free); | 197 | static LLIST_HEAD(dsqs_to_free); |
| 198 | | 198 | |
| 199 | DEFINE_RAW_SPINLOCK(scx_exit_bstr_buf_lock); | | |
| 200 | struct scx_bstr_buf scx_exit_bstr_buf; | | |
| 201 | | | |
| 202 | /* ops debug dump */ | 199 | /* ops debug dump */ |
| 203 | static DEFINE_RAW_SPINLOCK(scx_dump_lock); | 200 | static DEFINE_RAW_SPINLOCK(scx_dump_lock); |
| 204 | | 201 | |
| @@ -6760,17 +6757,12 @@ static void scx_disable_irq_workfn(struct irq_work *irq_work) · 6555 unmodified lines |
| 6760 | kthread_queue_work(sch->helper, &sch->disable_work); | 6757 | kthread_queue_work(sch->helper, &sch->disable_work); |
| 6761 | } | 6758 | } |
| 6762 | | 6759 | |
| 6763 | bool scx_vexit(struct scx_sched *sch, | 6760 | /* finish exit_info and kick the disable work, ei->msg must already be set */ |
| 6764 | enum scx_exit_kind kind, s64 exit_code, s32 exit_cpu, | 6761 | static void scx_finish_exit(struct scx_sched *sch, enum scx_exit_kind kind, |
| 6765 | const char *fmt, va_list args) | 6762 | s64 exit_code, s32 exit_cpu) |
| 6766 | { | 6763 | { |
| 6767 | struct scx_exit_info *ei = sch->exit_info; | 6764 | struct scx_exit_info *ei = sch->exit_info; |
| 6768 | | 6765 | |
| 6769 | guard(preempt)(); | | |
| 6770 | | | |
| 6771 | if (!scx_claim_exit(sch, kind)) | | |
| 6772 | return false; | | |
| 6773 | | | |
| 6774 | ei->exit_code = exit_code; | 6766 | ei->exit_code = exit_code; |
| 6775 | #ifdef CONFIG_STACKTRACE | 6767 | #ifdef CONFIG_STACKTRACE |
| 6776 | /* | 6768 | /* |
| @@ -6780,8 +6772,6 @@ bool scx_vexit(struct scx_sched *sch, · 3 unmodified lines |
| 6780 | if (kind >= SCX_EXIT_ERROR && !in_nmi()) | 6772 | if (kind >= SCX_EXIT_ERROR && !in_nmi()) |
| 6781 | ei->bt_len = stack_trace_save(ei->bt, SCX_EXIT_BT_LEN, 1); | 6773 | ei->bt_len = stack_trace_save(ei->bt, SCX_EXIT_BT_LEN, 1); |
| 6782 | #endif | 6774 | #endif |
| 6783 | vscnprintf(ei->msg, SCX_EXIT_MSG_LEN, fmt, args); | | |
| 6784 | | | |
| 6785 | /* | 6775 | /* |
| 6786 | * Set ei->kind and ->reason for scx_dump_state(). They'll be set again | 6776 | * Set ei->kind and ->reason for scx_dump_state(). They'll be set again |
| 6787 | * in scx_disable_workfn(). | 6777 | * in scx_disable_workfn(). |
| @@ -6791,6 +6781,22 @@ bool scx_vexit(struct scx_sched *sch, · 3 unmodified lines |
| 6791 | ei->exit_cpu = exit_cpu; | 6781 | ei->exit_cpu = exit_cpu; |
| 6792 | | 6782 | |
| 6793 | irq_work_queue(&sch->disable_irq_work); | 6783 | irq_work_queue(&sch->disable_irq_work); |
| | 6784 | } |
| | 6785 | |
| | 6786 | bool scx_vexit(struct scx_sched *sch, |
| | 6787 | enum scx_exit_kind kind, s64 exit_code, s32 exit_cpu, |
| | 6788 | const char *fmt, va_list args) |
| | 6789 | { |
| | 6790 | struct scx_exit_info *ei = sch->exit_info; |
| | 6791 | |
| | 6792 | guard(preempt)(); |
| | 6793 | |
| | 6794 | if (!scx_claim_exit(sch, kind)) |
| | 6795 | return false; |
| | 6796 | |
| | 6797 | vscnprintf(ei->msg, SCX_EXIT_MSG_LEN, fmt, args); |
| | 6798 | |
| | 6799 | scx_finish_exit(sch, kind, exit_code, exit_cpu); |
| 6794 | return true; | 6800 | return true; |
| 6795 | } | 6801 | } |
| 6796 | | 6802 | |
| @@ -9604,12 +9610,38 @@ static s32 __bstr_format(struct scx_sched *sch, u64 *data_buf, char *line_buf, · 2807 unmodified lines |
| 9604 | return ret; | 9610 | return ret; |
| 9605 | } | 9611 | } |
| 9606 | | 9612 | |
| 9607 | __printf(3, 0) | 9613 | /* |
| 9608 | s32 scx_bstr_format(struct scx_sched *sch, struct scx_bstr_buf *buf, | 9614 | * Exit @sch with the reason formatted from a BPF-supplied bstr format. The exit |
| 9609 | char *fmt, unsigned long long *data, u32 data__sz) | 9615 | * is claimed first and the reason is formatted directly into the winner-owned |
| | 9616 | * exit_info buffer, which allows use from any context including NMI. |
| | 9617 | * |
| | 9618 | * @fmt_blame is the sched blamed for formatting failures through the |
| | 9619 | * scx_error() calls in __bstr_format() and differs from @sch when a parent |
| | 9620 | * supplies the kill reason for a child. A formatting failure doesn't revert the |
| | 9621 | * claim - @sch still exits with the claimed kind and a fallback message. |
| | 9622 | */ |
| | 9623 | __printf(5, 0) |
| | 9624 | bool scx_exit_bstr(struct scx_sched *sch, enum scx_exit_kind kind, |
| | 9625 | s64 exit_code, struct scx_sched *fmt_blame, char *fmt, |
| | 9626 | unsigned long long *data, u32 data__sz) |
| 9610 | { | 9627 | { |
| 9611 | return __bstr_format(sch, buf->data, buf->line, sizeof(buf->line), | 9628 | struct scx_exit_info *ei = sch->exit_info; |
| 9612 | fmt, data, data__sz); | 9629 | u64 data_buf[MAX_BPRINTF_VARARGS]; |
| | 9630 | s32 ret; |
| | 9631 | |
| | 9632 | guard(preempt)(); |
| | 9633 | |
| | 9634 | if (!scx_claim_exit(sch, kind)) |
| | 9635 | return false; |
| | 9636 | |
| | 9637 | ret = __bstr_format(fmt_blame, data_buf, ei->msg, SCX_EXIT_MSG_LEN, |
| | 9638 | fmt, data, data__sz); |
| | 9639 | if (ret < 0) |
| | 9640 | scnprintf(ei->msg, SCX_EXIT_MSG_LEN, |
| | 9641 | "exit message formatting failed (%d)", ret); |
| | 9642 | |
| | 9643 | scx_finish_exit(sch, kind, exit_code, raw_smp_processor_id()); |
| | 9644 | return true; |
| 9613 | } | 9645 | } |
| 9614 | | 9646 | |
| 9615 | __bpf_kfunc_start_defs(); | 9647 | __bpf_kfunc_start_defs(); |
| @@ -9631,14 +9663,13 @@ __bpf_kfunc void scx_bpf_exit_bstr(s64 exit_code, char *fmt, · 15 unmodified lines |
| 9631 | const struct bpf_prog_aux *aux) | 9663 | const struct bpf_prog_aux *aux) |
| 9632 | { | 9664 | { |
| 9633 | struct scx_sched *sch; | 9665 | struct scx_sched *sch; |
| 9634 | unsigned long flags; | | |
| 9635 | | 9666 | |
| 9636 | raw_spin_lock_irqsave(&scx_exit_bstr_buf_lock, flags); | 9667 | guard(rcu)(); |
| | 9668 | |
| 9637 | sch = scx_prog_sched(aux); | 9669 | sch = scx_prog_sched(aux); |
| 9638 | if (likely(sch) && | 9670 | if (likely(sch)) |
| 9639 | scx_bstr_format(sch, &scx_exit_bstr_buf, fmt, data, data__sz) >= 0) | 9671 | scx_exit_bstr(sch, SCX_EXIT_UNREG_BPF, exit_code, sch, fmt, |
| 9640 | scx_exit(sch, SCX_EXIT_UNREG_BPF, exit_code, "%s", scx_exit_bstr_buf.line); | 9672 | data, data__sz); |
| 9641 | raw_spin_unlock_irqrestore(&scx_exit_bstr_buf_lock, flags); | | |
| 9642 | } | 9673 | } |
| 9643 | | 9674 | |
| 9644 | /** | 9675 | /** |
| @@ -9656,14 +9687,13 @@ __bpf_kfunc void scx_bpf_error_bstr(char *fmt, unsigned long long *data, · 11 unmodified lines |
| 9656 | u32 data__sz, const struct bpf_prog_aux *aux) | 9687 | u32 data__sz, const struct bpf_prog_aux *aux) |
| 9657 | { | 9688 | { |
| 9658 | struct scx_sched *sch; | 9689 | struct scx_sched *sch; |
| 9659 | unsigned long flags; | | |
| 9660 | | 9690 | |
| 9661 | raw_spin_lock_irqsave(&scx_exit_bstr_buf_lock, flags); | 9691 | guard(rcu)(); |
| | 9692 | |
| 9662 | sch = scx_prog_sched(aux); | 9693 | sch = scx_prog_sched(aux); |
| 9663 | if (likely(sch) && | 9694 | if (likely(sch)) |
| 9664 | scx_bstr_format(sch, &scx_exit_bstr_buf, fmt, data, data__sz) >= 0) | 9695 | scx_exit_bstr(sch, SCX_EXIT_ERROR_BPF, 0, sch, fmt, data, |
| 9665 | scx_exit(sch, SCX_EXIT_ERROR_BPF, 0, "%s", scx_exit_bstr_buf.line); | 9696 | data__sz); |
| 9666 | raw_spin_unlock_irqrestore(&scx_exit_bstr_buf_lock, flags); | | |
| 9667 | } | 9697 | } |
| 9668 | | 9698 | |
| 9669 | /** | 9699 | /** |