[PATCH net-next 3/4] netconsole: avoid printing partially updated target attributes
From: Gustavo Luiz Duarte
Date: Mon Sep 28 2026 - 14:03:19 EST
The configfs store callbacks all serialize on dynamic_netconsole_mutex
but not on the read side, so reading an attribute while it is being
written returns a partially updated value.
Hold dynamic_netconsole_mutex on *_show() callbacks to avoid racing with
writers.
Reported-by: Sashiko <netdev-bot+sashiko@xxxxxxxxxx>
Closes: https://netdev-ai.bots.linux.dev/sashiko/#/patchset/20260814-netcons_ipv6-v3-7-bc0915e8c75f@xxxxxxxxx
Signed-off-by: Gustavo Luiz Duarte <gustavold@xxxxxxxxx>
---
drivers/net/netconsole.c | 57 ++++++++++++++++++++++++++++++++++++++----------
1 file changed, 46 insertions(+), 11 deletions(-)
diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
index 5f4311726d11..627475f16383 100644
--- a/drivers/net/netconsole.c
+++ b/drivers/net/netconsole.c
@@ -861,7 +861,14 @@ static ssize_t release_show(struct config_item *item, char *buf)
static ssize_t dev_name_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%s\n", to_target(item)->np.dev_name);
+ struct netconsole_target *nt = to_target(item);
+ int ret;
+
+ dynamic_netconsole_mutex_lock();
+ ret = sysfs_emit(buf, "%s\n", nt->np.dev_name);
+ dynamic_netconsole_mutex_unlock();
+
+ return ret;
}
static ssize_t local_port_show(struct config_item *item, char *buf)
@@ -877,25 +884,39 @@ static ssize_t remote_port_show(struct config_item *item, char *buf)
static ssize_t local_ip_show(struct config_item *item, char *buf)
{
struct netconsole_target *nt = to_target(item);
+ int ret;
+
+ dynamic_netconsole_mutex_lock();
if (nt->local_ip.family == AF_UNSPEC)
- return sysfs_emit(buf, "\n");
- if (nt->local_ip.family == AF_INET6)
- return sysfs_emit(buf, "%pI6c\n", &nt->local_ip.in6);
+ ret = sysfs_emit(buf, "\n");
+ else if (nt->local_ip.family == AF_INET6)
+ ret = sysfs_emit(buf, "%pI6c\n", &nt->local_ip.in6);
else
- return sysfs_emit(buf, "%pI4\n", &nt->local_ip.ip);
+ ret = sysfs_emit(buf, "%pI4\n", &nt->local_ip.ip);
+
+ dynamic_netconsole_mutex_unlock();
+
+ return ret;
}
static ssize_t remote_ip_show(struct config_item *item, char *buf)
{
struct netconsole_target *nt = to_target(item);
+ int ret;
+
+ dynamic_netconsole_mutex_lock();
if (nt->remote_ip.family == AF_UNSPEC)
- return sysfs_emit(buf, "\n");
- if (nt->remote_ip.family == AF_INET6)
- return sysfs_emit(buf, "%pI6c\n", &nt->remote_ip.in6);
+ ret = sysfs_emit(buf, "\n");
+ else if (nt->remote_ip.family == AF_INET6)
+ ret = sysfs_emit(buf, "%pI6c\n", &nt->remote_ip.in6);
else
- return sysfs_emit(buf, "%pI4\n", &nt->remote_ip.ip);
+ ret = sysfs_emit(buf, "%pI4\n", &nt->remote_ip.ip);
+
+ dynamic_netconsole_mutex_unlock();
+
+ return ret;
}
static ssize_t local_mac_show(struct config_item *item, char *buf)
@@ -915,7 +936,14 @@ static ssize_t local_mac_show(struct config_item *item, char *buf)
static ssize_t remote_mac_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%pM\n", to_target(item)->remote_mac);
+ struct netconsole_target *nt = to_target(item);
+ int ret;
+
+ dynamic_netconsole_mutex_lock();
+ ret = sysfs_emit(buf, "%pM\n", nt->remote_mac);
+ dynamic_netconsole_mutex_unlock();
+
+ return ret;
}
static ssize_t transmit_errors_show(struct config_item *item, char *buf)
@@ -1350,7 +1378,14 @@ static struct netconsole_target *userdata_to_target(struct userdata *ud)
static ssize_t userdatum_value_show(struct config_item *item, char *buf)
{
- return sysfs_emit(buf, "%s\n", &(to_userdatum(item)->value[0]));
+ struct userdatum *udm = to_userdatum(item);
+ int ret;
+
+ dynamic_netconsole_mutex_lock();
+ ret = sysfs_emit(buf, "%s\n", udm->value);
+ dynamic_netconsole_mutex_unlock();
+
+ return ret;
}
/* Navigate configfs and calculate the lentgh of the formatted string
--
2.55.0