Skip to content

Commit 9502b99

Browse files
Sebastian Andrzej Siewiorgregkh
authored andcommitted
kcov, usb: Don't disable interrupts in kcov_remote_start_usb_softirq()
commit 9528d32 upstream. kcov_remote_start_usb_softirq() the begin of urb's completion callback. HCDs marked HCD_BH will invoke this function from the softirq and in_serving_softirq() will detect this properly. Root-HUB (RH) requests will not be delayed to softirq but complete immediately in IRQ context. This will confuse kcov because in_serving_softirq() will report true if the softirq is served after the hardirq and if the softirq got interrupted by the hardirq in which currently runs. This was addressed by simply disabling interrupts in kcov_remote_start_usb_softirq() which avoided the interruption by the RH while a regular completion callback was invoked. This not only changes the behaviour while kconv is enabled but also breaks PREEMPT_RT because now sleeping locks can no longer be acquired. Revert the previous fix. Address the issue by invoking kcov_remote_start_usb() only if the context is just "serving softirqs" which is identified by checking in_serving_softirq() and in_hardirq() must be false. Fixes: f85d39d ("kcov, usb: disable interrupts in kcov_remote_start_usb_softirq") Cc: stable <stable@kernel.org> Reported-by: Yunseong Kim <ysk@kzalloc.com> Closes: https://lore.kernel.org/all/20250725201400.1078395-2-ysk@kzalloc.com/ Tested-by: Yunseong Kim <ysk@kzalloc.com> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> Link: https://lore.kernel.org/r/20250811082745.ycJqBXMs@linutronix.de Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 913f3c0 commit 9502b99

File tree

2 files changed

+14
-45
lines changed

2 files changed

+14
-45
lines changed

drivers/usb/core/hcd.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,7 +1623,6 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
16231623
struct usb_hcd *hcd = bus_to_hcd(urb->dev->bus);
16241624
struct usb_anchor *anchor = urb->anchor;
16251625
int status = urb->unlinked;
1626-
unsigned long flags;
16271626

16281627
urb->hcpriv = NULL;
16291628
if (unlikely((urb->transfer_flags & URB_SHORT_NOT_OK) &&
@@ -1641,14 +1640,13 @@ static void __usb_hcd_giveback_urb(struct urb *urb)
16411640
/* pass ownership to the completion handler */
16421641
urb->status = status;
16431642
/*
1644-
* Only collect coverage in the softirq context and disable interrupts
1645-
* to avoid scenarios with nested remote coverage collection sections
1646-
* that KCOV does not support.
1647-
* See the comment next to kcov_remote_start_usb_softirq() for details.
1643+
* This function can be called in task context inside another remote
1644+
* coverage collection section, but kcov doesn't support that kind of
1645+
* recursion yet. Only collect coverage in softirq context for now.
16481646
*/
1649-
flags = kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
1647+
kcov_remote_start_usb_softirq((u64)urb->dev->bus->busnum);
16501648
urb->complete(urb);
1651-
kcov_remote_stop_softirq(flags);
1649+
kcov_remote_stop_softirq();
16521650

16531651
usb_anchor_resume_wakeups(anchor);
16541652
atomic_dec(&urb->use_count);

include/linux/kcov.h

Lines changed: 9 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -57,47 +57,21 @@ static inline void kcov_remote_start_usb(u64 id)
5757

5858
/*
5959
* The softirq flavor of kcov_remote_*() functions is introduced as a temporary
60-
* workaround for KCOV's lack of nested remote coverage sections support.
61-
*
62-
* Adding support is tracked in https://bugzilla.kernel.org/show_bug.cgi?id=210337.
63-
*
64-
* kcov_remote_start_usb_softirq():
65-
*
66-
* 1. Only collects coverage when called in the softirq context. This allows
67-
* avoiding nested remote coverage collection sections in the task context.
68-
* For example, USB/IP calls usb_hcd_giveback_urb() in the task context
69-
* within an existing remote coverage collection section. Thus, KCOV should
70-
* not attempt to start collecting coverage within the coverage collection
71-
* section in __usb_hcd_giveback_urb() in this case.
72-
*
73-
* 2. Disables interrupts for the duration of the coverage collection section.
74-
* This allows avoiding nested remote coverage collection sections in the
75-
* softirq context (a softirq might occur during the execution of a work in
76-
* the BH workqueue, which runs with in_serving_softirq() > 0).
77-
* For example, usb_giveback_urb_bh() runs in the BH workqueue with
78-
* interrupts enabled, so __usb_hcd_giveback_urb() might be interrupted in
79-
* the middle of its remote coverage collection section, and the interrupt
80-
* handler might invoke __usb_hcd_giveback_urb() again.
60+
* work around for kcov's lack of nested remote coverage sections support in
61+
* task context. Adding support for nested sections is tracked in:
62+
* https://bugzilla.kernel.org/show_bug.cgi?id=210337
8163
*/
8264

83-
static inline unsigned long kcov_remote_start_usb_softirq(u64 id)
65+
static inline void kcov_remote_start_usb_softirq(u64 id)
8466
{
85-
unsigned long flags = 0;
86-
87-
if (in_serving_softirq()) {
88-
local_irq_save(flags);
67+
if (in_serving_softirq() && !in_hardirq())
8968
kcov_remote_start_usb(id);
90-
}
91-
92-
return flags;
9369
}
9470

95-
static inline void kcov_remote_stop_softirq(unsigned long flags)
71+
static inline void kcov_remote_stop_softirq(void)
9672
{
97-
if (in_serving_softirq()) {
73+
if (in_serving_softirq() && !in_hardirq())
9874
kcov_remote_stop();
99-
local_irq_restore(flags);
100-
}
10175
}
10276

10377
#ifdef CONFIG_64BIT
@@ -131,11 +105,8 @@ static inline u64 kcov_common_handle(void)
131105
}
132106
static inline void kcov_remote_start_common(u64 id) {}
133107
static inline void kcov_remote_start_usb(u64 id) {}
134-
static inline unsigned long kcov_remote_start_usb_softirq(u64 id)
135-
{
136-
return 0;
137-
}
138-
static inline void kcov_remote_stop_softirq(unsigned long flags) {}
108+
static inline void kcov_remote_start_usb_softirq(u64 id) {}
109+
static inline void kcov_remote_stop_softirq(void) {}
139110

140111
#endif /* CONFIG_KCOV */
141112
#endif /* _LINUX_KCOV_H */

0 commit comments

Comments
 (0)