mirror of
https://github.com/torvalds/linux.git
synced 2026-11-06 21:58:01 +01:00
ptp: drain virtual clock sysfs operations before unregistering children
Parent clock removal walks its virtual clocks before removing the
n_vclocks sysfs attribute. The mutex taken by ptp_vclock_in_use() is
released before that walk, so a concurrent sysfs deletion can pick the
same child and unregister and free its ptp_vclock a second time. A
reference held by the device iterator does not protect that separately
allocated virtual clock.
Remove n_vclocks before walking the children. Removing the attribute
prevents new stores and drains stores already running, without holding
n_vclocks_mux across a callback that needs that mutex. Skip virtual
clocks, which do not have this attribute.
This race was found by code inspection of virtual-clock registration
failure cleanup and parent removal.
Fixes: bfcbb76b0f ("ptp: unregister virtual clocks when unregistering physical clock.")
Reviewed-by: Vadim Fedorenko <vadim.fedorenko@linux.dev>
Signed-off-by: James Hilliard <james.hilliard1@gmail.com>
Link: https://patch.msgid.link/20261026-ptp-vclock-sampling-v6-1-e705612541f1@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
603a0c40d4
commit
0e4a135aeb
|
|
@ -508,6 +508,11 @@ static int unregister_vclock(struct device *dev, void *data)
|
|||
|
||||
int ptp_clock_unregister(struct ptp_clock *ptp)
|
||||
{
|
||||
/*
|
||||
* Stop and drain virtual-clock creation and deletion before walking the
|
||||
* children. Do not hold n_vclocks_mux while waiting for sysfs callbacks.
|
||||
*/
|
||||
ptp_vclock_remove_sysfs(ptp);
|
||||
if (ptp_vclock_in_use(ptp)) {
|
||||
device_for_each_child(&ptp->dev, NULL, unregister_vclock);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ extern const struct attribute_group *ptp_groups[];
|
|||
|
||||
int ptp_populate_pin_groups(struct ptp_clock *ptp);
|
||||
void ptp_cleanup_pin_groups(struct ptp_clock *ptp);
|
||||
void ptp_vclock_remove_sysfs(struct ptp_clock *ptp);
|
||||
|
||||
struct ptp_vclock *ptp_vclock_register(struct ptp_clock *pclock);
|
||||
void ptp_vclock_unregister(struct ptp_vclock *vclock);
|
||||
|
|
|
|||
|
|
@ -267,6 +267,12 @@ static ssize_t n_vclocks_store(struct device *dev,
|
|||
}
|
||||
static DEVICE_ATTR_RW(n_vclocks);
|
||||
|
||||
void ptp_vclock_remove_sysfs(struct ptp_clock *ptp)
|
||||
{
|
||||
if (!ptp->is_virtual_clock)
|
||||
device_remove_file(&ptp->dev, &dev_attr_n_vclocks);
|
||||
}
|
||||
|
||||
static ssize_t max_vclocks_show(struct device *dev,
|
||||
struct device_attribute *attr, char *page)
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user