n_vclocks_store() publishes the new clock count only after every child
has been registered. If a later registration fails, it returns without
unregistering the children already created by that request. Those clocks
are left out of n_vclocks, and a subsequent request can overwrite their
index entries without removing them.
Unregister the newly created children in reverse order and clear their
index entries on failure. Leave the previously installed clocks and
their count unchanged. The n_vclocks mutex serializes this rollback with
other sysfs changes, and parent removal drains the store before walking
the children.
This was found by code inspection while adding initial PHC sample error
handling to virtual clock registration.
Fixes: 73f37068d540 ("ptp: support ptp physical/virtual clocks conversion")
Signed-off-by: James Hilliard <redacted>
---
drivers/ptp/ptp_sysfs.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/ptp/ptp_sysfs.c b/drivers/ptp/ptp_sysfs.c
index 53388b123198..fabc1c9b1752 100644
--- a/drivers/ptp/ptp_sysfs.c
+++ b/drivers/ptp/ptp_sysfs.c
@@ -225,7 +225,7 @@ static ssize_t n_vclocks_store(struct device *dev,
for (i = 0; i < num - ptp->n_vclocks; i++) {
vclock = ptp_vclock_register(ptp);
if (!vclock)
- goto out;
+ goto err_register;
*(ptp->vclock_index + ptp->n_vclocks + i) =
vclock->clock->index;@@ -257,6 +257,12 @@ static ssize_t n_vclocks_store(struct device *dev,
mutex_unlock(&ptp->n_vclocks_mux);
return count;
+err_register:
+ num = i;
+ if (num)
+ device_for_each_child_reverse(dev, &num, unregister_vclock);
+ for (num = 0; num < i; num++)
+ ptp->vclock_index[ptp->n_vclocks + num] = -1;
out:
mutex_unlock(&ptp->n_vclocks_mux);
return err;
--
2.53.0