Re: [PATCH net-next 1/2] netconsole: publish the userdata payload with RCU

From: Gustavo Luiz Duarte

Date: Tue Aug 04 2026 - 13:22:02 EST


On Mon, Aug 3, 2026 at 12:30 PM Breno Leitao <leitao@xxxxxxxxxx> wrote:
>
> update_userdata() takes target_list_lock to swap nt->userdata and
> nt->userdata_length, then frees the old buffer. Since commit
> 7eab73b18630 ("netconsole: convert to NBCON console infrastructure")
> that lock is also the console's device_lock, so writing a userdata value
> from configfs serialises against the printk core emitting messages.
>
> The buffer is immutable once published, which is what RCU is for. Move
> the string and its length into a single netconsole_userdata object and
> publish it with rcu_replace_pointer(), freeing the old one with
> kfree_rcu().
>
> New userdata design:
>
> 0) Unify the userdata fields into a struct netcons_userdata
> 1) update_userdata() no longer needs target_list_lock.
> 2) writers stay serialised by dynamic_netconsole_mutex.
> 3) reading userdata needs an RCU read lock.
>
> No functional change intended.
>
> Signed-off-by: Breno Leitao <leitao@xxxxxxxxxx>
> ---
> drivers/net/netconsole.c | 88 +++++++++++++++++++++++++++++-------------------
> 1 file changed, 54 insertions(+), 34 deletions(-)
>
> diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c
> index 862001d09aa84..c88c82f2136cb 100644
> --- a/drivers/net/netconsole.c
> +++ b/drivers/net/netconsole.c
> @@ -135,13 +135,27 @@ enum target_state {
> STATE_DEACTIVATED,
> };
>
> +/**
> + * struct netcons_userdata - Formatted userdata payload of a target.
> + * @rcu: Used to free the payload after a grace period.
> + * @length: Length of @data, excluding the NUL terminator.
> + * @data: Formatted " key=value\n" entries, NUL terminated.
> + *
> + * Immutable once published, so the transmit path never observes @data and
> + * @length disagreeing.
> + */
> +struct netcons_userdata {
> + struct rcu_head rcu;
> + size_t length;
> + char data[];
> +};
> +
> /**
> * struct netconsole_target - Represents a configured netconsole target.
> * @list: Links this target into the target_list.
> * @group: Links us into the configfs subsystem hierarchy.
> * @userdata_group: Links to the userdata configfs hierarchy
> - * @userdata: Cached, formatted string of append
> - * @userdata_length: String length of userdata.
> + * @userdata: Cached, formatted userdata payload. RCU protected.
> * @sysdata: Cached, formatted string of append
> * @sysdata_fields: Sysdata features enabled.
> * @msgcounter: Message sent counter.
> @@ -176,8 +190,7 @@ struct netconsole_target {
> #ifdef CONFIG_NETCONSOLE_DYNAMIC
> struct config_group group;
> struct config_group userdata_group;
> - char *userdata;
> - size_t userdata_length;
> + struct netcons_userdata __rcu *userdata;

With userdata now annotated with __rcu, it should be freed with
kfree(rcu_access_pointer(nt->userdata)) to avoid a sparse warning:

$ make C=1 drivers/net/netconsole.o
DESCEND objtool
DESCEND bpf/resolve_btfids
INSTALL libsubcmd_headers
CC drivers/net/netconsole.o
CHECK drivers/net/netconsole.c
drivers/net/netconsole.c:1702:17: expected void const *objp
drivers/net/netconsole.c:1702:17: got struct netcons_userdata
[noderef] __rcu *userdata
drivers/net/netconsole.c:2689:17: expected void const *objp
drivers/net/netconsole.c:2689:17: got struct netcons_userdata
[noderef] __rcu *userdata