| @@ -196,9 +196,6 @@ static const struct rhashtable_params dsq_hash_params = { · 195 unmodified lines |
| 196 | 196 | |
| 197 | 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 | 199 | /* ops debug dump */ |
| 203 | 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 | 6757 | kthread_queue_work(sch->helper, &sch->disable_work); |
| 6761 | 6758 | } |
| 6762 | 6759 | |
| 6763 | | −bool scx_vexit(struct scx_sched *sch, |
| 6764 | | − enum scx_exit_kind kind, s64 exit_code, s32 exit_cpu, |
| 6765 | | − const char *fmt, va_list args) |
| 6760 | +/* finish exit_info and kick the disable work, ei->msg must already be set */ |
| 6761 | +static void scx_finish_exit(struct scx_sched *sch, enum scx_exit_kind kind, |
| 6762 | + s64 exit_code, s32 exit_cpu) |
| 6766 | 6763 | { |
| 6767 | 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 | 6766 | ei->exit_code = exit_code; |
| 6775 | 6767 | #ifdef CONFIG_STACKTRACE |
| 6776 | 6768 | /* |
| @@ -6780,8 +6772,6 @@ bool scx_vexit(struct scx_sched *sch, · 3 unmodified lines |
| 6780 | 6772 | if (kind >= SCX_EXIT_ERROR && !in_nmi()) |
| 6781 | 6773 | ei->bt_len = stack_trace_save(ei->bt, SCX_EXIT_BT_LEN, 1); |
| 6782 | 6774 | #endif |
| 6783 | | − vscnprintf(ei->msg, SCX_EXIT_MSG_LEN, fmt, args); |
| 6784 | | − |
| 6785 | 6775 | /* |
| 6786 | 6776 | * Set ei->kind and ->reason for scx_dump_state(). They'll be set again |
| 6787 | 6777 | * in scx_disable_workfn(). |
| @@ -6791,6 +6781,22 @@ bool scx_vexit(struct scx_sched *sch, · 3 unmodified lines |
| 6791 | 6781 | ei->exit_cpu = exit_cpu; |
| 6792 | 6782 | |
| 6793 | 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 | 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 | 9610 | return ret; |
| 9605 | 9611 | } |
| 9606 | 9612 | |
| 9607 | | −__printf(3, 0) |
| 9608 | | −s32 scx_bstr_format(struct scx_sched *sch, struct scx_bstr_buf *buf, |
| 9609 | | − char *fmt, unsigned long long *data, u32 data__sz) |
| 9613 | +/* |
| 9614 | + * Exit @sch with the reason formatted from a BPF-supplied bstr format. The exit |
| 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), |
| 9612 | | − fmt, data, data__sz); |
| 9628 | + struct scx_exit_info *ei = sch->exit_info; |
| 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 | 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 | 9663 | const struct bpf_prog_aux *aux) |
| 9632 | 9664 | { |
| 9633 | 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 | 9669 | sch = scx_prog_sched(aux); |
| 9638 | | − if (likely(sch) && |
| 9639 | | − scx_bstr_format(sch, &scx_exit_bstr_buf, fmt, data, data__sz) >= 0) |
| 9640 | | − scx_exit(sch, SCX_EXIT_UNREG_BPF, exit_code, "%s", scx_exit_bstr_buf.line); |
| 9641 | | − raw_spin_unlock_irqrestore(&scx_exit_bstr_buf_lock, flags); |
| 9670 | + if (likely(sch)) |
| 9671 | + scx_exit_bstr(sch, SCX_EXIT_UNREG_BPF, exit_code, sch, fmt, |
| 9672 | + data, data__sz); |
| 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 | 9687 | u32 data__sz, const struct bpf_prog_aux *aux) |
| 9657 | 9688 | { |
| 9658 | 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 | 9693 | sch = scx_prog_sched(aux); |
| 9663 | | − if (likely(sch) && |
| 9664 | | − scx_bstr_format(sch, &scx_exit_bstr_buf, fmt, data, data__sz) >= 0) |
| 9665 | | − scx_exit(sch, SCX_EXIT_ERROR_BPF, 0, "%s", scx_exit_bstr_buf.line); |
| 9666 | | − raw_spin_unlock_irqrestore(&scx_exit_bstr_buf_lock, flags); |
| 9694 | + if (likely(sch)) |
| 9695 | + scx_exit_bstr(sch, SCX_EXIT_ERROR_BPF, 0, sch, fmt, data, |
| 9696 | + data__sz); |
| 9667 | 9697 | } |
| 9668 | 9698 | |
| 9669 | 9699 | /** |