diff options
| author | James Hilliard <james.hilliard1@gmail.com> | 2026-10-26 12:11:30 -0600 |
|---|---|---|
| committer | Jakub Kicinski <kuba@kernel.org> | 2026-10-30 16:15:58 -0700 |
| commit | d3fcce5afe3bb62e8f7a2efb29e43da4fe4ae1f3 (patch) | |
| tree | 39c056788279dca0954d0228ccfecb95bd411995 | |
| parent | d1bdfdafd663dd00b01d43eb3391f87718f2a09d (diff) | |
ptp: vclock: serialize extended samples with counter updates
The extended and cross-timestamp callbacks sample the physical clock
before taking the virtual clock mutex. A concurrent frequency adjustment
can advance the timecounter and change its multiplier in between, so the
older sample is converted using a different frequency than the one in
effect when it was taken.
Take the mutex before sampling and keep it held through the conversion.
Retain timecounter_cyc2time() and its existing conversion window. A PHC
sample need not advance the counter: for example, e1000e explicitly
allows non-monotonic SYSTIM readings. Treating a slightly older sample
as a forward delta would instead advance virtual time by nearly a full
counter wrap.
This race was found by code inspection of the virtual clock sampling
paths.
Fixes: f0067ebfc42b ("ptp: add gettimex64() to virtual clocks.")
Fixes: 21fad63084c2 ("ptp: add getcrosststamp() to virtual clocks.")
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-4-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
| -rw-r--r-- | drivers/ptp/ptp_vclock.c | 32 |
1 files changed, 14 insertions, 18 deletions
diff --git a/drivers/ptp/ptp_vclock.c b/drivers/ptp/ptp_vclock.c index b97f3a877260..679ae40916f7 100644 --- a/drivers/ptp/ptp_vclock.c +++ b/drivers/ptp/ptp_vclock.c @@ -115,20 +115,18 @@ static int ptp_vclock_gettimex(struct ptp_clock_info *ptp, struct ptp_clock *pptp = vclock->pclock; struct timespec64 pts; int err; - u64 ns; - - err = pptp->info->getcyclesx64(pptp->info, &pts, sts); - if (err) - return err; if (mutex_lock_interruptible(&vclock->lock)) return -EINTR; - ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts)); - mutex_unlock(&vclock->lock); + err = pptp->info->getcyclesx64(pptp->info, &pts, sts); + if (!err) { + u64 ns = timecounter_cyc2time(&vclock->tc, timespec64_to_ns(&pts)); - *ts = ns_to_timespec64(ns); + *ts = ns_to_timespec64(ns); + } + mutex_unlock(&vclock->lock); - return 0; + return err; } static int ptp_vclock_settime(struct ptp_clock_info *ptp, @@ -154,20 +152,18 @@ static int ptp_vclock_getcrosststamp(struct ptp_clock_info *ptp, struct ptp_vclock *vclock = info_to_vclock(ptp); struct ptp_clock *pptp = vclock->pclock; int err; - u64 ns; - - err = pptp->info->getcrosscycles(pptp->info, xtstamp); - if (err) - return err; if (mutex_lock_interruptible(&vclock->lock)) return -EINTR; - ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device)); - mutex_unlock(&vclock->lock); + err = pptp->info->getcrosscycles(pptp->info, xtstamp); + if (!err) { + u64 ns = timecounter_cyc2time(&vclock->tc, ktime_to_ns(xtstamp->device)); - xtstamp->device = ns_to_ktime(ns); + xtstamp->device = ns_to_ktime(ns); + } + mutex_unlock(&vclock->lock); - return 0; + return err; } static long ptp_vclock_refresh(struct ptp_clock_info *ptp) |
