diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-03 08:42:54 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2026-10-03 08:42:54 -0700 |
| commit | 903e23eda5af2a5491e698838645f84a8f90379b (patch) | |
| tree | 9d6001d74e512aea4fe4dbaf5b236050e224e11d /drivers/thunderbolt/ctl.c | |
| parent | 8623551a424d34a311bab3fb9243535c98e08c26 (diff) | |
| parent | a93862fa670a9c99fd9a24fb2ef69e4f948d9bd5 (diff) | |
| download | linux-stable-903e23eda5af2a5491e698838645f84a8f90379b.tar.gz linux-stable-903e23eda5af2a5491e698838645f84a8f90379b.zip | |
Merge tag 'usb-7.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/Thunderbolt fixes from Greg KH:
"Here is a big set of USB and Thunderbolt driver fixes for 7.3-rc6.
They were delayed on my side due to conference travel, not the fault
of the submitters at all. Included in here are:
- lots of small thunderbolt fixes for reported issues due to more
testing and devices and a few reverts as well based on that work
- more usb-serial device ids added
- usb-serial and cdc-acm driver hangup and other fixes
- dwc3 driver fixes for reported problems
- lots of usb gadget driver fixes as people again fuzz these drivers
and send in fixes, which is nice to finally see
- typec driver fixes for reported problems
- octeon-hcd driver fixes for reported problems
- more usb-storage quirks added
- other small USB driver bugs resolved for reported problems
All of these have been in linux-next without any reported issues"
* tag 'usb-7.3-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (63 commits)
usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
Revert "usb: dwc3: gadget: fix IRQ storm on invalid event buffer count"
USB: gadget: dummy-hcd: Fix wait for outstanding request completions
usb: typec: port-mapper: Only match USB4 port if host interface is available
usb: cdns3: Fix NULL pointer dereference in cdns3_pci_probe
usb: dwc3: gadget: fix IRQ storm on invalid event buffer count
usb: typec: ucsi: Get the connector fwnode based on reg value
usb: gadget: f_uac1_legacy: validate bRequest index in generic_{set,get}_cmd
usb: core: clear both ep_in and ep_out for non-ep0 control endpoints
USB: cdc-acm: skip URB restart in port_shutdown if disconnected
usb: gadget: f_fs: Fix NULL pointer dereference in FUNCTIONFS_ENDPOINT_DESC
usb: gadget: aspeed-vhub: cancel wake work on device removal
thunderbolt: Disable CL states for the Anker Prime TB5 dock
thunderbolt: stream: Announce support for FMODE_NOWAIT
usb: typec: ucsi: displayport: Current CAM OOB index fixup
usb: ohci-st: disable controller wakeup on removal
usb: ohci-spear: disable controller wakeup on removal
usb: ohci-s3c2410: disable controller wakeup on removal
usb: ohci-da8xx: disable controller wakeup on cleanup
usb: cdns3: fix use-after-free in cdns3_gadget_exit()
...
Diffstat (limited to 'drivers/thunderbolt/ctl.c')
| -rw-r--r-- | drivers/thunderbolt/ctl.c | 63 |
1 files changed, 31 insertions, 32 deletions
diff --git a/drivers/thunderbolt/ctl.c b/drivers/thunderbolt/ctl.c index cd47b627f..965988b18 100644 --- a/drivers/thunderbolt/ctl.c +++ b/drivers/thunderbolt/ctl.c @@ -73,7 +73,6 @@ struct tb_ctl { #define tb_ctl_dbg_once(ctl, format, arg...) \ dev_dbg_once((ctl)->nhi->dev, format, ## arg) -static DECLARE_WAIT_QUEUE_HEAD(tb_cfg_request_cancel_queue); /* Serializes access to request kref_get/put */ static DEFINE_MUTEX(tb_cfg_request_lock); @@ -133,41 +132,42 @@ void tb_cfg_request_put(struct tb_cfg_request *req) static int tb_cfg_request_enqueue(struct tb_ctl *ctl, struct tb_cfg_request *req) { + tb_cfg_request_get(req); + WARN_ON(test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)); WARN_ON(req->ctl); - mutex_lock(&ctl->request_queue_lock); + guard(mutex)(&ctl->request_queue_lock); if (!ctl->running) { - mutex_unlock(&ctl->request_queue_lock); + tb_cfg_request_put(req); return -ENOTCONN; } req->ctl = ctl; list_add_tail(&req->list, &ctl->request_queue); set_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); - mutex_unlock(&ctl->request_queue_lock); return 0; } -static void tb_cfg_request_dequeue(struct tb_cfg_request *req) +static bool tb_cfg_request_is_active(struct tb_cfg_request *req) { - struct tb_ctl *ctl = req->ctl; - - mutex_lock(&ctl->request_queue_lock); - if (!test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags)) { - mutex_unlock(&ctl->request_queue_lock); - return; - } + return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); +} - list_del(&req->list); - clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); - if (test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) - wake_up(&tb_cfg_request_cancel_queue); - mutex_unlock(&ctl->request_queue_lock); +static bool tb_cfg_request_is_canceled(struct tb_cfg_request *req) +{ + return test_bit(TB_CFG_REQUEST_CANCELED, &req->flags); } -static bool tb_cfg_request_is_active(struct tb_cfg_request *req) +static void tb_cfg_request_dequeue(struct tb_cfg_request *req) { - return test_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); + struct tb_ctl *ctl = req->ctl; + + guard(mutex)(&ctl->request_queue_lock); + if (tb_cfg_request_is_active(req)) { + list_del(&req->list); + clear_bit(TB_CFG_REQUEST_ACTIVE, &req->flags); + tb_cfg_request_put(req); + } } static struct tb_cfg_request * @@ -178,7 +178,7 @@ tb_cfg_request_find(struct tb_ctl *ctl, struct ctl_pkg *pkg) mutex_lock(&pkg->ctl->request_queue_lock); list_for_each_entry(iter, &pkg->ctl->request_queue, list) { tb_cfg_request_get(iter); - if (iter->match(iter, pkg)) { + if (!tb_cfg_request_is_canceled(iter) && iter->match(iter, pkg)) { req = iter; break; } @@ -512,8 +512,11 @@ static void tb_ctl_rx_callback(struct tb_ring *ring, struct ring_frame *frame, trace_tb_rx(pkg->ctl->index, frame->eof, pkg->buffer, frame->size, !req); if (req) { - if (req->copy(req, pkg)) - schedule_work(&req->work); + scoped_guard(mutex, &pkg->ctl->request_queue_lock) { + if (!tb_cfg_request_is_canceled(req) && + req->copy(req, pkg)) + schedule_work(&req->work); + } tb_cfg_request_put(req); } @@ -525,11 +528,10 @@ static void tb_cfg_request_work(struct work_struct *work) { struct tb_cfg_request *req = container_of(work, typeof(*req), work); - if (!test_bit(TB_CFG_REQUEST_CANCELED, &req->flags)) + if (!tb_cfg_request_is_canceled(req)) req->callback(req->callback_data); tb_cfg_request_dequeue(req); - tb_cfg_request_put(req); } /** @@ -555,10 +557,9 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, INIT_WORK(&req->work, tb_cfg_request_work); INIT_LIST_HEAD(&req->list); - tb_cfg_request_get(req); ret = tb_cfg_request_enqueue(ctl, req); if (ret) - goto err_put; + return ret; ret = tb_ctl_tx(ctl, req->request, req->request_size, req->request_type); @@ -572,9 +573,6 @@ int tb_cfg_request(struct tb_ctl *ctl, struct tb_cfg_request *req, err_dequeue: tb_cfg_request_dequeue(req); -err_put: - tb_cfg_request_put(req); - return ret; } @@ -588,9 +586,10 @@ err_put: */ void tb_cfg_request_cancel(struct tb_cfg_request *req, int err) { - set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); - schedule_work(&req->work); - wait_event(tb_cfg_request_cancel_queue, !tb_cfg_request_is_active(req)); + scoped_guard(mutex, &req->ctl->request_queue_lock) + set_bit(TB_CFG_REQUEST_CANCELED, &req->flags); + cancel_work_sync(&req->work); + tb_cfg_request_dequeue(req); req->result.err = err; } |
