hardware acceleration and support for NVIDIA cards on nonfree images (#3089)

* add nvidia packages

* add nvidia deps to nonfree

* gpu_acceleration flag & nvidia hacking

* fix gpu_config & /tmp/lxc.log

* implement hardware acceleration more dynamically

* refactor OpenUI

* use mknod

* registry updates for multi-hardware-requirements

* pluralize

* handle new registry types

* remove log

* migrations and driver fixes

* wip

* misc patches

* handle nvidia-container differently

* chore: comments (#3093)

* chore: comments

* revert some sizing

---------

Co-authored-by: Matt Hill <mattnine@protonmail.com>

* Revert "handle nvidia-container differently"

This reverts commit d708ae53df.

* fix debian containers

* cleanup

* feat: add empty array placeholder in forms (#3095)

* fixes from testing, client side device filtering for better fingerprinting resistance

* fix mac builds

---------

Co-authored-by: Sam Sartor <me@samsartor.com>
Co-authored-by: Matt Hill <mattnine@protonmail.com>
Co-authored-by: Alex Inkin <alexander@inkin.ru>
This commit is contained in:
Aiden McClelland
2026-01-15 11:42:17 -08:00
committed by GitHub
parent e8ef39adad
commit 99871805bd
95 changed files with 2758 additions and 1092 deletions

View File

@@ -2,6 +2,7 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use clap::Parser;
use imbl::OrdMap;
use imbl_value::Value;
use once_cell::sync::OnceCell;
use rpc_toolkit::yajrc::RpcError;
@@ -53,7 +54,13 @@ impl Context for ContainerCliContext {
}
impl CallRemote<EffectContext> for ContainerCliContext {
async fn call_remote(&self, method: &str, params: Value, _: Empty) -> Result<Value, RpcError> {
async fn call_remote(
&self,
method: &str,
_: OrdMap<&'static str, Value>,
params: Value,
_: Empty,
) -> Result<Value, RpcError> {
call_remote_socket(
tokio::net::UnixStream::connect(&self.0.socket)
.await

View File

@@ -6,7 +6,7 @@ use crate::prelude::*;
use crate::service::Service;
#[derive(Clone)]
pub(in crate::service) struct EffectContext(Weak<Service>);
pub struct EffectContext(Weak<Service>);
impl EffectContext {
pub fn new(service: Weak<Service>) -> Self {
Self(service)

View File

@@ -15,7 +15,7 @@ mod dependency;
mod health;
mod net;
mod prelude;
mod subcontainer;
pub mod subcontainer;
mod system;
mod version;

View File

@@ -11,6 +11,10 @@ use crate::service::effects::prelude::*;
use crate::service::persistent_container::Subcontainer;
use crate::util::Invoke;
pub const NVIDIA_OVERLAY_PATH: &str = "/var/tmp/startos/nvidia-overlay";
pub const NVIDIA_OVERLAY_DEBIAN: &str = "/var/tmp/startos/nvidia-overlay/debian";
pub const NVIDIA_OVERLAY_GENERIC: &str = "/var/tmp/startos/nvidia-overlay/generic";
#[cfg(target_os = "linux")]
mod sync;
@@ -112,8 +116,34 @@ pub async fn create_subcontainer_fs(
.with_kind(ErrorKind::Incoherent)?,
);
tracing::info!("Mounting overlay {guid} for {image_id}");
// Determine which nvidia overlay to use based on distro detection
let nvidia_overlay: &[&str] = if context
.seed
.persistent_container
.s9pk
.as_manifest()
.images
.get(&image_id)
.map_or(false, |i| i.nvidia_container)
{
// Check if image is debian-based by looking for /etc/debian_version
let is_debian = tokio::fs::metadata(image.path().join("etc/debian_version"))
.await
.is_ok();
if is_debian && tokio::fs::metadata(NVIDIA_OVERLAY_DEBIAN).await.is_ok() {
&[NVIDIA_OVERLAY_DEBIAN]
} else if tokio::fs::metadata(NVIDIA_OVERLAY_GENERIC).await.is_ok() {
&[NVIDIA_OVERLAY_GENERIC]
} else {
&[]
}
} else {
&[]
};
let subcontainer_wrapper = Subcontainer {
overlay: OverlayGuard::mount(image, &mountpoint).await?,
overlay: OverlayGuard::mount_layers(&[], image, nvidia_overlay, &mountpoint).await?,
name: name
.unwrap_or_else(|| InternedString::intern(format!("subcontainer-{}", image_id))),
image_id: image_id.clone(),

View File

@@ -9,7 +9,6 @@ use std::sync::{Arc, Weak};
use std::time::Duration;
use axum::extract::ws::Utf8Bytes;
use crate::util::net::WebSocket;
use clap::Parser;
use futures::future::BoxFuture;
use futures::stream::FusedStream;
@@ -48,6 +47,7 @@ use crate::util::Never;
use crate::util::actor::concurrent::ConcurrentActor;
use crate::util::future::NonDetachingJoinHandle;
use crate::util::io::{AsyncReadStream, AtomicFile, TermSize, delete_file};
use crate::util::net::WebSocket;
use crate::util::serde::Pem;
use crate::util::sync::SyncMutex;
use crate::volume::data_dir;

View File

@@ -96,7 +96,9 @@ impl PersistentContainer {
.join("logs")
.join(&s9pk.as_manifest().id),
),
LxcConfig::default(),
LxcConfig {
hardware_acceleration: s9pk.manifest.hardware_acceleration,
},
)
.await?;
let rpc_client = lxc_container.connect_rpc(Some(RPC_CONNECT_TIMEOUT)).await?;