From b7f73b86628ab8de3906d81f353ee293e55f93f5 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 21 Oct 2024 13:35:09 -0700 Subject: [PATCH 1/3] vmtest.config: skip RAID 6 algorithm benchmarking When we load the Btrfs module for running tests, it loads the raid6_pq module as a dependency. That module benchmarks a bunch of algorithms in order to pick the fastest one. This adds between half a second and 2 seconds of startup time for no reason, since we don't use Btrfs with RAID 6. Luckily, there is a kconfig option to disable benchmarking, so enable it. Unluckily, it was added in 5.0, so also patch it in for older vesrions. Signed-off-by: Omar Sandoval --- vmtest/config.py | 4 +- vmtest/kbuild.py | 4 + ...add-option-to-skip-algo-benchmarking.patch | 77 +++++++++++++++++++ 3 files changed, 84 insertions(+), 1 deletion(-) create mode 100644 vmtest/patches/lib-raid6-add-option-to-skip-algo-benchmarking.patch diff --git a/vmtest/config.py b/vmtest/config.py index 33953cb3f..f903d9ec0 100644 --- a/vmtest/config.py +++ b/vmtest/config.py @@ -127,6 +127,8 @@ # For filesystem tests. CONFIG_BTRFS_FS=m +# Don't waste time benchmarking in raid6_pq just to load the Btrfs module. +CONFIG_RAID6_PQ_BENCHMARK=n CONFIG_EXT4_FS=m CONFIG_XFS_FS=m @@ -423,7 +425,7 @@ def kconfig_localversion(arch: Architecture, flavor: KernelFlavor, version: str) vmtest_kernel_version = [ # Increment the major version to rebuild every # architecture/flavor/version combination. - 33, + 34, # The minor version makes the default flavor the "latest" version. 1 if flavor.name == "default" else 0, ] diff --git a/vmtest/kbuild.py b/vmtest/kbuild.py index 2c7eed5da..a5ce5b8f4 100644 --- a/vmtest/kbuild.py +++ b/vmtest/kbuild.py @@ -138,6 +138,10 @@ class _Patch(NamedTuple): name="s390-crash-fix-proc-vmcore-reads.patch", versions=((KernelVersion("5.18"), KernelVersion("6.0")),), ), + _Patch( + name="lib-raid6-add-option-to-skip-algo-benchmarking.patch", + versions=((None, KernelVersion("5.0")),), + ) ) diff --git a/vmtest/patches/lib-raid6-add-option-to-skip-algo-benchmarking.patch b/vmtest/patches/lib-raid6-add-option-to-skip-algo-benchmarking.patch new file mode 100644 index 000000000..e8bdd14e6 --- /dev/null +++ b/vmtest/patches/lib-raid6-add-option-to-skip-algo-benchmarking.patch @@ -0,0 +1,77 @@ +From be85f93ae2df32dea0b20908316f1d894c3e0f64 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Daniel Verkamp +Date: Mon, 12 Nov 2018 15:26:52 -0800 +Subject: [PATCH] lib/raid6: add option to skip algo benchmarking + +This is helpful for systems where fast startup time is important. +It is especially nice to avoid benchmarking RAID functions that are +never used (for example, BTRFS selects RAID6_PQ even if the parity RAID +mode is not in use). + +This saves 250+ milliseconds of boot time on modern x86 and ARM systems +with a dozen or more available implementations. + +The new option is defaulted to 'y' to match the previous behavior of +always benchmarking on init. + +Signed-off-by: Daniel Verkamp +Signed-off-by: Shaohua Li +--- + include/linux/raid/pq.h | 3 +++ + lib/Kconfig | 8 ++++++++ + lib/raid6/algos.c | 5 +++++ + 3 files changed, 16 insertions(+) + +diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h +index d7c99161bba2..605cf46c17bd 100644 +--- a/include/linux/raid/pq.h ++++ b/include/linux/raid/pq.h +@@ -70,6 +70,9 @@ extern const char raid6_empty_zero_page[PAGE_SIZE]; + #define MODULE_DESCRIPTION(desc) + #define subsys_initcall(x) + #define module_exit(x) ++ ++#define IS_ENABLED(x) (x) ++#define CONFIG_RAID6_PQ_BENCHMARK 1 + #endif /* __KERNEL__ */ + + /* Routine choices */ +diff --git a/lib/Kconfig b/lib/Kconfig +index a9965f4af4dd..fcb05305a5a2 100644 +--- a/lib/Kconfig ++++ b/lib/Kconfig +@@ -10,6 +10,14 @@ menu "Library routines" + config RAID6_PQ + tristate + ++config RAID6_PQ_BENCHMARK ++ bool "Automatically choose fastest RAID6 PQ functions" ++ depends on RAID6_PQ ++ default y ++ help ++ Benchmark all available RAID6 PQ functions on init and choose the ++ fastest one. ++ + config BITREVERSE + tristate + +diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c +index a753ff56670f..7e4f7a8ffa8e 100644 +--- a/lib/raid6/algos.c ++++ b/lib/raid6/algos.c +@@ -163,6 +163,11 @@ static inline const struct raid6_calls *raid6_choose_gen( + if ((*algo)->valid && !(*algo)->valid()) + continue; + ++ if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) { ++ best = *algo; ++ break; ++ } ++ + perf = 0; + + preempt_disable(); +-- +2.47.0 + From fd2ffbdaa2da0ab52f4ec5193c83dd6754d6accb Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Mon, 21 Oct 2024 16:06:27 -0700 Subject: [PATCH 2/3] vmtest.kbuild: add patch to fix 9p slab cache naming on Linux 6.12 6.12-rc4 introduced a regression that causes EIO errors when listing /sys/kernel/slab [1]. A fix is queued up for rc5. Patch it in the meantime. 1: https://lore.kernel.org/all/ZxafcO8KWMlXaeWE@telecaster.dhcp.thefacebook.com/ Signed-off-by: Omar Sandoval --- vmtest/kbuild.py | 6 ++- ...ix-slab-cache-name-creation-for-real.patch | 50 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 vmtest/patches/9p-fix-slab-cache-name-creation-for-real.patch diff --git a/vmtest/kbuild.py b/vmtest/kbuild.py index a5ce5b8f4..f71c20394 100644 --- a/vmtest/kbuild.py +++ b/vmtest/kbuild.py @@ -51,6 +51,10 @@ class _Patch(NamedTuple): name="proc-kcore-allow-enabling-CONFIG_PROC_KCORE-on-ARM.patch", versions=((None, None),), ), + _Patch( + name="9p-fix-slab-cache-name-creation-for-real.patch", + versions=((KernelVersion("6.12"), None),), + ), _Patch( name="filelock-fix-name-of-file_lease-slab-cache.patch", versions=((KernelVersion("6.9"), KernelVersion("6.10")),), @@ -141,7 +145,7 @@ class _Patch(NamedTuple): _Patch( name="lib-raid6-add-option-to-skip-algo-benchmarking.patch", versions=((None, KernelVersion("5.0")),), - ) + ), ) diff --git a/vmtest/patches/9p-fix-slab-cache-name-creation-for-real.patch b/vmtest/patches/9p-fix-slab-cache-name-creation-for-real.patch new file mode 100644 index 000000000..db8207078 --- /dev/null +++ b/vmtest/patches/9p-fix-slab-cache-name-creation-for-real.patch @@ -0,0 +1,50 @@ +From a360f311f57a36e96d88fa8086b749159714dcd2 Mon Sep 17 00:00:00 2001 +Message-ID: +From: Linus Torvalds +Date: Mon, 21 Oct 2024 11:57:38 -0700 +Subject: [PATCH] 9p: fix slab cache name creation for real + +This was attempted by using the dev_name in the slab cache name, but as +Omar Sandoval pointed out, that can be an arbitrary string, eg something +like "/dev/root". Which in turn trips verify_dirent_name(), which fails +if a filename contains a slash. + +So just make it use a sequence counter, and make it an atomic_t to avoid +any possible races or locking issues. + +Reported-and-tested-by: Omar Sandoval +Link: https://lore.kernel.org/all/ZxafcO8KWMlXaeWE@telecaster.dhcp.thefacebook.com/ +Fixes: 79efebae4afc ("9p: Avoid creating multiple slab caches with the same name") +Acked-by: Vlastimil Babka +Cc: Dominique Martinet +Cc: Thorsten Leemhuis +Signed-off-by: Linus Torvalds +--- + net/9p/client.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/net/9p/client.c b/net/9p/client.c +index 9e7b9151816d..09f8ced9f8bb 100644 +--- a/net/9p/client.c ++++ b/net/9p/client.c +@@ -977,6 +977,7 @@ static int p9_client_version(struct p9_client *c) + struct p9_client *p9_client_create(const char *dev_name, char *options) + { + int err; ++ static atomic_t seqno = ATOMIC_INIT(0); + struct p9_client *clnt; + char *client_id; + char *cache_name; +@@ -1036,7 +1037,8 @@ struct p9_client *p9_client_create(const char *dev_name, char *options) + if (err) + goto close_trans; + +- cache_name = kasprintf(GFP_KERNEL, "9p-fcall-cache-%s", dev_name); ++ cache_name = kasprintf(GFP_KERNEL, ++ "9p-fcall-cache-%u", atomic_inc_return(&seqno)); + if (!cache_name) { + err = -ENOMEM; + goto close_trans; +-- +2.47.0 + From 48b9629695407d3183693debcc15df9ee7049c92 Mon Sep 17 00:00:00 2001 From: Omar Sandoval Date: Tue, 22 Oct 2024 10:11:11 -0700 Subject: [PATCH 3/3] libdrgn: python: allow nesting blocking callbacks The upcoming module API may nest blocking sections. PyEval_SaveThread() doesn't support nesting. We have to use the lower-level PyThreadState_GetUnchecked() (named _PyThreadState_UncheckedGet() before Python 3.13) and PyEval_ReleaseThread() APIs instead. Signed-off-by: Omar Sandoval --- libdrgn/drgn.h | 4 +++- libdrgn/python/drgnpy.h | 4 ++++ libdrgn/python/program.c | 8 ++++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/libdrgn/drgn.h b/libdrgn/drgn.h index 33a5505c7..57a003877 100644 --- a/libdrgn/drgn.h +++ b/libdrgn/drgn.h @@ -1307,7 +1307,8 @@ typedef void *drgn_program_begin_blocking_fn(struct drgn_program *prog, * * @param[in] arg @c callback_arg passed to @ref * drgn_program_set_blocking_callback(). - * @param[in] state Return value of @ref drgn_program_begin_blocking_fn(). + * @param[in] state Return value of matching call to @ref + * drgn_program_begin_blocking_fn(). */ typedef void drgn_program_end_blocking_fn(struct drgn_program *prog, void *arg, void *state); @@ -1319,6 +1320,7 @@ typedef void drgn_program_end_blocking_fn(struct drgn_program *prog, * long-running computations. They are intended for things like releasing the * [global interpreter * lock](https://docs.python.org/3/glossary.html#term-global-interpreter-lock). + * Calls to these callbacks may be nested, but they will always be matched. * * @param[in] begin_callback Callback called before a blocking operation. Can be * @c NULL to unset. diff --git a/libdrgn/python/drgnpy.h b/libdrgn/python/drgnpy.h index 7cfcfad9a..ebeb01baf 100644 --- a/libdrgn/python/drgnpy.h +++ b/libdrgn/python/drgnpy.h @@ -40,6 +40,10 @@ } while (0) #endif +#if PY_VERSION_HEX < 0x030d00a1 +#define PyThreadState_GetUnchecked _PyThreadState_UncheckedGet +#endif + #define DRGNPY_PUBLIC __attribute__((__visibility__("default"))) // PyLong_From* and PyLong_As* for stdint.h types. These use _Generic for diff --git a/libdrgn/python/program.c b/libdrgn/python/program.c index 600991ac8..c03ceb7d8 100644 --- a/libdrgn/python/program.c +++ b/libdrgn/python/program.c @@ -231,12 +231,16 @@ int Program_type_arg(Program *prog, PyObject *type_obj, bool can_be_none, static void *drgnpy_begin_blocking(struct drgn_program *prog, void *arg) { - return PyEval_SaveThread(); + PyThreadState *state = PyThreadState_GetUnchecked(); + if (state) + PyEval_ReleaseThread(state); + return state; } static void drgnpy_end_blocking(struct drgn_program *prog, void *arg, void *state) { - PyEval_RestoreThread(state); + if (state) + PyEval_RestoreThread(state); } static Program *Program_new(PyTypeObject *subtype, PyObject *args,