From: Ivan Vecera <ivecera@redhat.com>
To: netdev@vger.kernel.org
Cc: Vadim Fedorenko <vadim.fedorenko@linux.dev>,
Arkadiusz Kubalewski <arkadiusz.kubalewski@intel.com>,
Jiri Pirko <jiri@resnulli.us>,
Milena Olech <milena.olech@intel.com>,
Przemek Kitszel <przemyslaw.kitszel@intel.com>,
Jakub Kicinski <kuba@kernel.org>,
"David S. Miller" <davem@davemloft.net>,
Michal Michalik <michal.michalik@intel.com>,
linux-kernel@vger.kernel.org
Subject: [PATCH net 2/2] dpll: report dumps interrupted by topology changes
Date: Thu, 5 Nov 2026 14:11:45 +0100 [thread overview]
Message-ID: <20261105131145.1010406-3-ivecera@redhat.com> (raw)
In-Reply-To: <20261105131145.1010406-1-ivecera@redhat.com>
Pin and device dumps release dpll_lock between parts and resume from the
id saved by the previous part. An object registered in between is missed
if its id is below that one, as is the case for an object allocated
before the dump started. User space gets an incomplete dump and has no
way to tell.
Count registrations and unregistrations in a generation counter and pass
it to genl_dump_check_consistent() to set NLM_F_DUMP_INTR. Check it only
after a message is built, a cancelled message would consume the change.
Found by code review. Reproduced with a test module registering a device
or a pin with a low id between parts of a raw netlink dump: the object was
missing and no message had the flag set. With this patch the flag is set
when an object is registered or unregistered during a dump, and is not
set on dumps without such a change. Tested in QEMU and on a ZL30732A
board, where unbinding the driver during a dump sets the flag as well.
Fixes: 9d71b54b65b1 ("dpll: netlink: Add DPLL framework base functions")
Signed-off-by: Ivan Vecera <ivecera@redhat.com>
---
drivers/dpll/dpll_core.c | 19 +++++++++++++++++++
drivers/dpll/dpll_core.h | 1 +
drivers/dpll/dpll_netlink.c | 4 ++++
3 files changed, 24 insertions(+)
diff --git a/drivers/dpll/dpll_core.c b/drivers/dpll/dpll_core.c
index 277692d12d3d1e..a68e8f5b609db8 100644
--- a/drivers/dpll/dpll_core.c
+++ b/drivers/dpll/dpll_core.c
@@ -22,6 +22,12 @@
/* Mutex lock to protect DPLL subsystem devices and pins */
DEFINE_MUTEX(dpll_lock);
+/* Changes with the topology of devices and pins, so that netlink dumps can
+ * detect it. Never 0, as netlink takes that for no sequence. Protected by
+ * dpll_lock.
+ */
+unsigned int dpll_generation = 1;
+
DEFINE_XARRAY_FLAGS(dpll_device_xa, XA_FLAGS_ALLOC);
DEFINE_XARRAY_FLAGS(dpll_pin_xa, XA_FLAGS_ALLOC);
@@ -53,6 +59,13 @@ struct dpll_pin_registration {
dpll_tracker tracker;
};
+static void dpll_generation_inc(void)
+{
+ lockdep_assert_held(&dpll_lock);
+ while (++dpll_generation == 0)
+ ;
+}
+
static int call_dpll_notifiers(unsigned long action, void *info)
{
lockdep_assert_held(&dpll_lock);
@@ -510,6 +523,7 @@ int dpll_device_register(struct dpll_device *dpll, enum dpll_type type,
}
xa_set_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
+ dpll_generation_inc();
dpll_device_create_ntf(dpll);
mutex_unlock(&dpll_lock);
@@ -549,6 +563,7 @@ void dpll_device_unregister(struct dpll_device *dpll,
return;
}
xa_clear_mark(&dpll_device_xa, dpll->id, DPLL_REGISTERED);
+ dpll_generation_inc();
mutex_unlock(&dpll_lock);
}
EXPORT_SYMBOL_GPL(dpll_device_unregister);
@@ -851,6 +866,7 @@ __dpll_pin_register(struct dpll_device *dpll, struct dpll_pin *pin,
if (ret)
goto ref_pin_del;
xa_set_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
+ dpll_generation_inc();
dpll_pin_create_ntf(pin, dpll->clock_id);
return ret;
@@ -941,6 +957,7 @@ __dpll_pin_unregister(struct dpll_device *dpll, struct dpll_pin *pin,
dpll_pin_delete_ntf(pin, dpll->clock_id);
dpll_xa_ref_pin_del(&dpll->pin_refs, pin, ops, priv, cookie);
dpll_xa_ref_dpll_del(&pin->dpll_refs, dpll, ops, priv, cookie);
+ dpll_generation_inc();
if (xa_empty(&pin->dpll_refs)) {
dpll_pin_ref_sync_pair_del(pin->id);
xa_clear_mark(&dpll_pin_xa, pin->id, DPLL_REGISTERED);
@@ -1005,6 +1022,7 @@ int dpll_pin_on_pin_register(struct dpll_pin *parent, struct dpll_pin *pin,
ret = dpll_xa_ref_pin_add(&pin->parent_refs, parent, ops, priv, pin);
if (ret)
goto unlock;
+ dpll_generation_inc();
xa_for_each(&parent->dpll_refs, i, ref) {
ret = __dpll_pin_register(ref->dpll, pin, ops, priv, parent);
if (ret) {
@@ -1057,6 +1075,7 @@ void dpll_pin_on_pin_unregister(struct dpll_pin *parent, struct dpll_pin *pin,
__dpll_pin_unregister(ref->dpll, pin, ops, priv, parent);
}
dpll_xa_ref_pin_del(&pin->parent_refs, parent, ops, priv, pin);
+ dpll_generation_inc();
mutex_unlock(&dpll_lock);
}
EXPORT_SYMBOL_GPL(dpll_pin_on_pin_unregister);
diff --git a/drivers/dpll/dpll_core.h b/drivers/dpll/dpll_core.h
index da8a369556ed11..c2ed0926de1b95 100644
--- a/drivers/dpll/dpll_core.h
+++ b/drivers/dpll/dpll_core.h
@@ -99,6 +99,7 @@ struct dpll_pin_ref *dpll_xa_ref_dpll_first(struct xarray *xa_refs);
extern struct xarray dpll_device_xa;
extern struct xarray dpll_pin_xa;
extern struct mutex dpll_lock;
+extern unsigned int dpll_generation;
void dpll_device_notify(struct dpll_device *dpll, unsigned long action);
void dpll_pin_notify(struct dpll_pin *pin, u64 src_clock_id,
diff --git a/drivers/dpll/dpll_netlink.c b/drivers/dpll/dpll_netlink.c
index e5380d95f238b3..87c8caef0f574b 100644
--- a/drivers/dpll/dpll_netlink.c
+++ b/drivers/dpll/dpll_netlink.c
@@ -1768,6 +1768,7 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
int ret = 0;
mutex_lock(&dpll_lock);
+ cb->seq = dpll_generation;
xa_for_each_marked_start(&dpll_pin_xa, i, pin, DPLL_REGISTERED,
ctx->idx) {
if (!dpll_pin_available(pin))
@@ -1789,6 +1790,7 @@ int dpll_nl_pin_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
}
break;
}
+ genl_dump_check_consistent(cb, hdr);
genlmsg_end(skb, hdr);
}
mutex_unlock(&dpll_lock);
@@ -1990,6 +1992,7 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
int ret = 0;
mutex_lock(&dpll_lock);
+ cb->seq = dpll_generation;
xa_for_each_marked_start(&dpll_device_xa, i, dpll, DPLL_REGISTERED,
ctx->idx) {
hdr = genlmsg_put(skb, NETLINK_CB(cb->skb).portid,
@@ -2004,6 +2007,7 @@ int dpll_nl_device_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
genlmsg_cancel(skb, hdr);
break;
}
+ genl_dump_check_consistent(cb, hdr);
genlmsg_end(skb, hdr);
}
mutex_unlock(&dpll_lock);
--
2.56.0
prev parent reply other threads:[~2026-11-05 13:12 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-05 13:11 [PATCH net 0/2] dpll: fix a false notification and report interrupted dumps Ivan Vecera
2026-11-05 13:11 ` [PATCH net 1/2] dpll: notify about a reference sync pair only if it was added Ivan Vecera
2026-11-05 13:11 ` Ivan Vecera [this message]
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=20261105131145.1010406-3-ivecera@redhat.com \
--to=ivecera@redhat.com \
--cc=arkadiusz.kubalewski@intel.com \
--cc=davem@davemloft.net \
--cc=jiri@resnulli.us \
--cc=kuba@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=michal.michalik@intel.com \
--cc=milena.olech@intel.com \
--cc=netdev@vger.kernel.org \
--cc=przemyslaw.kitszel@intel.com \
--cc=vadim.fedorenko@linux.dev \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®