diff options
-rw-r--r-- | Documentation/networking/netconsole.rst | 32 | ||||
-rw-r--r-- | drivers/net/netconsole.c | 66 | ||||
-rwxr-xr-x | tools/testing/selftests/drivers/net/netcons_sysdata.sh | 30 |
3 files changed, 128 insertions, 0 deletions
diff --git a/Documentation/networking/netconsole.rst b/Documentation/networking/netconsole.rst index a0076b542e9c..59cb9982afe6 100644 --- a/Documentation/networking/netconsole.rst +++ b/Documentation/networking/netconsole.rst @@ -340,6 +340,38 @@ In this example, the message was sent by CPU 42. cpu=42 # kernel-populated value +Message ID auto population in userdata +-------------------------------------- + +Within the netconsole configfs hierarchy, there is a file named `msgid_enabled` +located in the `userdata` directory. This file controls the message ID +auto-population feature, which assigns a numeric id to each message sent to a +given target and appends the ID to userdata dictionary in every message sent. + +The message ID is generated using a per-target 32 bit counter that is +incremented for every message sent to the target. Note that this counter will +eventually wrap around after reaching uint32_t max value, so the message ID is +not globally unique over time. However, it can still be used by the target to +detect if messages were dropped before reaching the target by identifying gaps +in the sequence of IDs. + +It is important to distinguish message IDs from the message <sequnum> field. +Some kernel messages may never reach netconsole (for example, due to printk +rate limiting). Thus, a gap in <sequnum> cannot be solely relied upon to +indicate that a message was dropped during transmission, as it may never have +been sent via netconsole. The message ID, on the other hand, is only assigned +to messages that are actually transmitted via netconsole. + +Example:: + + echo "This is message #1" > /dev/kmsg + echo "This is message #2" > /dev/kmsg + 13,434,54928466,-;This is message #1 + msgid=1 + 13,435,54934019,-;This is message #2 + msgid=2 + + Extended console: ================= diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 89afe127b46c..e3722de08ea9 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -113,6 +113,8 @@ enum sysdata_feature { SYSDATA_TASKNAME = BIT(1), /* Kernel release/version as part of sysdata */ SYSDATA_RELEASE = BIT(2), + /* Include a per-target message ID as part of sysdata */ + SYSDATA_MSGID = BIT(3), }; /** @@ -123,6 +125,7 @@ enum sysdata_feature { * @extradata_complete: Cached, formatted string of append * @userdata_length: String length of usedata in extradata_complete. * @sysdata_fields: Sysdata features enabled. + * @msgcounter: Message sent counter. * @stats: Packet send stats for the target. Used for debugging. * @enabled: On / off knob to enable / disable target. * Visible from userspace (read-write). @@ -153,6 +156,8 @@ struct netconsole_target { size_t userdata_length; /* bit-wise with sysdata_feature bits */ u32 sysdata_fields; + /* protected by target_list_lock */ + u32 msgcounter; #endif struct netconsole_target_stats stats; bool enabled; @@ -504,6 +509,19 @@ static void unregister_netcons_consoles(void) unregister_console(&netconsole); } +static ssize_t sysdata_msgid_enabled_show(struct config_item *item, + char *buf) +{ + struct netconsole_target *nt = to_target(item->ci_parent); + bool msgid_enabled; + + mutex_lock(&dynamic_netconsole_mutex); + msgid_enabled = !!(nt->sysdata_fields & SYSDATA_MSGID); + mutex_unlock(&dynamic_netconsole_mutex); + + return sysfs_emit(buf, "%d\n", msgid_enabled); +} + /* * This one is special -- targets created through the configfs interface * are not enabled (and the corresponding netpoll activated) by default. @@ -799,6 +817,8 @@ static size_t count_extradata_entries(struct netconsole_target *nt) entries += 1; if (nt->sysdata_fields & SYSDATA_RELEASE) entries += 1; + if (nt->sysdata_fields & SYSDATA_MSGID) + entries += 1; return entries; } @@ -935,6 +955,40 @@ static void disable_sysdata_feature(struct netconsole_target *nt, nt->extradata_complete[nt->userdata_length] = 0; } +static ssize_t sysdata_msgid_enabled_store(struct config_item *item, + const char *buf, size_t count) +{ + struct netconsole_target *nt = to_target(item->ci_parent); + bool msgid_enabled, curr; + ssize_t ret; + + ret = kstrtobool(buf, &msgid_enabled); + if (ret) + return ret; + + mutex_lock(&dynamic_netconsole_mutex); + curr = !!(nt->sysdata_fields & SYSDATA_MSGID); + if (msgid_enabled == curr) + goto unlock_ok; + + if (msgid_enabled && + count_extradata_entries(nt) >= MAX_EXTRADATA_ITEMS) { + ret = -ENOSPC; + goto unlock; + } + + if (msgid_enabled) + nt->sysdata_fields |= SYSDATA_MSGID; + else + disable_sysdata_feature(nt, SYSDATA_MSGID); + +unlock_ok: + ret = strnlen(buf, count); +unlock: + mutex_unlock(&dynamic_netconsole_mutex); + return ret; +} + static ssize_t sysdata_release_enabled_store(struct config_item *item, const char *buf, size_t count) { @@ -1050,6 +1104,7 @@ CONFIGFS_ATTR(userdatum_, value); CONFIGFS_ATTR(sysdata_, cpu_nr_enabled); CONFIGFS_ATTR(sysdata_, taskname_enabled); CONFIGFS_ATTR(sysdata_, release_enabled); +CONFIGFS_ATTR(sysdata_, msgid_enabled); static struct configfs_attribute *userdatum_attrs[] = { &userdatum_attr_value, @@ -1112,6 +1167,7 @@ static struct configfs_attribute *userdata_attrs[] = { &sysdata_attr_cpu_nr_enabled, &sysdata_attr_taskname_enabled, &sysdata_attr_release_enabled, + &sysdata_attr_msgid_enabled, NULL, }; @@ -1309,6 +1365,14 @@ static int sysdata_append_release(struct netconsole_target *nt, int offset) init_utsname()->release); } +static int sysdata_append_msgid(struct netconsole_target *nt, int offset) +{ + wrapping_assign_add(nt->msgcounter, 1); + return scnprintf(&nt->extradata_complete[offset], + MAX_EXTRADATA_ENTRY_LEN, " msgid=%u\n", + nt->msgcounter); +} + /* * prepare_extradata - append sysdata at extradata_complete in runtime * @nt: target to send message to @@ -1331,6 +1395,8 @@ static int prepare_extradata(struct netconsole_target *nt) extradata_len += sysdata_append_taskname(nt, extradata_len); if (nt->sysdata_fields & SYSDATA_RELEASE) extradata_len += sysdata_append_release(nt, extradata_len); + if (nt->sysdata_fields & SYSDATA_MSGID) + extradata_len += sysdata_append_msgid(nt, extradata_len); WARN_ON_ONCE(extradata_len > MAX_EXTRADATA_ENTRY_LEN * MAX_EXTRADATA_ITEMS); diff --git a/tools/testing/selftests/drivers/net/netcons_sysdata.sh b/tools/testing/selftests/drivers/net/netcons_sysdata.sh index a737e377bf08..baf69031089e 100755 --- a/tools/testing/selftests/drivers/net/netcons_sysdata.sh +++ b/tools/testing/selftests/drivers/net/netcons_sysdata.sh @@ -53,6 +53,17 @@ function set_release() { echo 1 > "${NETCONS_PATH}/userdata/release_enabled" } +# Enable the msgid to be appended to sysdata +function set_msgid() { + if [[ ! -f "${NETCONS_PATH}/userdata/msgid_enabled" ]] + then + echo "Not able to enable msgid sysdata append. Configfs not available in ${NETCONS_PATH}/userdata/msgid_enabled" >&2 + exit "${ksft_skip}" + fi + + echo 1 > "${NETCONS_PATH}/userdata/msgid_enabled" +} + # Disable the sysdata cpu_nr feature function unset_cpu_nr() { echo 0 > "${NETCONS_PATH}/userdata/cpu_nr_enabled" @@ -67,6 +78,10 @@ function unset_release() { echo 0 > "${NETCONS_PATH}/userdata/release_enabled" } +function unset_msgid() { + echo 0 > "${NETCONS_PATH}/userdata/msgid_enabled" +} + # Test if MSG contains sysdata function validate_sysdata() { # OUTPUT_FILE will contain something like: @@ -74,6 +89,7 @@ function validate_sysdata() { # userdatakey=userdatavalue # cpu=X # taskname=<taskname> + # msgid=<id> # Echo is what this test uses to create the message. See runtest() # function @@ -104,6 +120,12 @@ function validate_sysdata() { exit "${ksft_fail}" fi + if ! grep -q "msgid=[0-9]\+$" "${OUTPUT_FILE}"; then + echo "FAIL: 'msgid=<id>' not found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + rm "${OUTPUT_FILE}" pkill_socat } @@ -155,6 +177,12 @@ function validate_no_sysdata() { exit "${ksft_fail}" fi + if grep -q "msgid=" "${OUTPUT_FILE}"; then + echo "FAIL: 'msgid= found in ${OUTPUT_FILE}" >&2 + cat "${OUTPUT_FILE}" >&2 + exit "${ksft_fail}" + fi + rm "${OUTPUT_FILE}" } @@ -206,6 +234,7 @@ set_cpu_nr # Enable taskname to be appended to sysdata set_taskname set_release +set_msgid runtest # Make sure the message was received in the dst part # and exit @@ -235,6 +264,7 @@ MSG="Test #3 from CPU${CPU}" unset_cpu_nr unset_taskname unset_release +unset_msgid runtest # At this time, cpu= shouldn't be present in the msg validate_no_sysdata |