All of lore.kernel.org
 help / color / mirror / Atom feed
From: Mika Westerberg <mika.westerberg@linux.intel.com>
To: linux-usb@vger.kernel.org
Cc: Yehezkel Bernat <YehezkelShB@gmail.com>,
	Lukas Wunner <lukas@wunner.de>,
	Andreas Noever <andreas.noever@gmail.com>,
	Alan Borzeszkowski <alan.borzeszkowski@linux.intel.com>,
	Milo Chen <cmh79479@gmail.com>,
	Mika Westerberg <mika.westerberg@linux.intel.com>
Subject: [PATCH 2/3] thunderbolt: Use separate lock class for each ring
Date: Mon, 31 Aug 2026 15:18:39 +0200	[thread overview]
Message-ID: <20260831131840.1982842-3-mika.westerberg@linux.intel.com> (raw)
In-Reply-To: <20260831131840.1982842-1-mika.westerberg@linux.intel.com>

When connected to another host and then unplugging cable lockdep
triggers following:

 ======================================================
 WARNING: possible circular locking dependency detected
 7.1.0-rc2+ #1775 Tainted: G     U
 ------------------------------------------------------
 kworker/u16:6/312 is trying to acquire lock:
 ffff8881179c70a8 ((work_completion)(&ring->work)){+.+.}-{0:0}, at: __flush_work+0x3cf/0xd10

 but task is already holding lock:
 ffff8881a8b810b0 (&net->connection_lock){+.+.}-{4:4}, at: tbnet_tear_down+0x110/0x720 [thunderbolt_net]

 which lock already depends on the new lock.

 the existing dependency chain (in reverse order) is:

 -> #1 (&net->connection_lock){+.+.}-{4:4}:
        __mutex_lock+0x19a/0x2490
        mutex_lock_nested+0x1b/0x30
        tbnet_handle_packet+0x74c/0xd70 [thunderbolt_net]
        tb_xdomain_handle_request+0x37c/0x4b0 [thunderbolt]
        tb_domain_event_cb+0xc9/0x140 [thunderbolt]
        tb_ctl_handle_event+0xd6/0x2c0 [thunderbolt]
        tb_ctl_rx_callback+0x22c/0xa10 [thunderbolt]
        ring_work+0x715/0xcb0 [thunderbolt]
        process_one_work+0x902/0x1790
        worker_thread+0x5cd/0xfe0
        kthread+0x339/0x420
        ret_from_fork+0x79a/0x9d0
        ret_from_fork_asm+0x1a/0x30

 -> #0 ((work_completion)(&ring->work)){+.+.}-{0:0}:
        __lock_acquire+0x1592/0x2640
        lock_acquire+0x1a3/0x300
        __flush_work+0x3e9/0xd10
        flush_work+0x21/0x30
        tb_ring_stop+0x240/0x840 [thunderbolt]
        tbnet_tear_down+0x2ff/0x720 [thunderbolt_net]
        tbnet_stop+0x47/0x1a0 [thunderbolt_net]
        __dev_close_many+0x19e/0x4e0
        netif_close_many+0x1e8/0x640
        unregister_netdevice_many_notify+0x6d3/0x22d0
        unregister_netdevice_queue+0x2b9/0x3a0
        unregister_netdev+0x1c/0x70
        tbnet_remove+0x52/0xb0 [thunderbolt_net]
        tb_service_remove+0x8a/0xe0 [thunderbolt]
        device_remove+0xc5/0x190
        device_release_driver_internal+0x3db/0x590
        device_release_driver+0x12/0x20
        bus_remove_device+0x2c1/0x580
        device_del+0x3d9/0x9f0
        device_unregister+0x17/0xc0
        unregister_service+0x46/0x60 [thunderbolt]
        device_for_each_child_reverse+0xfa/0x180
        tb_xdomain_unregister+0x57/0xe0 [thunderbolt]
        unregister_unplugged_xdomain+0x101/0x1a0 [thunderbolt]
        bus_for_each_dev+0x111/0x1a0
        tb_domain_unregister_unplugged_xdomains+0x98/0xe0 [thunderbolt]
        tb_handle_hotplug+0xc3/0x2bb0 [thunderbolt]
        process_one_work+0x902/0x1790
        worker_thread+0x5cd/0xfe0
        kthread+0x339/0x420
        ret_from_fork+0x79a/0x9d0
        ret_from_fork_asm+0x1a/0x30

 other info that might help us debug this:

  Possible unsafe locking scenario:

        CPU0                    CPU1
        ----                    ----
   lock(&net->connection_lock);
                                lock((work_completion)(&ring->work));
                                lock(&net->connection_lock);
   lock((work_completion)(&ring->work));

