Skip to content

[SYCL] Check access to /dev/dri/renderD* in sycl-ls #19520

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 41 additions & 0 deletions sycl/test/tools/Inputs/mock_renderd_access.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#define _GNU_SOURCE

#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>

int stat(const char *pathname, struct stat *statbuf) {
const char *mock_mode = getenv("MOCK_STAT_MODE");
if (strstr(pathname, "renderD128")) {
if (mock_mode && strcmp(mock_mode, "notfound") == 0) {
errno = ENOENT;
return -1;
}
if (mock_mode && strcmp(mock_mode, "exists") == 0) {
memset(statbuf, 0, sizeof(*statbuf));
statbuf->st_mode = S_IFCHR | 0666;
return 0;
}
}
// Default: file does not exist
errno = ENOENT;
return -1;
}

int open(const char *pathname, int flags, ...) {
const char *mock_mode = getenv("MOCK_OPEN_MODE");
if (strstr(pathname, "renderD128")) {
if (mock_mode && strcmp(mock_mode, "deny") == 0) {
errno = EACCES;
return -1;
}
if (mock_mode && strcmp(mock_mode, "allow") == 0) {
return 3; // Dummy fd
}
}
// Default: permission denied
errno = EACCES;
return -1;
}
21 changes: 21 additions & 0 deletions sycl/test/tools/render-group.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// REQUIRES: linux

// Compile Inputs/mock_renderd_access.c to a shared library and then use
// LD_PRELOAD to mock the stat and open functions.
// RUN: %clang -shared -fPIC -o %t-mock_stat.so %S/Inputs/mock_renderd_access.c

// Check the case when /dev/dri/renderD128 does not exist.
// RUN: env MOCK_STAT_MODE=notfound LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s -check-prefix=CHECK-NOTFOUND
// We don't expect any warning about permissions in this case.
// CHECK-NOTFOUND-NOT: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES).

// Check the case when /dev/dri/renderD128 exists but is not accessible.
// RUN: env MOCK_STAT_MODE=exists MOCK_OPEN_MODE=deny LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s --check-prefix=CHECK-DENY
// CHECK-DENY: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES).
// CHECK-DENY-NEXT: You might be missing the 'render' group locally.
// CHECK-DENY-NEXT: Try: sudo usermod -a -G render $USER
// CHECK-DENY-NEXT: Then log out and log back in.

// Check the case when /dev/dri/renderD128 exists and is accessible.
// RUN: env MOCK_STAT_MODE=exists MOCK_OPEN_MODE=allow LD_PRELOAD=%t-mock_stat.so sycl-ls --verbose --ignore-device-selectors 2>&1 | FileCheck %s --check-prefix=CHECK-GRANT
// CHECK-GRANT-NOT: WARNING: Unable to access /dev/dri/renderD128 due to permissions (EACCES).
34 changes: 33 additions & 1 deletion sycl/tools/sycl-ls/sycl-ls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
#include <string>
#include <vector>

#ifdef __linux__
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#endif
#ifdef _WIN32
#include <system_error>
#include <windows.h>
Expand Down Expand Up @@ -344,8 +351,30 @@ static int unsetFilterEnvVarsAndFork() {
}
#endif

int main(int argc, char **argv) {
static void checkRenderGroupPermission() {
#ifdef __linux__
// Check for /dev/dri/render* devices
for (int i = 128; i < 256; ++i) {
std::string path = std::string("/dev/dri/renderD") + std::to_string(i);
Comment on lines +356 to +358
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we know for sure that renderD directory name will have a suffix in the range 128 - 255? Any doc?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, is /dev/dri/renderD[128-255] directory only used by Intel GPUs?

Copy link
Contributor Author

@againull againull Jul 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to find official documentation regardin number of render nodes, but according to this comment it used to be limited to 64 (starting with D128, ..) but that condition was relaxed:
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/drivers/gpu/drm/drm_drv.c#n131
So I think better to just use globbing to find existing nodes, here is the follow-up patch:
#19538

According to my understanding, /dev/dri/renderD* is used not only by intel gpu graphics driver but also, for example, for ROCM (https://rocm.docs.amd.com/projects/install-on-linux/en/latest/how-to/docker.html#restricting-gpu-access).
in this case we generate general warning in verbose mode indicating that some permissions are missing which are necessary for gpgpu offloading on some backends (intel, rocm and probably something else).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. That makes sense.

struct stat st;
if (stat(path.c_str(), &st) == 0) {
int fd = open(path.c_str(), O_RDWR);
if (fd < 0 && errno == EACCES) {
std::cerr << "WARNING: Unable to access " << path
<< " due to permissions (EACCES).\n"
<< "You might be missing the 'render' group locally.\n"
<< "Try: sudo usermod -a -G render $USER\n"
<< "Then log out and log back in.\n";
break;
}
if (fd >= 0)
close(fd);
}
}
#endif
}

int main(int argc, char **argv) {
if (argc == 1) {
verbose = false;
DiscardFilters = false;
Expand All @@ -361,6 +390,9 @@ int main(int argc, char **argv) {
}
}

if (verbose)
checkRenderGroupPermission();

bool SuppressNumberPrinting = false;
// Print warning and suppress printing device ids if any of
// the filter environment variable is set.
Expand Down