mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
rtla: Abort on nr_cpus mismatch with tracer
In rare situations, sysfs might report a different number of CPUs than the kernel sees, for example, when /sys is not real sysfs. In tracefs mode, RTLA will discard any samples that are reported on CPUs higher than the maximum in sysfs. However, in BPF mode, the incorrectly sized BPF_MAP_LOOKUP_ELEM syscall on percpu maps will cause a buffer overflow. To cover for this corner case, write "all" to osnoise/cpus, and read back the real kernel-side list of all possible cpus. If it doesn't match RTLA's nr_cpus (read from sysfs), abort with an error. Assisted-by: Claude:claude-opus-4-6 Link: https://lore.kernel.org/r/20260814135511.2207190-4-tglozar@redhat.com Signed-off-by: Tomas Glozar <tglozar@redhat.com>
This commit is contained in:
parent
bdb4d4d5db
commit
b105ffc19d
|
|
@ -62,11 +62,22 @@ static void unset_signals(struct common_params *params)
|
|||
int
|
||||
common_apply_config(struct osnoise_tool *tool, struct common_params *params)
|
||||
{
|
||||
int retval, i;
|
||||
int retval, i, tracer_cpus;
|
||||
|
||||
if (!params->sleep_time)
|
||||
params->sleep_time = 1;
|
||||
|
||||
tracer_cpus = osnoise_get_cpu_count();
|
||||
if (tracer_cpus < 0) {
|
||||
err_msg("Failed to get tracer cpu count from osnoise/cpus\n");
|
||||
goto out_err;
|
||||
}
|
||||
if (tracer_cpus != nr_cpus) {
|
||||
err_msg("Kernel reports %d cpus but rtla sees %d\n",
|
||||
tracer_cpus, nr_cpus);
|
||||
goto out_err;
|
||||
}
|
||||
|
||||
retval = osnoise_set_cpus(tool->context, params->cpus ? params->cpus : "all");
|
||||
if (retval) {
|
||||
err_msg("Failed to apply CPUs config\n");
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ should_continue_tracing(const struct common_params *params)
|
|||
int
|
||||
common_threshold_handler(const struct osnoise_tool *tool);
|
||||
|
||||
int osnoise_get_cpu_count(void);
|
||||
int osnoise_set_cpus(struct osnoise_context *context, char *cpus);
|
||||
void osnoise_restore_cpus(struct osnoise_context *context);
|
||||
|
||||
|
|
|
|||
|
|
@ -124,6 +124,50 @@ void osnoise_put_cpus(struct osnoise_context *context)
|
|||
context->orig_cpus = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_get_cpu_count - get the number of CPUs as seen by the osnoise tracer
|
||||
*
|
||||
* Write "all" to osnoise/cpus and read back the real kernel-side list
|
||||
* of all possible cpus. Restore the original value afterwards.
|
||||
*
|
||||
* Returns the number of CPUs, or -1 on error.
|
||||
*/
|
||||
int osnoise_get_cpu_count(void)
|
||||
{
|
||||
char *orig, *readback;
|
||||
int max_cpu;
|
||||
|
||||
orig = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
|
||||
if (!orig)
|
||||
return -1;
|
||||
|
||||
if (tracefs_instance_file_write(NULL, "osnoise/cpus", "all\n") < 0) {
|
||||
free(orig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
readback = tracefs_instance_file_read(NULL, "osnoise/cpus", NULL);
|
||||
if (!readback) {
|
||||
tracefs_instance_file_write(NULL, "osnoise/cpus", orig);
|
||||
free(orig);
|
||||
return -1;
|
||||
}
|
||||
|
||||
max_cpu = get_max_cpu_from_list(readback);
|
||||
free(readback);
|
||||
|
||||
if (tracefs_instance_file_write(NULL, "osnoise/cpus", orig) < 0) {
|
||||
free(orig);
|
||||
return -1;
|
||||
}
|
||||
free(orig);
|
||||
|
||||
if (max_cpu < 0)
|
||||
return -1;
|
||||
|
||||
return max_cpu + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* osnoise_read_ll_config - read a long long value from a config
|
||||
*
|
||||
|
|
|
|||
|
|
@ -161,6 +161,22 @@ static int max_cpu_callback(int i, void *data)
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_max_cpu_from_list - get the maximum CPU in a CPU list
|
||||
*
|
||||
* Returns maximum CPU number, or -1 on error
|
||||
*/
|
||||
int get_max_cpu_from_list(const char *cpu_list)
|
||||
{
|
||||
int max_cpu = -1;
|
||||
|
||||
if (cpu_list_iterate(cpu_list, max_cpu_callback, &max_cpu) < 0)
|
||||
return -1;
|
||||
|
||||
return max_cpu;
|
||||
}
|
||||
|
||||
|
||||
static int tmp_cpu_set_callback(int i, void *data)
|
||||
{
|
||||
bool *cpu_set = data;
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ long parse_seconds_duration(char *val);
|
|||
void get_duration(time_t start_time, char *output, int output_size);
|
||||
|
||||
int cpu_list_iterate(const char *cpu_list, int (*callback)(int, void *), void *data);
|
||||
int get_max_cpu_from_list(const char *cpu_list);
|
||||
int get_possible_cpus(void);
|
||||
|
||||
long long get_llong_from_str(char *start);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user