This in fact is false positive because they involve unrelated rings (and
unrelated work structures). In the first one it is ring 0 which is used
for control traffic and in the second it is dealing with another ring
used for the high-speed traffic.

Fix this by using separate lock class for each ring worker.

Signed-off-by: Mika Westerberg <mika.westerberg@linux.intel.com>
---
 drivers/thunderbolt/nhi.c   | 5 +++++
 include/linux/thunderbolt.h | 3 +++
 2 files changed, 8 insertions(+)

diff --git a/drivers/thunderbolt/nhi.c b/drivers/thunderbolt/nhi.c
index 5809809f64d4..d4d1efa2afa0 100644
--- a/drivers/thunderbolt/nhi.c
+++ b/drivers/thunderbolt/nhi.c
@@ -15,6 +15,7 @@
 #include <linux/dma-mapping.h>
 #include <linux/interrupt.h>
 #include <linux/iommu.h>
+#include <linux/lockdep.h>
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/property.h>
@@ -560,6 +561,8 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
 	INIT_LIST_HEAD(&ring->in_flight);
 	INIT_WORK(&ring->work, ring_work);
 	init_waitqueue_head(&ring->wait);
+	lockdep_register_key(&ring->lock_key);
+	lockdep_init_map(&ring->work.lockdep_map, "ring.work", &ring->lock_key, 0);
 
 	ring->nhi = nhi;
 	ring->hop = hop;
@@ -599,6 +602,7 @@ static struct tb_ring *tb_ring_alloc(struct tb_nhi *nhi, u32 hop, int size,
 			  ring->size * sizeof(*ring->descriptors),
 			  ring->descriptors, ring->descriptors_dma);
 err_free_ring:
+	lockdep_unregister_key(&ring->lock_key);
 	kfree(ring);
 
 	return NULL;
@@ -848,6 +852,7 @@ void tb_ring_free(struct tb_ring *ring)
 	 * to finish before freeing the ring.
 	 */
 	flush_work(&ring->work);
+	lockdep_unregister_key(&ring->lock_key);
 	kfree(ring);
 }
 EXPORT_SYMBOL_GPL(tb_ring_free);
diff --git a/include/linux/thunderbolt.h b/include/linux/thunderbolt.h
index d48623fda79b..b62dfa52b149 100644
--- a/include/linux/thunderbolt.h
+++ b/include/linux/thunderbolt.h
@@ -22,6 +22,7 @@ struct device;
 #include <linux/device.h>
 #include <linux/idr.h>
 #include <linux/list.h>
+#include <linux/lockdep.h>
 #include <linux/mutex.h>
 #include <linux/device-id/tb.h>
 #include <linux/pci.h>
@@ -565,6 +566,7 @@ struct tb_nhi {
  * @interval_nsec: Interval counter if interrupt throttling is to be
  *		   used with this ring (in ns)
  * @wait: Used to signal that the ring may be empty now
+ * @lock_key: Lock validator class key per-ring
  */
 struct tb_ring {
 	spinlock_t lock;
@@ -590,6 +592,7 @@ struct tb_ring {
 	void *poll_data;
 	unsigned int interval_nsec;
 	wait_queue_head_t wait;
+	struct lock_class_key lock_key;
 };
 
 /* Leave ring interrupt enabled on suspend */
-- 
2.50.1


  parent reply	other threads:[~2026-08-31 13:18 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31 13:18 [PATCH 0/3] thunderbolt: Couple of fixes for reported issues Mika Westerberg
2026-08-31 13:18 ` [PATCH 1/3] thunderbolt: Fix KASAN reported use-after-free when request is canceled Mika Westerberg
2026-08-31 13:18 ` Mika Westerberg [this message]
2026-08-31 13:18 ` [PATCH 3/3] Revert "thunderbolt: xdomain: Notify peers after enumeration" Mika Westerberg
2026-09-04  6:36 ` [PATCH 0/3] thunderbolt: Couple of fixes for reported issues Mika Westerberg

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260831131840.1982842-3-mika.westerberg@linux.intel.com \
    --to=mika.westerberg@linux.intel.com \
    --cc=YehezkelShB@gmail.com \
    --cc=alan.borzeszkowski@linux.intel.com \
    --cc=andreas.noever@gmail.com \
    --cc=cmh79479@gmail.com \
    --cc=linux-usb@vger.kernel.org \
    --cc=lukas@wunner.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.