* [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths
@ 2026-03-23 14:39 Jeff Layton
2026-03-23 14:39 ` [PATCH v5 1/2] firmware_loader: add search= module option for multi-path firmware lookup Jeff Layton
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Jeff Layton @ 2026-03-23 14:39 UTC (permalink / raw)
To: Luis Chamberlain, Russ Weight, Danilo Krummrich,
Greg Kroah-Hartman, Rafael J. Wysocki, Shuah Khan
Cc: Michal Grzedzicki, driver-core, linux-kernel, linux-kselftest,
Jeff Layton
This is something Michal had asked for last year, and I just got around
to implementing. This version also adds some selftests for this
functionality.
Signed-off-by: Jeff Layton <jlayton@kernel.org>
---
Changes in v5:
- Increase search= string length from 256 to 4096
- Preprocess search= path when it's set rather than on every firmware load
- Add selftests for search= functionality
- Link to v4: https://lore.kernel.org/r/20260320-fw-path-v4-1-7547e2f0dc64@kernel.org
Changes in v4:
- Move search path to new search= option that is tried after path=
- Link to v3: https://lore.kernel.org/r/20260318-fw-path-v3-1-a701a08bc025@kernel.org
Changes in v3:
- Allow '\' to escape a literal ':' or '\' in the string
- Link to v2: https://lore.kernel.org/r/20260318-fw-path-v2-1-8a106eb91eb4@kernel.org
Changes in v2:
- switch to using ':' as path delimiter
- Link to v1: https://lore.kernel.org/r/20260318-fw-path-v1-1-7884d9bf618f@kernel.org
---
Jeff Layton (2):
firmware_loader: add search= module option for multi-path firmware lookup
selftests/firmware: add search path test for firmware_class.search=
drivers/base/firmware_loader/main.c | 273 +++++++++++++++++++-------
tools/testing/selftests/firmware/Makefile | 2 +-
tools/testing/selftests/firmware/fw_search.sh | 222 +++++++++++++++++++++
3 files changed, 420 insertions(+), 77 deletions(-)
---
base-commit: c369299895a591d96745d6492d4888259b004a9e
change-id: 20260317-fw-path-a094c30259a5
Best regards,
--
Jeff Layton <jlayton@kernel.org>
^ permalink raw reply [flat|nested] 4+ messages in thread* [PATCH v5 1/2] firmware_loader: add search= module option for multi-path firmware lookup 2026-03-23 14:39 [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton @ 2026-03-23 14:39 ` Jeff Layton 2026-03-23 14:39 ` [PATCH v5 2/2] selftests/firmware: add search path test for firmware_class.search= Jeff Layton 2026-03-23 14:45 ` [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton 2 siblings, 0 replies; 4+ messages in thread From: Jeff Layton @ 2026-03-23 14:39 UTC (permalink / raw) To: Luis Chamberlain, Russ Weight, Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki, Shuah Khan Cc: Michal Grzedzicki, driver-core, linux-kernel, linux-kselftest, Jeff Layton Refactor fw_get_filesystem_firmware() by extracting the per-path firmware loading logic into a new fw_try_firmware_path() helper. Add a new firmware_class.search= module option that accepts a ':'-separated list of firmware search directories. The input is preprocessed at set time (boot or sysfs write) into a NUL-separated sequence of paths, avoiding per-load parsing overhead. Backslash escapes are supported: '\:' for literal ':', '\\' for literal '\'. The firmware lookup order is: 1. firmware_class.path= (single legacy path) 2. firmware_class.search= (colon-separated paths) 3. Built-in default paths (/lib/firmware/updates/..., /lib/firmware) Example: firmware_class.search=/custom/path1:/custom/path2 Suggested-by: Michal Grzedzicki <mge@meta.com> Signed-off-by: Jeff Layton <jlayton@kernel.org> --- drivers/base/firmware_loader/main.c | 273 ++++++++++++++++++++++++++---------- 1 file changed, 197 insertions(+), 76 deletions(-) diff --git a/drivers/base/firmware_loader/main.c b/drivers/base/firmware_loader/main.c index a11b30dda23be563bd55f25474ceff2153ddd667..c86f86977aa436ce6ccc19506cb0a774e06d019c 100644 --- a/drivers/base/firmware_loader/main.c +++ b/drivers/base/firmware_loader/main.c @@ -469,8 +469,9 @@ static int fw_decompress_xz(struct device *dev, struct fw_priv *fw_priv, /* direct firmware loading support */ static char fw_path_para[256]; +static char fw_search_para[4096]; +static int fw_search_len; static const char * const fw_path[] = { - fw_path_para, "/lib/firmware/updates/" UTS_RELEASE, "/lib/firmware/updates", "/lib/firmware/" UTS_RELEASE, @@ -485,6 +486,159 @@ static const char * const fw_path[] = { module_param_string(path, fw_path_para, sizeof(fw_path_para), 0644); MODULE_PARM_DESC(path, "customized firmware image search path with a higher priority than default path"); +/* + * fw_search_set - preprocess a colon-separated search path string + * + * Converts the input into a NUL-separated sequence of paths stored in + * fw_search_para, with fw_search_len tracking the total used length. + * Backslash escapes '\:' (literal ':') and '\\' (literal '\'). + * Trailing newlines on each component are stripped. + */ +static int fw_search_set(const char *val, const struct kernel_param *kp) +{ + const char *p; + int len = 0; + + if (!val) { + fw_search_para[0] = '\0'; + fw_search_len = 0; + return 0; + } + + for (p = val; *p; p++) { + if (p[0] == '\\' && (p[1] == ':' || p[1] == '\\')) { + p++; + if (len < sizeof(fw_search_para) - 2) + fw_search_para[len++] = *p; + } else if (*p == ':') { + /* strip trailing newline before the separator */ + if (len > 0 && fw_search_para[len - 1] == '\n') + len--; + if (len > 0 && fw_search_para[len - 1] != '\0') { + if (len < sizeof(fw_search_para) - 2) + fw_search_para[len++] = '\0'; + } + } else { + if (len < sizeof(fw_search_para) - 2) + fw_search_para[len++] = *p; + } + } + + /* strip trailing newline from last component */ + if (len > 0 && fw_search_para[len - 1] == '\n') + len--; + + /* ensure double-NUL termination */ + fw_search_para[len] = '\0'; + fw_search_len = len; + + return 0; +} + +/* + * fw_search_get - reconstruct colon-separated string for sysfs reads + */ +static int fw_search_get(char *buffer, const struct kernel_param *kp) +{ + const char *p; + int pos = 0; + + p = fw_search_para; + while (p < fw_search_para + fw_search_len) { + int slen = strlen(p); + + if (!slen) + break; + if (pos > 0) + buffer[pos++] = ':'; + memcpy(buffer + pos, p, slen); + pos += slen; + p += slen + 1; + } + buffer[pos] = '\0'; + return pos; +} + +static const struct kernel_param_ops fw_search_ops = { + .set = fw_search_set, + .get = fw_search_get, +}; +module_param_cb(search, &fw_search_ops, NULL, 0644); +MODULE_PARM_DESC(search, "colon-separated list of firmware search paths, tried after path= (use '\\:' for literal ':', '\\\\' for literal '\\')"); + +static int +fw_try_firmware_path(struct device *device, struct fw_priv *fw_priv, + const char *suffix, + int (*decompress)(struct device *dev, + struct fw_priv *fw_priv, + size_t in_size, + const void *in_buffer), + const char *dir, int dirlen, + char *path, void **bufp, size_t msize) +{ + size_t file_size = 0; + size_t *file_size_ptr = NULL; + size_t size; + int len, rc; + + len = snprintf(path, PATH_MAX, "%.*s/%s%s", + dirlen, dir, fw_priv->fw_name, suffix); + if (len >= PATH_MAX) + return -ENAMETOOLONG; + + fw_priv->size = 0; + + /* + * The total file size is only examined when doing a partial + * read; the "full read" case needs to fail if the whole + * firmware was not completely loaded. + */ + if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && *bufp) + file_size_ptr = &file_size; + + /* load firmware files from the mount namespace of init */ + rc = kernel_read_file_from_path_initns(path, fw_priv->offset, + bufp, msize, + file_size_ptr, + READING_FIRMWARE); + if (rc < 0) { + if (!(fw_priv->opt_flags & FW_OPT_NO_WARN)) { + if (rc != -ENOENT) + dev_warn(device, + "loading %s failed with error %d\n", + path, rc); + else + dev_dbg(device, + "loading %s failed for no such file or directory.\n", + path); + } + return rc; + } + size = rc; + + dev_dbg(device, "Loading firmware from %s\n", path); + if (decompress) { + dev_dbg(device, "f/w decompressing %s\n", + fw_priv->fw_name); + rc = decompress(device, fw_priv, size, *bufp); + /* discard the superfluous original content */ + vfree(*bufp); + *bufp = NULL; + if (rc) { + fw_free_paged_buf(fw_priv); + return rc; + } + } else { + dev_dbg(device, "direct-loading %s\n", + fw_priv->fw_name); + if (!fw_priv->data) + fw_priv->data = *bufp; + fw_priv->size = size; + } + fw_state_done(fw_priv); + return 0; +} + static int fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, const char *suffix, @@ -493,10 +647,9 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, size_t in_size, const void *in_buffer)) { - size_t size; - int i, len, maxlen = 0; + int i; int rc = -ENOENT; - char *path, *nt = NULL; + char *path; size_t msize = INT_MAX; void *buffer = NULL; @@ -511,83 +664,51 @@ fw_get_filesystem_firmware(struct device *device, struct fw_priv *fw_priv, return -ENOMEM; wait_for_initramfs(); - for (i = 0; i < ARRAY_SIZE(fw_path); i++) { - size_t file_size = 0; - size_t *file_size_ptr = NULL; - - /* skip the unset customized path */ - if (!fw_path[i][0]) - continue; - - /* strip off \n from customized path */ - maxlen = strlen(fw_path[i]); - if (i == 0) { - nt = strchr(fw_path[i], '\n'); - if (nt) - maxlen = nt - fw_path[i]; - } - len = snprintf(path, PATH_MAX, "%.*s/%s%s", - maxlen, fw_path[i], - fw_priv->fw_name, suffix); - if (len >= PATH_MAX) { - rc = -ENAMETOOLONG; - break; - } + /* Try the customized path first */ + if (fw_path_para[0]) { + int dirlen = strlen(fw_path_para); - fw_priv->size = 0; + /* strip trailing newline */ + if (fw_path_para[dirlen - 1] == '\n') + dirlen--; - /* - * The total file size is only examined when doing a partial - * read; the "full read" case needs to fail if the whole - * firmware was not completely loaded. - */ - if ((fw_priv->opt_flags & FW_OPT_PARTIAL) && buffer) - file_size_ptr = &file_size; - - /* load firmware files from the mount namespace of init */ - rc = kernel_read_file_from_path_initns(path, fw_priv->offset, - &buffer, msize, - file_size_ptr, - READING_FIRMWARE); - if (rc < 0) { - if (!(fw_priv->opt_flags & FW_OPT_NO_WARN)) { - if (rc != -ENOENT) - dev_warn(device, - "loading %s failed with error %d\n", - path, rc); - else - dev_dbg(device, - "loading %s failed for no such file or directory.\n", - path); - } - continue; - } - size = rc; - rc = 0; - - dev_dbg(device, "Loading firmware from %s\n", path); - if (decompress) { - dev_dbg(device, "f/w decompressing %s\n", - fw_priv->fw_name); - rc = decompress(device, fw_priv, size, buffer); - /* discard the superfluous original content */ - vfree(buffer); - buffer = NULL; - if (rc) { - fw_free_paged_buf(fw_priv); - continue; - } - } else { - dev_dbg(device, "direct-loading %s\n", - fw_priv->fw_name); - if (!fw_priv->data) - fw_priv->data = buffer; - fw_priv->size = size; + rc = fw_try_firmware_path(device, fw_priv, suffix, decompress, + fw_path_para, dirlen, + path, &buffer, msize); + if (!rc) + goto done; + } + + /* Try each preprocessed NUL-separated path in fw_search_para */ + if (fw_search_len > 0) { + const char *p = fw_search_para; + + while (p < fw_search_para + fw_search_len) { + int dirlen = strlen(p); + + if (!dirlen) + break; + rc = fw_try_firmware_path(device, fw_priv, + suffix, decompress, + p, dirlen, + path, &buffer, msize); + if (!rc) + goto done; + p += dirlen + 1; } - fw_state_done(fw_priv); - break; } + + /* Try default firmware paths */ + for (i = 0; i < ARRAY_SIZE(fw_path); i++) { + rc = fw_try_firmware_path(device, fw_priv, suffix, decompress, + fw_path[i], strlen(fw_path[i]), + path, &buffer, msize); + if (!rc) + break; + } + +done: __putname(path); return rc; -- 2.53.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* [PATCH v5 2/2] selftests/firmware: add search path test for firmware_class.search= 2026-03-23 14:39 [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton 2026-03-23 14:39 ` [PATCH v5 1/2] firmware_loader: add search= module option for multi-path firmware lookup Jeff Layton @ 2026-03-23 14:39 ` Jeff Layton 2026-03-23 14:45 ` [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton 2 siblings, 0 replies; 4+ messages in thread From: Jeff Layton @ 2026-03-23 14:39 UTC (permalink / raw) To: Luis Chamberlain, Russ Weight, Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki, Shuah Khan Cc: Michal Grzedzicki, driver-core, linux-kernel, linux-kselftest, Jeff Layton Add fw_search.sh, a new selftest that validates the firmware_class.search= module parameter using the existing test_firmware module's sysfs trigger interface. The test covers: - Firmware found in first/second/third search directory - Firmware not found in any search path - path= takes priority over search= - Empty search= does not break firmware loading - Sysfs readback matches what was written - Escaped colon (\:) in directory name - Escaped backslash (\\) in directory name - Escaped colon combined with multiple search paths Signed-off-by: Jeff Layton <jlayton@kernel.org> --- tools/testing/selftests/firmware/Makefile | 2 +- tools/testing/selftests/firmware/fw_search.sh | 222 ++++++++++++++++++++++++++ 2 files changed, 223 insertions(+), 1 deletion(-) diff --git a/tools/testing/selftests/firmware/Makefile b/tools/testing/selftests/firmware/Makefile index 7992969deaa2737ff2a033ffe60136b84ea2f3f0..42e5bd72886b3cd8f62ae42d53c1554e8a1b331c 100644 --- a/tools/testing/selftests/firmware/Makefile +++ b/tools/testing/selftests/firmware/Makefile @@ -3,7 +3,7 @@ CFLAGS = -Wall \ -O2 -TEST_PROGS := fw_run_tests.sh +TEST_PROGS := fw_run_tests.sh fw_search.sh TEST_FILES := fw_fallback.sh fw_filesystem.sh fw_upload.sh fw_lib.sh TEST_GEN_FILES := fw_namespace diff --git a/tools/testing/selftests/firmware/fw_search.sh b/tools/testing/selftests/firmware/fw_search.sh new file mode 100755 index 0000000000000000000000000000000000000000..ec6873e54a4cc381771311be11203083b2531bf6 --- /dev/null +++ b/tools/testing/selftests/firmware/fw_search.sh @@ -0,0 +1,222 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Test the firmware_class.search= module parameter, which allows +# specifying multiple colon-separated firmware search directories. + +set -e + +TEST_REQS_FW_SYSFS_FALLBACK="no" +TEST_REQS_FW_SET_CUSTOM_PATH="no" +TEST_DIR=$(dirname $0) +source $TEST_DIR/fw_lib.sh + +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +SEARCH_SYSFS="/sys/module/firmware_class/parameters/search" +PATH_SYSFS="/sys/module/firmware_class/parameters/path" + +check_mods +check_setup +verify_reqs + +if [ ! -f "$SEARCH_SYSFS" ]; then + echo "$0: search= parameter not available, skipping" + exit $ksft_skip +fi + +# Save original values +OLD_SEARCH="$(cat $SEARCH_SYSFS)" +OLD_PATH="$(cat $PATH_SYSFS)" + +# Create temp directories for firmware +FWDIR1=$(mktemp -d) +FWDIR2=$(mktemp -d) +FWDIR3=$(mktemp -d) + +FW_NAME="test-search-fw.bin" +FW_CONTENT1="SEARCH_PATH_1" +FW_CONTENT2="SEARCH_PATH_2" +FW_CONTENT3="SEARCH_PATH_3" + +DIR=/sys/devices/virtual/misc/test_firmware + +cleanup() +{ + # Restore original values + if [ "$OLD_PATH" = "" ]; then + printf '\000' >$PATH_SYSFS + else + echo -n "$OLD_PATH" >$PATH_SYSFS + fi + if [ "$OLD_SEARCH" = "" ]; then + printf '\000' >$SEARCH_SYSFS + else + echo -n "$OLD_SEARCH" >$SEARCH_SYSFS + fi + rm -rf "$FWDIR1" "$FWDIR2" "$FWDIR3" +} +trap cleanup EXIT + +# Clear path= so search= is consulted +printf '\000' >$PATH_SYSFS + +# Test 1: firmware found in first search path +echo -n "$FW_CONTENT1" >"$FWDIR1/$FW_NAME" +echo -n "$FWDIR1:$FWDIR2" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 1" >&2 + exit 1 +fi +if ! diff -q "$FWDIR1/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 1" >&2 + exit 1 +fi +echo "$0: search path - first directory: OK" + +# Test 2: firmware found in second search path (not in first) +rm -f "$FWDIR1/$FW_NAME" +echo -n "$FW_CONTENT2" >"$FWDIR2/$FW_NAME" +echo -n "$FWDIR1:$FWDIR2" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 2" >&2 + exit 1 +fi +if ! diff -q "$FWDIR2/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 2" >&2 + exit 1 +fi +echo "$0: search path - second directory: OK" + +# Test 3: firmware not found in any search path +rm -f "$FWDIR2/$FW_NAME" +echo -n "$FWDIR1:$FWDIR2" >$SEARCH_SYSFS + +if echo -n "nonexistent-$FW_NAME" >$DIR/trigger_request 2>/dev/null; then + echo "$0: FAIL - firmware should not have been found in test 3" >&2 + exit 1 +fi +echo "$0: search path - not found: OK" + +# Test 4: path= takes priority over search= +echo -n "$FW_CONTENT1" >"$FWDIR1/$FW_NAME" +echo -n "$FW_CONTENT2" >"$FWDIR2/$FW_NAME" +echo -n "$FWDIR1" >$PATH_SYSFS +echo -n "$FWDIR2" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 4" >&2 + exit 1 +fi +if ! diff -q "$FWDIR1/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - path= should take priority over search= in test 4" >&2 + exit 1 +fi +echo "$0: search path - path= priority over search=: OK" + +# Clear path= again for remaining tests +printf '\000' >$PATH_SYSFS + +# Test 5: three search paths, firmware in third +rm -f "$FWDIR1/$FW_NAME" "$FWDIR2/$FW_NAME" +echo -n "$FW_CONTENT3" >"$FWDIR3/$FW_NAME" +echo -n "$FWDIR1:$FWDIR2:$FWDIR3" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 5" >&2 + exit 1 +fi +if ! diff -q "$FWDIR3/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 5" >&2 + exit 1 +fi +echo "$0: search path - third directory: OK" + +# Test 6: empty search= should not break anything +rm -f "$FWDIR3/$FW_NAME" +printf '\000' >$SEARCH_SYSFS + +if echo -n "nonexistent-$FW_NAME" >$DIR/trigger_request 2>/dev/null; then + echo "$0: FAIL - empty search= should not find firmware" >&2 + exit 1 +fi +echo "$0: search path - empty search=: OK" + +# Test 7: verify sysfs readback matches what was written +echo -n "$FWDIR1:$FWDIR2:$FWDIR3" >$SEARCH_SYSFS +READBACK="$(cat $SEARCH_SYSFS)" +EXPECTED="$FWDIR1:$FWDIR2:$FWDIR3" +if [ "$READBACK" != "$EXPECTED" ]; then + echo "$0: FAIL - sysfs readback mismatch: '$READBACK' != '$EXPECTED'" >&2 + exit 1 +fi +echo "$0: search path - sysfs readback: OK" + +# Test 8: escaped colon in directory name (\: -> literal ':') +FWDIR_COLON=$(mktemp -d)/fw:dir +mkdir -p "$FWDIR_COLON" +echo -n "$FW_CONTENT1" >"$FWDIR_COLON/$FW_NAME" +# Write the path with the colon escaped as \: +ESCAPED_COLON="${FWDIR_COLON//:/\\:}" +echo -n "$ESCAPED_COLON" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 8" >&2 + rm -rf "$(dirname "$FWDIR_COLON")" + exit 1 +fi +if ! diff -q "$FWDIR_COLON/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 8" >&2 + rm -rf "$(dirname "$FWDIR_COLON")" + exit 1 +fi +rm -rf "$(dirname "$FWDIR_COLON")" +echo "$0: search path - escaped colon in directory: OK" + +# Test 9: escaped backslash in directory name (\\ -> literal '\') +FWDIR_BS=$(mktemp -d)/fw\\dir +mkdir -p "$FWDIR_BS" +echo -n "$FW_CONTENT2" >"$FWDIR_BS/$FW_NAME" +# Write the path with backslashes escaped as \\ +ESCAPED_BS="${FWDIR_BS//\\/\\\\}" +echo -n "$ESCAPED_BS" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 9" >&2 + rm -rf "$(dirname "$FWDIR_BS")" + exit 1 +fi +if ! diff -q "$FWDIR_BS/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 9" >&2 + rm -rf "$(dirname "$FWDIR_BS")" + exit 1 +fi +rm -rf "$(dirname "$FWDIR_BS")" +echo "$0: search path - escaped backslash in directory: OK" + +# Test 10: escaped colon with multiple search paths +FWDIR_COLON2=$(mktemp -d)/has:colon +mkdir -p "$FWDIR_COLON2" +echo -n "$FW_CONTENT3" >"$FWDIR_COLON2/$FW_NAME" +ESCAPED_COLON2="${FWDIR_COLON2//:/\\:}" +# First path is normal (no firmware), second has escaped colon (has firmware) +echo -n "$FWDIR1:$ESCAPED_COLON2" >$SEARCH_SYSFS + +if ! echo -n "$FW_NAME" >$DIR/trigger_request; then + echo "$0: FAIL - could not trigger request for test 10" >&2 + rm -rf "$(dirname "$FWDIR_COLON2")" + exit 1 +fi +if ! diff -q "$FWDIR_COLON2/$FW_NAME" /dev/test_firmware >/dev/null; then + echo "$0: FAIL - firmware content mismatch in test 10" >&2 + rm -rf "$(dirname "$FWDIR_COLON2")" + exit 1 +fi +rm -rf "$(dirname "$FWDIR_COLON2")" +echo "$0: search path - escaped colon with multiple paths: OK" + +echo "$0: all search path tests passed" +exit 0 -- 2.53.0 ^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths 2026-03-23 14:39 [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton 2026-03-23 14:39 ` [PATCH v5 1/2] firmware_loader: add search= module option for multi-path firmware lookup Jeff Layton 2026-03-23 14:39 ` [PATCH v5 2/2] selftests/firmware: add search path test for firmware_class.search= Jeff Layton @ 2026-03-23 14:45 ` Jeff Layton 2 siblings, 0 replies; 4+ messages in thread From: Jeff Layton @ 2026-03-23 14:45 UTC (permalink / raw) To: Luis Chamberlain, Russ Weight, Danilo Krummrich, Greg Kroah-Hartman, Rafael J. Wysocki, Shuah Khan Cc: Michal Grzedzicki, driver-core, linux-kernel, linux-kselftest Erm, obviously I forgot to update the subject line on the b4 cover letter. Just pretend it says: "firmware_loader: add search= module option for multi-path firmware lookup" Thanks, Jeff On Mon, 2026-03-23 at 10:39 -0400, Jeff Layton wrote: > This is something Michal had asked for last year, and I just got around > to implementing. This version also adds some selftests for this > functionality. > > Signed-off-by: Jeff Layton <jlayton@kernel.org> > --- > Changes in v5: > - Increase search= string length from 256 to 4096 > - Preprocess search= path when it's set rather than on every firmware load > - Add selftests for search= functionality > - Link to v4: https://lore.kernel.org/r/20260320-fw-path-v4-1-7547e2f0dc64@kernel.org > > Changes in v4: > - Move search path to new search= option that is tried after path= > - Link to v3: https://lore.kernel.org/r/20260318-fw-path-v3-1-a701a08bc025@kernel.org > > Changes in v3: > - Allow '\' to escape a literal ':' or '\' in the string > - Link to v2: https://lore.kernel.org/r/20260318-fw-path-v2-1-8a106eb91eb4@kernel.org > > Changes in v2: > - switch to using ':' as path delimiter > - Link to v1: https://lore.kernel.org/r/20260318-fw-path-v1-1-7884d9bf618f@kernel.org > > --- > Jeff Layton (2): > firmware_loader: add search= module option for multi-path firmware lookup > selftests/firmware: add search path test for firmware_class.search= > > drivers/base/firmware_loader/main.c | 273 +++++++++++++++++++------- > tools/testing/selftests/firmware/Makefile | 2 +- > tools/testing/selftests/firmware/fw_search.sh | 222 +++++++++++++++++++++ > 3 files changed, 420 insertions(+), 77 deletions(-) > --- > base-commit: c369299895a591d96745d6492d4888259b004a9e > change-id: 20260317-fw-path-a094c30259a5 > > Best regards, -- Jeff Layton <jlayton@kernel.org> ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-03-23 14:45 UTC | newest] Thread overview: 4+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-03-23 14:39 [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton 2026-03-23 14:39 ` [PATCH v5 1/2] firmware_loader: add search= module option for multi-path firmware lookup Jeff Layton 2026-03-23 14:39 ` [PATCH v5 2/2] selftests/firmware: add search path test for firmware_class.search= Jeff Layton 2026-03-23 14:45 ` [PATCH v5 0/2] firmware_loader: allow firmware_class.path to take multiple paths Jeff Layton
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox