From nobody Fri Oct 2 03:50:55 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 015003D9545; Wed, 5 Aug 2026 10:59:12 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927557; cv=none; b=F/D5gvhL1pEj4R4cwU8FrMd9n8DsR/lr5re7Vx2Rg+XTNjyARfm5mwA3vxzYQWnSTsCCgCqtrEtvN0OyCTMVtnv9Um/KbY4GEjTnt5rJWZV5XPD3KPJJh5cdxmT7FX7d9gcbq9Sn3jONU5wWZTjSssREoTMR0Pq7m+sMtJ2pehw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927557; c=relaxed/simple; bh=wLGKCNog8+m8abD/kjwLtMo1+vBYXg7HqfBu+BVQlhY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=iVyNEXhlty/wvmoQffhKvM0Qg6RByhSsqKvGKwYPsU71diiEMVPCRUMEL0X2uBF7i2bZ3W8NvB0rzwkq+N2hVfYeKTnd+uq9P4CLM/Tw1p54ed6UdmdzXuK+PzypaDhgs7IOVw2RbqaZ5wDQqllX5NcdSRYMLxevdFL0wy7pXJ4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=rLrqYqYw; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="rLrqYqYw" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=gNVUO/AfyFVjoPlB6G7IBcBKUi8NdH5E7PNb7ECR5qs=; b=rLrqYqYwSUtb+OKaJ2lk4xPDRL ZD6YRWPZtnZbUywf0P2BKFniIajBpl4U7y/rEI9YZvH360UO1lgFU6cUrG/RWI04Fh5BNwfZk+TpO CrsxZeY7EEju4QVFb56wciH1u6JR59jElrEsxLKu73yj50GgTBcGiJEtim/R4szLc2ErAjm/g95dm spqCnrVJnXiqzQ2vTqR9BQFBwMHbr65aFi8hn8r93nAEyxgUwwrmmDCXDFLQk+qh+wLYz/16yi6ky gy168fEoE0aAr2IR0ofDnmtW8cCmgsSIFPMLGIT5M96L7s5+IFvopmMxnks0gM2C2dICjUW5mzzom Ui0hb4Iw==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wrZL2-00Drzs-1V; Wed, 05 Aug 2026 10:59:08 +0000 From: Breno Leitao Date: Wed, 05 Aug 2026 03:58:19 -0700 Subject: [PATCH net-next v2 1/2] netconsole: publish the userdata payload with RCU Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260805-netcons-userdata-rcu-v2-1-c5e80f6a7a46@debian.org> References: <20260805-netcons-userdata-rcu-v2-0-c5e80f6a7a46@debian.org> In-Reply-To: <20260805-netcons-userdata-rcu-v2-0-c5e80f6a7a46@debian.org> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, gustavold@gmail.com, asantostc@gmail.com, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=8446; i=leitao@debian.org; h=from:subject:message-id; bh=wLGKCNog8+m8abD/kjwLtMo1+vBYXg7HqfBu+BVQlhY=; b=owEBbAKT/ZANAwAIATWjk5/8eHdtAcsmYgBqcxdyf54+EOKh3YdxSFJ0vrx0oHlHf7q+3Gg3+ KN8qV4Rg82JAjIEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCanMXcgAKCRA1o5Of/Hh3 bdV6D/id2gANdUoavcPxE9kS6WOZcoSOm7zajfEMnR9v0pQf35Bh1iK793km+6zlWc1A82ujYu7 dQVp5WWN7UVXbY9l5DTBdPnELYHOQevecuMPMSTb9tIGJkj/OKmMUDAouoTuGuFi/L/MmlURYIP hAejKK71WXkQWxoEIsm99WMr8bi8hHCHuwONIn04v/JfELfNmpStNzbjwiIK9v9MpIZEsD9BtlQ Er2ifw4CgOvZd+H744+fzKc1WRE14PSIhXNZUvc0F0zoc8t8z/HpVFW9Yhg/hWFGOrofhacFLoh 6BT/6gwwiawWQeV0Us4KxjlwzRoxTzAnjQr/Feu0ouUa4fCTawZabC+D3zReBJWUGIx+WTMOnqB vgRSY3FeCFPqvP/Dp+gwzP+mOfP2Q98ni77qM/LBJUdKHWnHAXNFUvpKPW77deswaHuUcUI2XAH 4KhQZDlOK6Takpxrktqx04dGxb3rsxvK8EZribXB3oDN2YQaIhGdvHrE+N5eZhuLpDQlfRcr/f8 +FLbtVdnsoWHux/0ufpZBLupbt9nzKeZk3bVZ+/TM09p+x3XcxUP7aIAdjmqR0LKx5xr48mqAFL 4B9PndI47FVixLSJ0ruWRBUXznXpi9I2JAMdAagUIimeeiYp91aIdR0rUDTTEr919Vad6PYPlZK ZnRaFrbhK0RNv X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao 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 netcons_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 Reviewed-by: Gustavo Luiz Duarte --- drivers/net/netconsole.c | 92 +++++++++++++++++++++++++++++---------------= ---- 1 file changed, 56 insertions(+), 36 deletions(-) diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 862001d09aa84..14092fb15f6d0 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -135,13 +135,27 @@ enum target_state { STATE_DEACTIVATED, }; =20 +/** + * 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=3Dvalue\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; char sysdata[MAX_EXTRADATA_ENTRY_LEN * MAX_SYSDATA_ITEMS]; =20 /* bit-wise with sysdata_feature bits */ @@ -1059,12 +1072,11 @@ static int calc_userdata_len(struct netconsole_targ= et *nt) =20 static int update_userdata(struct netconsole_target *nt) { + struct netcons_userdata *new =3D NULL; + struct netcons_userdata *old; struct userdatum *udm_item; struct config_item *item; struct list_head *entry; - char *old_buf =3D NULL; - char *new_buf =3D NULL; - unsigned long flags; int offset =3D 0; int len; =20 @@ -1076,8 +1088,8 @@ static int update_userdata(struct netconsole_target *= nt) =20 /* Allocate new buffer */ if (len) { - new_buf =3D kmalloc(len + 1, GFP_KERNEL); - if (!new_buf) + new =3D kmalloc_flex(*new, data, len + 1); + if (!new) return -ENOMEM; } =20 @@ -1087,22 +1099,21 @@ static int update_userdata(struct netconsole_target= *nt) udm_item =3D to_userdatum(item); /* Skip userdata with no value set */ if (udm_item->value[0]) { - offset +=3D scnprintf(&new_buf[offset], len + 1 - offset, + offset +=3D scnprintf(&new->data[offset], + len + 1 - offset, " %s=3D%s\n", item->ci_name, udm_item->value); } } =20 WARN_ON_ONCE(offset !=3D len); + if (new) + new->length =3D offset; =20 - /* Switch to new buffer and free old buffer */ - spin_lock_irqsave(&target_list_lock, flags); - old_buf =3D nt->userdata; - nt->userdata =3D new_buf; - nt->userdata_length =3D offset; - spin_unlock_irqrestore(&target_list_lock, flags); - - kfree(old_buf); + /* Writers are serialized by dynamic_netconsole_mutex. */ + old =3D rcu_replace_pointer(nt->userdata, new, + lockdep_is_held(&dynamic_netconsole_mutex)); + kfree_rcu(old, rcu); =20 return 0; } @@ -1392,7 +1403,7 @@ static void netconsole_target_release(struct config_i= tem *item) { struct netconsole_target *nt =3D to_target(item); =20 - kfree(nt->userdata); + kfree(rcu_access_pointer(nt->userdata)); kfree(nt); } =20 @@ -1926,14 +1937,13 @@ static void send_udp(struct netconsole_target *nt, = const char *msg, int len) static void send_msg_no_fragmentation(struct netconsole_target *nt, const char *msg, int msg_len, - int release_len) + int release_len, + const struct netcons_userdata *userdata) { - const char *userdata =3D NULL; const char *sysdata =3D NULL; const char *release; =20 #ifdef CONFIG_NETCONSOLE_DYNAMIC - userdata =3D nt->userdata; sysdata =3D nt->sysdata; #endif =20 @@ -1950,7 +1960,7 @@ static void send_msg_no_fragmentation(struct netconso= le_target *nt, if (userdata) msg_len +=3D scnprintf(&nt->buf[msg_len], sizeof(nt->buf) - msg_len, "%s", - userdata); + userdata->data); =20 if (sysdata) msg_len +=3D scnprintf(&nt->buf[msg_len], @@ -1970,7 +1980,8 @@ static void append_release(char *buf) =20 static void send_fragmented_body(struct netconsole_target *nt, const char *msgbody_ptr, int header_len, - int msgbody_len, int sysdata_len) + int msgbody_len, int sysdata_len, + const struct netcons_userdata *userdata) { const char *userdata_ptr =3D NULL; const char *sysdata_ptr =3D NULL; @@ -1981,12 +1992,12 @@ static void send_fragmented_body(struct netconsole_= target *nt, int userdata_len =3D 0; =20 #ifdef CONFIG_NETCONSOLE_DYNAMIC - userdata_ptr =3D nt->userdata; sysdata_ptr =3D nt->sysdata; - userdata_len =3D nt->userdata_length; #endif - if (WARN_ON_ONCE(!userdata_ptr && userdata_len !=3D 0)) - return; + if (userdata) { + userdata_ptr =3D userdata->data; + userdata_len =3D userdata->length; + } =20 if (WARN_ON_ONCE(!sysdata_ptr && sysdata_len !=3D 0)) return; @@ -2063,7 +2074,8 @@ static void send_msg_fragmented(struct netconsole_tar= get *nt, const char *msg, int msg_len, int release_len, - int sysdata_len) + int sysdata_len, + const struct netcons_userdata *userdata) { int header_len, msgbody_len; const char *msgbody; @@ -2092,7 +2104,7 @@ static void send_msg_fragmented(struct netconsole_tar= get *nt, * will be replaced */ send_fragmented_body(nt, msgbody, header_len, msgbody_len, - sysdata_len); + sysdata_len, userdata); } =20 /** @@ -2107,25 +2119,33 @@ static void send_msg_fragmented(struct netconsole_t= arget *nt, static void send_ext_msg_udp(struct netconsole_target *nt, struct nbcon_write_context *wctxt) { + const struct netcons_userdata *userdata =3D NULL; int userdata_len =3D 0; int release_len =3D 0; int sysdata_len =3D 0; int len; =20 + /* Keeps the payload picked below alive until the last send_udp(). */ + rcu_read_lock(); + #ifdef CONFIG_NETCONSOLE_DYNAMIC sysdata_len =3D prepare_sysdata(nt, wctxt); - userdata_len =3D nt->userdata_length; + userdata =3D rcu_dereference(nt->userdata); + if (userdata) + userdata_len =3D userdata->length; #endif if (nt->release) release_len =3D strlen(init_utsname()->release) + 1; =20 len =3D wctxt->len + release_len + sysdata_len + userdata_len; if (len <=3D MAX_PRINT_CHUNK) - return send_msg_no_fragmentation(nt, wctxt->outbuf, - wctxt->len, release_len); + send_msg_no_fragmentation(nt, wctxt->outbuf, wctxt->len, + release_len, userdata); + else + send_msg_fragmented(nt, wctxt->outbuf, wctxt->len, release_len, + sysdata_len, userdata); =20 - return send_msg_fragmented(nt, wctxt->outbuf, wctxt->len, release_len, - sysdata_len); + rcu_read_unlock(); } =20 static void send_msg_udp(struct netconsole_target *nt, const char *msg, @@ -2357,7 +2377,7 @@ static void free_param_target(struct netconsole_targe= t *nt) cancel_work_sync(&nt->resume_wq); netpoll_cleanup(&nt->np); #ifdef CONFIG_NETCONSOLE_DYNAMIC - kfree(nt->userdata); + kfree(rcu_access_pointer(nt->userdata)); #endif kfree(nt); } --=20 2.53.0-Meta From nobody Fri Oct 2 03:50:55 2026 Received: from stravinsky.debian.org (stravinsky.debian.org [82.195.75.108]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 30BCB42CB18; Wed, 5 Aug 2026 10:59:16 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=82.195.75.108 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927562; cv=none; b=sMKcJdlGsLoPwgmBJU3cCRzooi+TNMBlN7gLZ42tktgVdCCoqLw3Jzdhq1QfbP4ucEoZdfFJgwzsOcC8S5mMg4RfvqQLfI8+edKHHgxm1EQfoj8OQxLRCHuf85Hh7r4tsRcnzNagTQpXV4GvzpKrbWciKg2jvhyUp7tQnkno8H4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1785927562; c=relaxed/simple; bh=MsmLy0KjlGvz7Z+I9vf/fAAWD7ems2kzDzIs+rWqR4U=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=r5KXgE/phvqzS0PhSZdMIoFqPjcaX/ytBZjae1cZz1ZBUHLx277xt01+A8H/HKJ8pdP5v1hoDuAE/Ha0OWb+pF5uo+FtpeIiDv1lMJhupPnL9L9sTKgQej159DDD6AVPrzGqAnunfM77MWHjnly7SIuepHISJfr+RngbMJC4DA8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org; spf=pass smtp.mailfrom=debian.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b=YPjxJGki; arc=none smtp.client-ip=82.195.75.108 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=debian.org Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=debian.org Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=debian.org header.i=@debian.org header.b="YPjxJGki" DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debian.org; s=smtpauto.stravinsky; h=X-Debian-User:Cc:To:In-Reply-To:References: Message-Id:Content-Transfer-Encoding:Content-Type:MIME-Version:Subject:Date: From:Reply-To:Content-ID:Content-Description; bh=TOslnepK47dHho2QtfJP4nojTAlEBKd7pBk23hTvEPI=; b=YPjxJGki8nLrPvNgsPP6aYL2Oe ftRQb3GR6sW+LM9EadVOTltC2h9jqHndN3eAANyihbCyOKLBqnKkoLJoWvMSCkFeeKXlqtO5FdZHG uthlCHreyeD/3HAm9kmovNvfWZ6qWIr6pNjxIMz1kS8asRD4F+iyjyNKsQ/+W94AKu/N0yYHqFGaf CG2BY3J7tPtkR3/y6Jlt6dmnUc3pJ5rS2ugtyjYSNUc2hPkdC4CqEBIAvF9WsxwsQeFdVyy+H8zAO 5o2caMz/vDY87+XruDOo2oCvQjwWWjiL0XMq9VdWi/i1ALdp5sEpU2tunkU+ogawZ/33zd8V/PSHq 6NsGKZxA==; Received: from authenticated-user by stravinsky.debian.org with esmtpsa (TLS1.3:ECDHE_X25519__RSA_PSS_RSAE_SHA256__AES_256_GCM:256) (Exim 4.96) (envelope-from ) id 1wrZL6-00Ds06-2H; Wed, 05 Aug 2026 10:59:13 +0000 From: Breno Leitao Date: Wed, 05 Aug 2026 03:58:20 -0700 Subject: [PATCH net-next v2 2/2] selftests: netconsole: add a userdata torture test Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260805-netcons-userdata-rcu-v2-2-c5e80f6a7a46@debian.org> References: <20260805-netcons-userdata-rcu-v2-0-c5e80f6a7a46@debian.org> In-Reply-To: <20260805-netcons-userdata-rcu-v2-0-c5e80f6a7a46@debian.org> To: Andrew Lunn , "David S. Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Shuah Khan Cc: netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org, gustavold@gmail.com, asantostc@gmail.com, Breno Leitao , kernel-team@meta.com X-Mailer: b4 0.16-dev-f8e9d X-Developer-Signature: v=1; a=openpgp-sha256; l=7858; i=leitao@debian.org; h=from:subject:message-id; bh=MsmLy0KjlGvz7Z+I9vf/fAAWD7ems2kzDzIs+rWqR4U=; b=owEBbQKS/ZANAwAIATWjk5/8eHdtAcsmYgBqcxdyU49Eq39dS0DaUaU14fogFML6x64isjCHn kxAtisg2eOJAjMEAAEIAB0WIQSshTmm6PRnAspKQ5s1o5Of/Hh3bQUCanMXcgAKCRA1o5Of/Hh3 bYrHD/45reACrbzUBBwp5mGFuADIc40UlfxMsg73d7Qk2xdg3VB0C+h3HdcM4LckZivUHwkShv1 3WOZmxN1DvvlOycNsqrGsi/005Osqg55etCye5EwOlJ/l9/Pbn92mPdWNygbkBVvoj/XcSl/G2k Q0imwZH8yCFlBKWglH3mhGLYFxlVdjiB41N/siH3GoG6xnTxDthm72UqOQj2Zuz3WBD+tYENdsx PIkonZPGeI0PVCMxBx0kKuYdn4ePzGtOHJrV9ew7VivlIdNFPgHztvecs9smuN21+gGmVHhrw35 abVdLBifWJr74pycF9F4QfFpMQBIvXKJQNf8j7Eb2ixAE/ZrJpm/Wt6BIt4zPRsgLhLNAZEetcv qAcezyvt1+Y9//nm7t8cJH+KcEStdynqQgE8lVQ4UCYwf+cNTPtw6fzaqEI+igmABNaK7KNn2X2 eP+ZQtFSjueTXdgG/qYKBwAQSF5sDD4SytxDM6xs3+xGwUyH+SAPW78oslRVmV4diQ2Oxr3HOIy vDzsBuCZZ6jc/Zqa6EM8HEJXdFsiWy1uMdh9oY8bZD6wM3idjwSqdUVXVd2lj4kQ2U2T4MHAw8R VX3LA1X3cHEP+zpv3n4hG8a0Boc2H+oFhorLj19Qv6jDHaZzqGYRztuk0KJkxAdqs+hcz8jpoOJ XckwDB86KlTgRaQ== X-Developer-Key: i=leitao@debian.org; a=openpgp; fpr=AC8539A6E8F46702CA4A439B35A3939FFC78776D X-Debian-User: leitao The userdata payload is rebuilt and republished on every configfs write, including while the target is enabled and messages are being sent. Add netcons_userdata.sh that runs random tests with userdata. Signed-off-by: Breno Leitao Reviewed-by: Gustavo Luiz Duarte --- .../selftests/drivers/net/netconsole/Makefile | 1 + .../drivers/net/netconsole/netcons_userdata.sh | 229 +++++++++++++++++= ++++ 2 files changed, 230 insertions(+) diff --git a/tools/testing/selftests/drivers/net/netconsole/Makefile b/tool= s/testing/selftests/drivers/net/netconsole/Makefile index b56c70b7e2742..f0674c0017fc4 100644 --- a/tools/testing/selftests/drivers/net/netconsole/Makefile +++ b/tools/testing/selftests/drivers/net/netconsole/Makefile @@ -13,6 +13,7 @@ TEST_PROGS :=3D \ netcons_resume.sh \ netcons_sysdata.sh \ netcons_torture.sh \ + netcons_userdata.sh \ # end of TEST_PROGS =20 include ../../../lib.mk diff --git a/tools/testing/selftests/drivers/net/netconsole/netcons_userdat= a.sh b/tools/testing/selftests/drivers/net/netconsole/netcons_userdata.sh new file mode 100755 index 0000000000000..113903f4ce1c5 --- /dev/null +++ b/tools/testing/selftests/drivers/net/netconsole/netcons_userdata.sh @@ -0,0 +1,229 @@ +#!/usr/bin/env bash +# SPDX-License-Identifier: GPL-2.0 + +# Exercise the netconsole userdata payload. +# +# The first part checks that the payload the target transmits follows what +# configfs says: a value shows up in the next message, an update replaces = the +# previous one, clearing the value drops the entry, and so does removing t= he +# key. +# +# The second part rewrites values, creates and deletes keys, and clears the +# payload entirely while messages are being sent, so the transmit path kee= ps +# picking up payloads that are being replaced underneath it. It runs twice, +# once with a payload small enough to fit in a single packet and once large +# enough to be fragmented. +# +# Author: Breno Leitao + +set -euo pipefail + +SCRIPTDIR=3D$(dirname "$(readlink -e "${BASH_SOURCE[0]}")") + +source "${SCRIPTDIR}"/../lib/sh/lib_netcons.sh + +# Number of times each torture worker loops +ITERATIONS=3D${1:-200} + +# Keys owned by each torture worker. Workers do not share keys, so a faili= ng +# configfs operation means a real problem and not a lost race. +CHURN_KEY=3D"churnkey" +TRANSIENT_KEY=3D"transientkey" +# Number of keys used to push a message past MAX_PRINT_CHUNK +BULK_KEYS=3D8 + +USERDATA_DIR=3D"${NETCONS_PATH}/userdata" +# Values are capped at MAX_EXTRADATA_VALUE_LEN(200) bytes, so ${BULK_KEYS} +# entries of this size are enough to force fragmentation +LONG_VALUE=3D$(printf -- 'v%.0s' {1..190}) + +function write_key() { + local KEY=3D"${1}" + local VALUE=3D"${2}" + + mkdir -p "${USERDATA_DIR}/${KEY}" + echo "${VALUE}" > "${USERDATA_DIR}/${KEY}/value" +} + +# Send a single message and capture it on the destination interface +function send_and_capture() { + rm -f "${OUTPUT_FILE}" + + listen_port_and_save_to "${OUTPUT_FILE}" & + wait_for_port "${NAMESPACE}" "${PORT}" "${IP_VERSION}" + echo "${MSG}: ${TARGET}" > /dev/kmsg + busywait "${BUSYWAIT_TIMEOUT}" test -s "${OUTPUT_FILE}" || true + pkill_socat + validate_msg "${OUTPUT_FILE}" +} + +function expect_in_msg() { + local WANTED=3D"${1}" + + if ! grep -q -- "${WANTED}" "${OUTPUT_FILE}"; then + echo "FAIL: '${WANTED}' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi +} + +function expect_not_in_msg() { + local UNWANTED=3D"${1}" + + if grep -q -- "${UNWANTED}" "${OUTPUT_FILE}"; then + echo "FAIL: '${UNWANTED}' found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi +} + +# Every write publishes a new payload and frees the previous one. An empty +# value is skipped when the payload is formatted, so this also drives the +# target through having no payload at all. +function churn_value() { + local i + + for i in $(seq "${ITERATIONS}") + do + echo "value${i}" > "${USERDATA_DIR}/${CHURN_KEY}/value" + echo > "${USERDATA_DIR}/${CHURN_KEY}/value" + done +} + +# Create and delete a key underneath the sender +function churn_key() { + local i + + for i in $(seq "${ITERATIONS}") + do + mkdir "${USERDATA_DIR}/${TRANSIENT_KEY}" + echo "transient${i}" > "${USERDATA_DIR}/${TRANSIENT_KEY}/value" + rmdir "${USERDATA_DIR}/${TRANSIENT_KEY}" + done +} + +# Keep the transmit path busy while the payload is being replaced +function send_messages() { + local i + + for i in $(seq "${ITERATIONS}") + do + echo "${MSG}: ${TARGET} ${i}" > /dev/kmsg + done +} + +# Run the workers concurrently and fail if any of them hits an error +function run_workers() { + local PIDS=3D() + local WORKER + local RET=3D0 + local PID + + for WORKER in "$@" + do + "${WORKER}" & + PIDS+=3D("$!") + done + + # Reap every worker before reporting a failure, otherwise a surviving + # worker keeps writing to configfs while the exit trap cleans it up. + for PID in "${PIDS[@]}" + do + wait "${PID}" || RET=3D1 + done + + if [[ "${RET}" -ne 0 ]] + then + echo "FAIL: userdata torture worker failed" >&2 + exit "${ksft_fail}" + fi +} + +function create_bulk_keys() { + local i + + for i in $(seq "${BULK_KEYS}") + do + write_key "bulk${i}" "${LONG_VALUE}" + done +} + +function delete_bulk_keys() { + local i + + for i in $(seq "${BULK_KEYS}") + do + rmdir "${USERDATA_DIR}/bulk${i}" + done +} + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # +# Start here # +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D # + +modprobe netdevsim 2> /dev/null || true +modprobe netconsole 2> /dev/null || true + +IP_VERSION=3D"ipv4" +# The content of kmsg will be saved to the following file +OUTPUT_FILE=3D"/tmp/${TARGET}" + +# Check for basic system dependency and exit if not found +check_for_dependencies +# Set current loglevel to KERN_INFO(6), and default to KERN_NOTICE(5) +echo "6 5" > /proc/sys/kernel/printk +# Remove the namespace, interfaces and netconsole target on exit +trap cleanup EXIT +# Create one namespace and two interfaces +set_network "${IP_VERSION}" +# Create a dynamic target for netconsole +create_dynamic_target + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +# TEST #1 +# A value written to configfs reaches the destination +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +write_key "${USERDATA_KEY}" "first" +send_and_capture +expect_in_msg "${USERDATA_KEY}=3Dfirst" + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +# TEST #2 +# Updating the value replaces the previous payload +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +write_key "${USERDATA_KEY}" "second" +send_and_capture +expect_in_msg "${USERDATA_KEY}=3Dsecond" +expect_not_in_msg "${USERDATA_KEY}=3Dfirst" + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +# TEST #3 +# Clearing the value drops the entry +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +echo > "${USERDATA_DIR}/${USERDATA_KEY}/value" +send_and_capture +expect_not_in_msg "${USERDATA_KEY}=3D" + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +# TEST #4 +# Removing the key drops the entry +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +write_key "${USERDATA_KEY}" "third" +rmdir "${USERDATA_DIR}/${USERDATA_KEY}" +send_and_capture +expect_not_in_msg "${USERDATA_KEY}=3D" +rm "${OUTPUT_FILE}" + +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +# TEST #5 +# Torture the payload while messages are being sent, +# first unfragmented and then fragmented +# =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D +write_key "${CHURN_KEY}" "${USERDATA_VALUE}" +run_workers churn_value churn_key send_messages + +create_bulk_keys +run_workers churn_value churn_key send_messages +delete_bulk_keys + +exit "${ksft_pass}" --=20 2.53.0-Meta