v3d: Don't use performance counters names array with an older kernel

Starting with Linux v6.11+, performance counter information is no
longer duplicated in both the kernel and userspace. Instead, an IOCTL
retrieves this information, allowing userspace to maintain a local
array for reuse, thus avoiding redundant kernel queries.

However, support for older kernels without these new IOCTLs remains.
To distinguish between versions, we check `devinfo->max_perfcnt` -
which is non-zero on Linux v6.11+ and zero on older kernels.

Currently, applications using performance queries on platforms with
older kernels encounter a SEGFAULT, as we don't validate
`devinfo->max_perfcnt` before accessing the userspace array for
performance counter information.

This commit makes sure that, if `devinfo->max_perfcnt` is zero,
`screen->perfcnt_names` will be NULL. This way, we can check if
`screen->perfcnt_names` is different than NULL before attempting to use
the userspace array.

Fixes: 017dde0d1c ("v3d: Use DRM_IOCTL_V3D_GET_COUNTER to get perfcnt information")
Signed-off-by: Maíra Canal <mcanal@igalia.com>
Reviewed-by: Juan A. Suarez <jasuarez@igalia.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31552>
This commit is contained in:
Maíra Canal 2024-10-07 19:34:52 -03:00
parent 5d7f3753d7
commit 47a78614ea
2 changed files with 24 additions and 19 deletions

View file

@ -942,10 +942,13 @@ v3d_screen_create(int fd, const struct pipe_screen_config *config,
if (!v3d_get_device_info(screen->fd, &screen->devinfo, &v3d_ioctl))
goto fail;
screen->perfcnt_names = rzalloc_array(screen, char*, screen->devinfo.max_perfcnt);
if (!screen->perfcnt_names) {
fprintf(stderr, "Error allocating performance counters names");
goto fail;
const uint8_t max_perfcnt = screen->devinfo.max_perfcnt;
if (max_perfcnt) {
screen->perfcnt_names = rzalloc_array(screen, char*, max_perfcnt);
if (!screen->perfcnt_names) {
fprintf(stderr, "Error allocating performance counters names");
goto fail;
}
}
driParseConfigFiles(config->options, config->options_info, 0, "v3d",

View file

@ -91,22 +91,24 @@ v3dX(get_driver_query_info_perfcnt)(struct v3d_screen *screen, unsigned index,
if (index >= max_perfcnt)
return 0;
if (screen->perfcnt_names[index]) {
info->name = screen->perfcnt_names[index];
} else if (devinfo->max_perfcnt) {
struct drm_v3d_perfmon_get_counter counter = {
.counter = index,
};
int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_PERFMON_GET_COUNTER, &counter);
if (ret != 0) {
fprintf(stderr, "Failed to get performance counter %d: %s\n",
index, strerror(errno));
return 0;
}
if (screen->perfcnt_names) {
if (screen->perfcnt_names[index]) {
info->name = screen->perfcnt_names[index];
} else {
struct drm_v3d_perfmon_get_counter counter = {
.counter = index,
};
int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_PERFMON_GET_COUNTER, &counter);
if (ret != 0) {
fprintf(stderr, "Failed to get performance counter %d: %s\n",
index, strerror(errno));
return 0;
}
screen->perfcnt_names[index] = ralloc_strdup(screen->perfcnt_names,
(const char *) counter.name);
info->name = screen->perfcnt_names[index];
screen->perfcnt_names[index] = ralloc_strdup(screen->perfcnt_names,
(const char *) counter.name);
info->name = screen->perfcnt_names[index];
}
} else {
info->name = v3d_performance_counters[index][V3D_PERFCNT_NAME];
}