fix: ensure XDG_DATA_DIRS contains system dirs so Vulkan drivers load#1742
fix: ensure XDG_DATA_DIRS contains system dirs so Vulkan drivers load#1742btlqql wants to merge 1 commit into
Conversation
The Vulkan ICD loader discovers driver manifests by scanning each entry of XDG_DATA_DIRS for a "vulkan/icd.d" subdirectory, falling back to "/usr/local/share:/usr/share" only when XDG_DATA_DIRS is unset. In a Linglong container the host XDG_DATA_DIRS (which on a Linyaps session points at Linyaps specific paths such as /var/lib/linglong/entries/share) can be forwarded into the container environment. That overrides the loader's default search path, so the loader never looks into /usr/share/vulkan/icd.d and fails to enumerate any GPU. This is why OpenGL keeps working (Mesa finds DRI drivers through the compiled-in library path) while Vulkan does not, and why exporting VK_ICD_FILENAMES works around it (issue OpenAtom-Linyaps#1457). Always ensure the conventional system data directories remain part of XDG_DATA_DIRS when assembling the container environment, preserving any forwarded value and avoiding duplicates. This lets the Vulkan loader (and any other XDG-data consumer) discover system provided data such as the Mesa Turnip/freedreno driver manifest under /usr/share/vulkan/icd.d. Resolves OpenAtom-Linyaps#1457. Signed-off-by: btlqql <2977859784@qq.com>
|
Welcome @btlqql! It looks like this is your first PR to OpenAtom-Linyaps/linyaps 🎉 |
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: btlqql The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
Hi @btlqql. Thanks for your PR. I'm waiting for a OpenAtom-Linyaps member to verify that this patch is reasonable to test. If it is, they should reply with Once the patch is verified, the new status will be reflected by the I understand the commands that are listed here. DetailsInstructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
There was a problem hiding this comment.
Code Review
This pull request ensures that conventional system data directories (/usr/local/share and /usr/share) remain reachable through XDG_DATA_DIRS in the container environment, which is necessary for the Vulkan ICD loader to discover system-provided driver manifests. It also adds corresponding unit tests to verify this behavior. The reviewer suggested optimizing the environment variable building logic to avoid unnecessary string copying and heap allocations when the system directories are already present.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| const std::vector<std::string> systemDataDirs{ "/usr/local/share", "/usr/share" }; | ||
| auto xdgIt = environment.find("XDG_DATA_DIRS"); | ||
| std::string currentValue = (xdgIt != environment.end()) ? xdgIt->second : std::string{}; | ||
| auto entries = | ||
| common::strings::split(currentValue, ':', common::strings::splitOption::SkipEmpty); | ||
|
|
||
| std::vector<std::string> dirs; | ||
| dirs.reserve(entries.size() + systemDataDirs.size()); | ||
| for (auto entry : entries) { | ||
| dirs.emplace_back(entry); | ||
| } | ||
|
|
||
| bool changed = (xdgIt == environment.end()); | ||
| for (const auto &dir : systemDataDirs) { | ||
| if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) { | ||
| dirs.push_back(dir); | ||
| changed = true; | ||
| } | ||
| } | ||
|
|
||
| if (changed) { | ||
| environment["XDG_DATA_DIRS"] = common::strings::join(dirs, ':'); | ||
| } | ||
| } |
There was a problem hiding this comment.
We can optimize this block to avoid unnecessary string copying and heap allocations:
- Use
std::string_viewforcurrentValueinstead of copyingxdgIt->secondinto a newstd::string. - Check if the system directories are already present in
entriesbefore allocating and copying elements intodirs. If they are already present, we can skip the entire update process entirely.
const std::vector<std::string> systemDataDirs{ "/usr/local/share", "/usr/share" };
auto xdgIt = environment.find("XDG_DATA_DIRS");
std::string_view currentValue = (xdgIt != environment.end()) ? std::string_view{xdgIt->second} : std::string_view{};
auto entries =
common::strings::split(currentValue, ':', common::strings::splitOption::SkipEmpty);
bool changed = (xdgIt == environment.end());
if (!changed) {
for (const auto &dir : systemDataDirs) {
if (std::find(entries.begin(), entries.end(), dir) == entries.end()) {
changed = true;
break;
}
}
}
if (changed) {
std::vector<std::string> dirs;
dirs.reserve(entries.size() + systemDataDirs.size());
for (auto entry : entries) {
dirs.emplace_back(entry);
}
for (const auto &dir : systemDataDirs) {
if (std::find(dirs.begin(), dirs.end(), dir) == dirs.end()) {
dirs.push_back(dir);
}
}
environment["XDG_DATA_DIRS"] = common::strings::join(dirs, ':');
}
Summary
Fixes #1457 — Mesa3D Snapdragon Turnip (freedreno) Vulkan driver fails to load inside Linglong containers, while OpenGL works.
Root cause
The Vulkan ICD loader discovers driver manifests by scanning each entry of
XDG_DATA_DIRSfor avulkan/icd.dsubdirectory, and only falls back to/usr/local/share:/usr/sharewhenXDG_DATA_DIRSis unset.Inside a Linglong container the host
XDG_DATA_DIRS— which on a Linyaps session points at Linyaps specific paths such as/var/lib/linglong/entries/share— can be forwarded into the container environment (e.g. viaforwardEnv()). That overrides the loader's default search path, so the loader never scans/usr/share/vulkan/icd.dand enumerates no GPU.This perfectly matches the reported symptoms:
XDG_DATA_DIRS.XDG_DATA_DIRS-based discovery.VK_ICD_FILENAMES=...works around it (as the maintainer confirmed), because that variable bypasses the directory search.Fix
In
ContainerCfgBuilder::buildEnv()(the central place where the container environment is assembled, used by both thell-cliand UAB paths), ensure the conventional system data directories/usr/shareand/usr/local/shareare always part ofXDG_DATA_DIRS:This lets the Vulkan loader (and any other XDG-data consumer) keep discovering system-provided data such as the Mesa Turnip driver manifest at
/usr/share/vulkan/icd.d, without requiring users to exportVK_ICD_FILENAMES.Files changed
libs/oci-cfg-generators/src/linglong/oci-cfg-generators/container_cfg_builder.cpp— normalizeXDG_DATA_DIRSinbuildEnv().libs/linglong/tests/ll-tests/src/linglong/oci_cfg_generators/container_cfg_builder_test.cpp— new regression tests.libs/linglong/tests/ll-tests/CMakeLists.txt— register the new test source.Verification
Configured with
cmake --preset debugand builtlinglong::linglong::ll-tests:Ran the new tests plus the surrounding runtime/env suites:
Result: 23/23 passed. The three new tests cover:
XDG_DATA_DIRSunset → defaults added (/usr/share,/usr/local/share).Full suite: 460 passed, 12 skipped (FUSE/display), 1 failure (
Error.WarpStdErrorCode) which is pre-existing and environmental — it expects a non-root runner, while the CI sandbox runs as root socreate_directory("/no_permission_to_create")succeeds.clang-format --dry-run --Werrorpasses on both changed source files.Risk / assumptions
XDG_DATA_DIRS; it never removes existing entries, so application/desktop-entry data discovery is unaffected.mesa-vulkan-driversprovides the freedreno ICD, as confirmed by the maintainer's test showing driverMesa 24.3.0-1deepin1).