[BUG] One-time initialization of riscv_hwprobe vDSO data results in inconsistent results
Tsukasa OI
research_trasio at irq.a4lg.com
Sun May 18 19:27:56 PDT 2025
Hello,
While I'm testing a userland Rust patch to query target CPU features
using the riscv_hwprobe system call on Linux, I found a strange mismatch
between a test program written in C.
cf. <https://github.com/rust-lang/stdarch/pull/1770>
On my QEMU-based simulator setup, the Rust version returned the value
RISCV_HWPROBE_MISALIGNED_VECTOR_FAST for the key
RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF but the test program (in C)
returned RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN.
Strangely, the value obtained by the Rust version is correct.
Later I found that the difference between C and Rust programs (both
using riscv_hwprobe) is whether to use vDSO or not.
To avoid compatibility issues, the Rust userland version calls the
syscall function through the libc crate, which (accidentally) avoids
using vDSO. On the other hand, the test program written in C uses
__riscv_hwprobe glibc function, which utilizes vDSO. Calling syscall
from the test program in C changed the results so that all values are
consistent with the Rust-based program.
After applying the small instrumentation patch below
(this is applicable to kernel v6.15-rc7),
> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index 249aec8594a9..f59b82e35b7e 100644--- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -495,6 +495,7 @@ static int __init init_hwprobe_vdso_data(void)
> * vDSO should defer to the kernel for exotic cpu masks.
> */
> avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1;
> + pr_info("init_hwprobe_vdso_data completed.\n");
> return 0;
> }
I found that vDSO data page for riscv_hwprobe system call is initialized
only once (by the init_hwprobe_vdso_data function) and never updated
(causing mismatches if the reference data is updated after the vDSO data
page is initialized).
Here is the excerpt from the kernel log on the test environment
(QEMU-based) with instrumentation:
> [ 0.375055] cpu0: Ratio of byte access time to unaligned word access is 5.46, unaligned accesses are fast
> [ 0.499882] init_hwprobe_vdso_data completed.
> [ 0.644822] cpu0: Ratio of vector byte access time to vector unaligned word access is 3.09, unaligned accesses are fast
Right after the first line is printed, *_FAST is set for
RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF (that's why it did not cause a
mismatch on this key).
However, when RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF's value is set to
*_FAST (right after the third line is printed), the vDSO data page is
already initialized (as in the second line), leaving the old state
(RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN) in the vDSO data page.
Not only it causes mismatches to benchmark-based data depending on the
timing, it can be a blocker of CPU hotplug support for the RISC-V
architecture as CPU hotplug can possibly change riscv_hwprobe results.
I'm not sure how to resolve this issue correctly (due to atomicity
requirements to update the vDSO data page) but at least I want this
issue to be acknowledged.
Best regards,
Tsukasa
More information about the linux-riscv
mailing list