Skip to content

Commit 997f6ec

Browse files
authored
fix: preserve hybrid graphics and publish stability (#1239)
1 parent 8e66b98 commit 997f6ec

9 files changed

Lines changed: 110 additions & 28 deletions

File tree

.github/workflows/build-aarch64.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ jobs:
7878
with:
7979
storage-backend: btrfs
8080
update-podman: true
81+
native-overlay: true
8182
install-tools: '["just"]'
8283

8384
- name: Capture build timestamp

.github/workflows/build.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ jobs:
9595
with:
9696
storage-backend: btrfs
9797
update-podman: true
98+
native-overlay: true
9899
install-tools: '["just"]'
99100

100101
- name: Generate BuildStream CI config

.github/workflows/execute-release.yml

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ jobs:
143143
[
144144
{"image":"dakota","source_tag":"${{ needs.freshness-check.outputs.build_sha }}","target_tag":"stable"},
145145
{"image":"dakota-nvidia","source_tag":"${{ needs.freshness-check.outputs.build_sha }}","target_tag":"stable"},
146-
{"image":"dakota-gaming","source_tag":"${{ needs.freshness-check.outputs.build_sha }}","target_tag":"stable"}
146+
{"image":"dakota-gaming","source_tag":"${{ needs.freshness-check.outputs.build_sha }}","target_tag":"stable"},
147+
{"image":"dakota-nvidia-gaming","source_tag":"${{ needs.freshness-check.outputs.build_sha }}","target_tag":"stable"}
147148
]
148149
cosign_identity_regexp: ^https://github\.com/projectbluefin/dakota/\.github/workflows/publish\.yml@refs/heads/(testing|gh-readonly-queue/testing/.+)$
149150
# fast_forward_branch omitted: handled by update-main-bookmark job below,
@@ -234,7 +235,7 @@ jobs:
234235
id: digests
235236
run: |
236237
set -euo pipefail
237-
for image in dakota dakota-nvidia dakota-gaming; do
238+
for image in dakota dakota-nvidia dakota-gaming dakota-nvidia-gaming; do
238239
digest=$(skopeo inspect --no-tags "docker://ghcr.io/projectbluefin/${image}:stable" \
239240
| jq -r '.Digest' | cut -c1-19)
240241
echo "${image}=${digest}" >> "$GITHUB_OUTPUT"
@@ -245,6 +246,7 @@ jobs:
245246
DAKOTA_DIGEST: ${{ steps.digests.outputs.dakota }}
246247
NVIDIA_DIGEST: ${{ steps.digests.outputs.dakota-nvidia }}
247248
GAMING_DIGEST: ${{ steps.digests.outputs.dakota-gaming }}
249+
NVIDIA_GAMING_DIGEST: ${{ steps.digests.outputs.dakota-nvidia-gaming }}
248250
run: |
249251
set -euo pipefail
250252
TAG=$(gh release list --repo "${{ github.repository }}" --limit 1 --json tagName --jq '.[0].tagName')
@@ -258,6 +260,7 @@ jobs:
258260
"| \`dakota\` | \`:stable\` | \`${DAKOTA_DIGEST}\` |" \
259261
"| \`dakota-nvidia\` | \`:stable\` | \`${NVIDIA_DIGEST}\` |" \
260262
"| \`dakota-gaming\` | \`:stable\` | \`${GAMING_DIGEST}\` |" \
263+
"| \`dakota-nvidia-gaming\` | \`:stable\` | \`${NVIDIA_GAMING_DIGEST}\` |" \
261264
'' \
262265
'---' \
263266
'')
@@ -398,7 +401,7 @@ jobs:
398401
run: |
399402
set -euo pipefail
400403
sudo apt-get update -qq && sudo apt-get install -y -qq skopeo
401-
for image in dakota dakota-nvidia dakota-gaming; do
404+
for image in dakota dakota-nvidia dakota-gaming dakota-nvidia-gaming; do
402405
promoted_digest=$(skopeo inspect --no-tags \
403406
"docker://ghcr.io/projectbluefin/${image}:${BUILD_SHA}" | jq -r .Digest)
404407
stable_digest=$(skopeo inspect --no-tags \
@@ -459,6 +462,15 @@ jobs:
459462
delete-only-untagged-versions: 'true'
460463
continue-on-error: true
461464

465+
- name: Prune untagged GHCR versions for dakota-nvidia-gaming
466+
uses: actions/delete-package-versions@e5bc658cc4c965c472efe991f8beea3981499c55 # v5.0.0
467+
with:
468+
package-name: dakota-nvidia-gaming
469+
package-type: container
470+
min-versions-to-keep: 100
471+
delete-only-untagged-versions: 'true'
472+
continue-on-error: true
473+
462474
- name: Summary — ready for next cycle
463475
run: |
464476
{

.github/workflows/publish.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,14 @@ jobs:
141141
id: timestamp
142142
run: echo "created=$(date -u +%Y-%m-%dT%H:%M:%SZ)" >> "$GITHUB_OUTPUT"
143143

144-
# update-podman: true — newer podman from Ubuntu resolute for bst2 + push.
145-
# Note: setup-runner btrfs does not expose loopback-free; watch for disk
146-
# pressure and upstream the option if needed.
144+
# Use the runner's Podman stack with native rootful overlay storage.
145+
# FUSE-backed storage below chunkify's kernel overlay can return ESTALE.
147146
- name: Setup runner
148147
uses: projectbluefin/actions/bootc-build/setup-runner@v1
149148
with:
150149
storage-backend: btrfs
151150
update-podman: true
151+
native-overlay: true
152152
install-tools: '["just"]'
153153

154154
# Fetch-only BST config — pull artifact from remote CAS, no build/push
@@ -315,6 +315,7 @@ jobs:
315315
with:
316316
storage-backend: btrfs
317317
update-podman: true
318+
native-overlay: true
318319
install-tools: '["just"]'
319320

320321
# BST config for remote CAS — buildstream-sbom calls bst show --deps all

docs/skills/ci.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2038,6 +2038,43 @@ unacceptably slow even when the overlay is on the correct BTRFS volume. Dakota's
20382038
uses that recipe and then transfers the rootful result back to the runner user's
20392039
podman store before lint and push.
20402040

2041+
### GitHub runner Podman must use native rootful overlay storage (2026-07-29)
2042+
2043+
**Symptom:** `just chunkify` fails immediately after fakecap restoration while
2044+
walking the mounted rootfs:
2045+
2046+
```
2047+
Error: scanning /chunkah for files
2048+
Caused by:
2049+
0: failed to walk rootfs
2050+
1: Stale file handle (os error 116)
2051+
```
2052+
2053+
**Root cause:** the `ubuntu-24.04` runner image update from `20260720.247.2`
2054+
to `20260726.254.1` added a static Podman 5.8 stack under `/usr/local` and an
2055+
`/etc/containers/storage.conf` that selects `fuse-overlayfs`. Installing Podman
2056+
5.7 from Ubuntu Resolute does not remove those files: `/usr/local/bin/podman`
2057+
still wins path resolution while the host contains a mixture of runner and
2058+
Resolute packages. Dakota then creates a kernel overlay from `podman image
2059+
mount` and asks chunkah to scan that overlay through a Podman bind mount. The
2060+
FUSE-backed lower store can return `ESTALE` under that nested access pattern.
2061+
2062+
**Rule:** use the shared `setup-runner` action's explicit native-overlay mode at
2063+
every Dakota call site:
2064+
2065+
```yaml
2066+
with:
2067+
storage-backend: btrfs
2068+
update-podman: false
2069+
native-overlay: true
2070+
```
2071+
2072+
The shared action must keep this mode opt-in until other consumers validate it.
2073+
It must reject `native-overlay: true` together with `update-podman: true`, verify
2074+
the runner Podman version, and fail unless rootful `podman info` reports native
2075+
overlay without a `fuse-overlayfs` mount program. Do not remove or replace
2076+
runner binaries ad hoc in Dakota workflows.
2077+
20412078
### actions/cache does not create the cache directory on a cold miss — podman bind-mounts fail (2026-06-13)
20422079

20432080
`actions/cache` only *restores* an existing archive; on a cache miss it does

docs/skills/oci-layers.md

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -193,16 +193,23 @@ In a bootc/OSTree-based immutable OS like Dakota, `/etc` is mutable, user-owned,
193193
2. **Inject Bootc Kernel Arguments**: Install kargs TOML files directly under `/usr/lib/bootc/kargs.d/` (e.g. `/usr/lib/bootc/kargs.d/20-zswap.toml`). Bootc automatically reads these on switch/upgrade and applies them.
194194
3. **Vendor Sysctl parameters**: Store system defaults under `/usr/lib/sysctl.d/*.conf` (e.g. `60-swappiness.conf`) instead of `/etc/sysctl.conf`.
195195

196-
### Never install a real directory at a GL/ extension path from a layer (2026-07-18)
197-
198-
In the composed image, several paths under `%{libdir}/GL/` are symlinks into
199-
the Mesa GL extension tree (e.g. `GL/glvnd/egl_vendor.d ->
200-
../default/glvnd/egl_vendor.d`). A layer that installs a real directory at
201-
one of those paths shadows the symlink at OCI merge time and evicts the
202-
files behind it — installing an EGL vendor ICD to
203-
`%{libdir}/GL/glvnd/egl_vendor.d/` removed Mesa's `50_mesa.json` from
204-
GLVND's view and with it the llvmpipe fallback. Vendor ICDs belong in
205-
`/etc/glvnd/egl_vendor.d` (fdsdk's libglvnd searches only `/etc/glvnd` and
206-
the GL extension dir — never `/usr/share/glvnd`). The same shadowing hazard
207-
applies to any `GL/` path: check with `ls -ld` on a composed image before
208-
choosing an install location under `GL/`.
196+
### Preserve FDSDK GL merge symlinks when adding vendor backends (2026-07-18; updated 2026-07-29)
197+
198+
In the composed image, paths under `%{libdir}/GL/` are symlinks into the Mesa
199+
GL extension tree. A layer that installs a real directory at one of those
200+
paths shadows the symlink at OCI merge time and evicts the Mesa files behind
201+
it.
202+
203+
Two load-bearing examples:
204+
205+
- `GL/glvnd/egl_vendor.d -> ../default/glvnd/egl_vendor.d`: install vendor
206+
ICDs in `/etc/glvnd/egl_vendor.d`; fdsdk's libglvnd searches `/etc/glvnd`
207+
and the GL extension directory, not `/usr/share/glvnd`.
208+
- `GL/lib/gbm -> ../default/lib/gbm`: install an NVIDIA GBM backend in
209+
`GL/default/lib/gbm`, not `GL/lib/gbm`. Replacing this symlink hides Mesa's
210+
`dri_gbm.so`; Intel/AMD iGPU + NVIDIA dGPU laptops then fall back to the
211+
connector-less NVIDIA GPU and show a black GDM screen.
212+
213+
Final NVIDIA OCI assembly must assert that `GL/lib/gbm` remains a symlink and
214+
that both `dri_gbm.so` and `nvidia-drm_gbm.so` resolve through it. Check the
215+
composed path with `ls -ld` before choosing any install location under `GL/`.

docs/skills/release-promotion.md

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ testing (trunk) → build.yml → publish.yml → :testing tag
2424

2525
`main` is a release bookmark only. It is fast-forwarded by `execute-release.yml` after each successful promotion. Do not open PRs against `main`.
2626

27+
Stable promotion advances all four x86 variants together: `dakota`,
28+
`dakota-nvidia`, `dakota-gaming`, and `dakota-nvidia-gaming`. A missing or
29+
unverified SHA-pinned variant must fail promotion instead of leaving the stable
30+
variant set partially updated.
31+
2732
Do not conflate "publish is healthy" with "stable promotion is healthy".
2833

2934
## When to Use
@@ -348,10 +353,12 @@ flow (issue 1073). The key differences:
348353

349354
### Keep stable variant lists aligned
350355

351-
When adding an image variant to stable promotion, update the reusable release
352-
matrix, release-note digest collection, post-release digest verification, and
353-
untagged package cleanup together. The release workflow can otherwise promote
354-
only part of the variant set or report success without verifying the new image.
356+
The stable x86 set is `dakota`, `dakota-nvidia`, `dakota-gaming`, and
357+
`dakota-nvidia-gaming`. When adding or removing an image variant, update the
358+
reusable release matrix, release-note digest collection and table, post-release
359+
digest verification, and untagged package cleanup together. The release
360+
workflow can otherwise promote only part of the variant set or report success
361+
without verifying the new image.
355362

356363
## Rollback
357364

elements/bluefin-nvidia/nvidia-drivers.bst

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -175,11 +175,12 @@ config:
175175
ln -sf "$target" "$LIBDIR/${subdir}${name}"
176176
;;
177177
G)
178-
# Relocated to the backend dir freedesktop-sdk's Mesa
179-
# compiles into libgbm; the link IS the backend (its
180-
# entrypoints live in the target library).
181-
install -d "$LIBDIR/GL/lib/gbm"
182-
ln -sf "../../../$target" "$LIBDIR/GL/lib/gbm/$name"
178+
# FDSDK exposes GL/lib/gbm as a symlink to the Mesa extension's
179+
# GL/default/lib/gbm. Install into that target: creating a real
180+
# GL/lib/gbm here shadows Mesa's dri_gbm.so on hybrid systems.
181+
GBM_DIR="$LIBDIR/GL/default/lib/gbm"
182+
install -d "$GBM_DIR"
183+
ln -srf "$LIBDIR/$target" "$GBM_DIR/$name"
183184
;;
184185
esac
185186
done

elements/oci/bluefin-nvidia.bst

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,21 @@ config:
5656
- |
5757
dconf update /layer/etc/dconf/db
5858
59+
- |
60+
# FDSDK's Mesa merge path must stay a symlink so libgbm sees both
61+
# Mesa's DRI backend and NVIDIA's backend on hybrid systems.
62+
GBM_DIR="/layer%{libdir}/GL/lib/gbm"
63+
if [ ! -L "$GBM_DIR" ]; then
64+
echo "FATAL: $GBM_DIR is not the FDSDK Mesa merge symlink" >&2
65+
exit 1
66+
fi
67+
for backend in dri_gbm.so nvidia-drm_gbm.so; do
68+
if [ ! -e "$GBM_DIR/$backend" ]; then
69+
echo "FATAL: GBM backend $GBM_DIR/$backend is missing" >&2
70+
exit 1
71+
fi
72+
done
73+
5974
- |
6075
cd "%{install-root}"
6176
build-oci <<EOF

0 commit comments

Comments
 (0)