]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ptp: vclock: Switch from RCU to SRCU
authorKurt Kanzenbach <kurt@linutronix.de>
Fri, 29 May 2026 17:11:47 +0000 (19:11 +0200)
committerJakub Kicinski <kuba@kernel.org>
Thu, 4 Jun 2026 01:58:54 +0000 (18:58 -0700)
The usage of PTP vClocks leads immediately to the following issues with
ptp4l with LOCKDEP and DEBUG_ATOMIC_SLEEP enabled: "BUG: sleeping function
called from invalid context".

ptp_convert_timestamp() acquires a mutex_t within a RCU read section.  This
is illegal, because acquiring a mutex_t can result in voluntary scheduling
request which is not allowed within a RCU read section.

Replace the RCU usage with SRCU where sleeping is allowed.

Reported-by: Florian Zeitz <florian.zeitz@schettke.com>
Closes: https://lore.kernel.org/all/00a8cce8-410e-4038-98af-49be6d93d7bd@schettke.com/
Fixes: 67d93ffc0f3c ("ptp: vclock: use mutex to fix "sleep on atomic" bug")
Signed-off-by: Kurt Kanzenbach <kurt@linutronix.de>
Reviewed-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Link: https://patch.msgid.link/20260529-vclock_rcu-v2-1-02a5531fab92@linutronix.de
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
drivers/ptp/ptp_vclock.c

index 915a4f6defc945c1db4c2cc234c3655fcfb23a59..84cb527f59ccc6f2abb8f12e1dcc4b6512f3d48b 100644 (file)
@@ -19,6 +19,8 @@ static DEFINE_SPINLOCK(vclock_hash_lock);
 
 static DEFINE_READ_MOSTLY_HASHTABLE(vclock_hash, 8);
 
+DEFINE_STATIC_SRCU(vclock_srcu);
+
 static void ptp_vclock_hash_add(struct ptp_vclock *vclock)
 {
        spin_lock(&vclock_hash_lock);
@@ -37,7 +39,7 @@ static void ptp_vclock_hash_del(struct ptp_vclock *vclock)
 
        spin_unlock(&vclock_hash_lock);
 
-       synchronize_rcu();
+       synchronize_srcu(&vclock_srcu);
 }
 
 static int ptp_vclock_adjfine(struct ptp_clock_info *ptp, long scaled_ppm)
@@ -276,14 +278,16 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
 {
        unsigned int hash = vclock_index % HASH_SIZE(vclock_hash);
        struct ptp_vclock *vclock;
-       u64 ns;
        u64 vclock_ns = 0;
+       int srcu_idx;
+       u64 ns;
 
        ns = ktime_to_ns(*hwtstamp);
 
-       rcu_read_lock();
+       srcu_idx = srcu_read_lock(&vclock_srcu);
 
-       hlist_for_each_entry_rcu(vclock, &vclock_hash[hash], vclock_hash_node) {
+       hlist_for_each_entry_srcu(vclock, &vclock_hash[hash], vclock_hash_node,
+                                 srcu_read_lock_held(&vclock_srcu)) {
                if (vclock->clock->index != vclock_index)
                        continue;
 
@@ -294,7 +298,7 @@ ktime_t ptp_convert_timestamp(const ktime_t *hwtstamp, int vclock_index)
                break;
        }
 
-       rcu_read_unlock();
+       srcu_read_unlock(&vclock_srcu, srcu_idx);
 
        return ns_to_ktime(vclock_ns);
 }