mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
feat: oci packer can now use mksquashfs if available (#70)
* feat: oci packer can now use mksquashfs if available * fix: use nproc in kernel build script for default jobs, and fix DEV.md guide * feat: working erofs backend
This commit is contained in:
parent
0a6a112133
commit
24c71e9725
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -1517,11 +1517,13 @@ dependencies = [
|
||||
"backhand",
|
||||
"bytes",
|
||||
"env_logger",
|
||||
"indexmap 2.2.6",
|
||||
"krata-tokio-tar",
|
||||
"log",
|
||||
"oci-spec",
|
||||
"path-clean",
|
||||
"reqwest",
|
||||
"scopeguard",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha256",
|
||||
|
@ -42,6 +42,7 @@ fancy-duration = "0.9.2"
|
||||
flate2 = "1.0"
|
||||
futures = "0.3.30"
|
||||
human_bytes = "0.4"
|
||||
indexmap = "2.2.6"
|
||||
indicatif = "0.17.8"
|
||||
ipnetwork = "0.20.0"
|
||||
libc = "0.2"
|
||||
|
15
DEV.md
15
DEV.md
@ -28,10 +28,21 @@ it's corresponding code path from the above table.
|
||||
|
||||
1. Install the specified Debian version on a x86_64 host _capable_ of KVM (NOTE: KVM is not used, Xen is a type-1 hypervisor).
|
||||
|
||||
2. Install required packages: `apt install git xen-system-amd64 flex bison libelf-dev libssl-dev bc`
|
||||
2. Install required packages:
|
||||
|
||||
```sh
|
||||
$ apt install git xen-system-amd64 build-essential libclang-dev musl-tools flex bison libelf-dev libssl-dev bc protobuf-compiler libprotobuf-dev squashfs-tools erofs-utils
|
||||
```
|
||||
|
||||
3. Install [rustup](https://rustup.rs) for managing a Rust environment.
|
||||
|
||||
Make sure to install the targets that you need for krata:
|
||||
|
||||
```sh
|
||||
$ rustup target add x86_64-unknown-linux-gnu
|
||||
$ rustup target add x86_64-unknown-linux-musl
|
||||
```
|
||||
|
||||
4. Configure `/etc/default/grub.d/xen.cfg` to give krata guests some room:
|
||||
|
||||
```sh
|
||||
@ -43,7 +54,7 @@ After changing the grub config, update grub: `update-grub`
|
||||
|
||||
Then reboot to boot the system as a Xen dom0.
|
||||
|
||||
You can validate that Xen is setup by running `xl info` and ensuring it returns useful information about the Xen hypervisor.
|
||||
You can validate that Xen is setup by running `dmesg | grep "Hypervisor detected"` and ensuring it returns a line like `Hypervisor detected: Xen PV`, if that is missing, the host is not running under Xen.
|
||||
|
||||
5. Clone the krata source code:
|
||||
```sh
|
||||
|
2
FAQ.md
2
FAQ.md
@ -2,7 +2,7 @@
|
||||
|
||||
## How does krata currently work?
|
||||
|
||||
The krata hypervisor makes it possible to launch OCI containers on a Xen hypervisor without utilizing the Xen userspace tooling. krata contains just enough of the userspace of Xen (reimplemented in Rust) to start an x86_64 Xen Linux PV guest, and implements a Linux init process that can boot an OCI container. It does so by converting an OCI image into a squashfs file and packaging basic startup data in a bundle which the init container can read.
|
||||
The krata hypervisor makes it possible to launch OCI containers on a Xen hypervisor without utilizing the Xen userspace tooling. krata contains just enough of the userspace of Xen (reimplemented in Rust) to start an x86_64 Xen Linux PV guest, and implements a Linux init process that can boot an OCI container. It does so by converting an OCI image into a squashfs/erofs file and packaging basic startup data in a bundle which the init container can read.
|
||||
|
||||
In addition, due to the desire to reduce dependence on the dom0 network, krata contains a networking daemon called kratanet. kratanet listens for krata guests to startup and launches a userspace networking environment. krata guests can access the dom0 networking stack via the proxynat layer that makes it possible to communicate over UDP, TCP, and ICMP (echo only) to the outside world. In addition, each krata guest is provided a "gateway" IP (both in IPv4 and IPv6) which utilizes smoltcp to provide a virtual host. That virtual host in the future could dial connections into the container to access container networking resources.
|
||||
|
||||
|
@ -182,8 +182,7 @@ async fn wait_guest_started(id: &str, events: EventStream) -> Result<()> {
|
||||
for layer in &oci.layers {
|
||||
let bar = ProgressBar::new(layer.total);
|
||||
bar.set_style(
|
||||
ProgressStyle::with_template("{msg} {wide_bar} {pos}/{len}")
|
||||
.unwrap(),
|
||||
ProgressStyle::with_template("{msg} {wide_bar}").unwrap(),
|
||||
);
|
||||
progresses.insert(layer.id.clone(), bar.clone());
|
||||
multi_progress.add(bar);
|
||||
@ -204,35 +203,54 @@ async fn wait_guest_started(id: &str, events: EventStream) -> Result<()> {
|
||||
_ => "unknown",
|
||||
};
|
||||
|
||||
progress.set_message(format!("{} {}", layer.id, phase));
|
||||
progress.set_length(layer.total);
|
||||
progress.set_position(layer.value);
|
||||
let simple = if let Some((_, hash)) = layer.id.split_once(':') {
|
||||
hash
|
||||
} else {
|
||||
id
|
||||
};
|
||||
let simple = if simple.len() > 10 {
|
||||
&simple[0..10]
|
||||
} else {
|
||||
simple
|
||||
};
|
||||
let message = format!("{:width$} {}", simple, phase, width = 10);
|
||||
|
||||
if message != progress.message() {
|
||||
progress.set_message(message);
|
||||
}
|
||||
|
||||
progress.update(|state| {
|
||||
state.set_len(layer.total);
|
||||
state.set_pos(layer.value);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
OciProgressEventPhase::Packing => {
|
||||
for (key, progress) in &mut *progresses {
|
||||
for (key, bar) in &mut *progresses {
|
||||
if key == "packing" {
|
||||
continue;
|
||||
}
|
||||
progress.finish_and_clear();
|
||||
multi_progress.remove(progress);
|
||||
bar.finish_and_clear();
|
||||
multi_progress.remove(bar);
|
||||
}
|
||||
progresses.retain(|k, _| k == "packing");
|
||||
if progresses.is_empty() {
|
||||
let progress = ProgressBar::new(100);
|
||||
progress.set_message("packing");
|
||||
progress.set_style(
|
||||
ProgressStyle::with_template("{msg} {wide_bar} {pos}/{len}")
|
||||
.unwrap(),
|
||||
ProgressStyle::with_template("{msg} {wide_bar}").unwrap(),
|
||||
);
|
||||
progresses.insert("packing".to_string(), progress);
|
||||
}
|
||||
let Some(progress) = progresses.get("packing") else {
|
||||
continue;
|
||||
};
|
||||
progress.set_message("packing image");
|
||||
progress.set_length(oci.total);
|
||||
progress.set_position(oci.value);
|
||||
|
||||
progress.update(|state| {
|
||||
state.set_len(oci.total);
|
||||
state.set_pos(oci.value);
|
||||
});
|
||||
}
|
||||
|
||||
_ => {}
|
||||
|
@ -5,6 +5,7 @@ use std::{
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use krata::launchcfg::LaunchPackedFormat;
|
||||
use krata::v1::{
|
||||
common::{
|
||||
guest_image_spec::Image, Guest, GuestErrorInfo, GuestExitInfo, GuestNetworkState,
|
||||
@ -238,6 +239,7 @@ impl GuestReconciler {
|
||||
let info = self
|
||||
.runtime
|
||||
.launch(GuestLaunchRequest {
|
||||
format: LaunchPackedFormat::Squashfs,
|
||||
uuid: Some(uuid),
|
||||
name: if spec.name.is_empty() {
|
||||
None
|
||||
|
@ -4,7 +4,7 @@ use futures::stream::TryStreamExt;
|
||||
use ipnetwork::IpNetwork;
|
||||
use krata::ethtool::EthtoolHandle;
|
||||
use krata::idm::client::IdmClient;
|
||||
use krata::launchcfg::{LaunchInfo, LaunchNetwork};
|
||||
use krata::launchcfg::{LaunchInfo, LaunchNetwork, LaunchPackedFormat};
|
||||
use libc::{sethostname, setsid, TIOCSCTTY};
|
||||
use log::{trace, warn};
|
||||
use nix::ioctl_write_int_bad;
|
||||
@ -80,11 +80,13 @@ impl GuestInit {
|
||||
let idm = IdmClient::open("/dev/hvc1")
|
||||
.await
|
||||
.map_err(|x| anyhow!("failed to open idm client: {}", x))?;
|
||||
self.mount_squashfs_images().await?;
|
||||
self.mount_config_image().await?;
|
||||
|
||||
let config = self.parse_image_config().await?;
|
||||
let launch = self.parse_launch_config().await?;
|
||||
|
||||
self.mount_root_image(launch.root.format.clone()).await?;
|
||||
|
||||
self.mount_new_root().await?;
|
||||
self.bind_new_root().await?;
|
||||
|
||||
@ -98,11 +100,19 @@ impl GuestInit {
|
||||
if result != 0 {
|
||||
warn!("failed to set hostname: {}", result);
|
||||
}
|
||||
|
||||
let etc = PathBuf::from_str("/etc")?;
|
||||
if !etc.exists() {
|
||||
fs::create_dir(&etc).await?;
|
||||
}
|
||||
let mut etc_hostname = etc;
|
||||
etc_hostname.push("hostname");
|
||||
fs::write(&etc_hostname, hostname + "\n").await?;
|
||||
}
|
||||
|
||||
if let Some(network) = &launch.network {
|
||||
trace!("initializing network");
|
||||
if let Err(error) = self.network_setup(network).await {
|
||||
if let Err(error) = self.network_setup(&launch, network).await {
|
||||
warn!("failed to initialize network: {}", error);
|
||||
}
|
||||
}
|
||||
@ -177,24 +187,41 @@ impl GuestInit {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn mount_squashfs_images(&mut self) -> Result<()> {
|
||||
trace!("mounting squashfs images");
|
||||
let image_mount_path = Path::new(IMAGE_MOUNT_PATH);
|
||||
async fn mount_config_image(&mut self) -> Result<()> {
|
||||
trace!("mounting config image");
|
||||
let config_mount_path = Path::new(CONFIG_MOUNT_PATH);
|
||||
self.mount_squashfs(Path::new(IMAGE_BLOCK_DEVICE_PATH), image_mount_path)
|
||||
.await?;
|
||||
self.mount_squashfs(Path::new(CONFIG_BLOCK_DEVICE_PATH), config_mount_path)
|
||||
self.mount_image(
|
||||
Path::new(CONFIG_BLOCK_DEVICE_PATH),
|
||||
config_mount_path,
|
||||
LaunchPackedFormat::Squashfs,
|
||||
)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn mount_root_image(&mut self, format: LaunchPackedFormat) -> Result<()> {
|
||||
trace!("mounting root image");
|
||||
let image_mount_path = Path::new(IMAGE_MOUNT_PATH);
|
||||
self.mount_image(Path::new(IMAGE_BLOCK_DEVICE_PATH), image_mount_path, format)
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn mount_squashfs(&mut self, from: &Path, to: &Path) -> Result<()> {
|
||||
trace!("mounting squashfs image {:?} to {:?}", from, to);
|
||||
async fn mount_image(
|
||||
&mut self,
|
||||
from: &Path,
|
||||
to: &Path,
|
||||
format: LaunchPackedFormat,
|
||||
) -> Result<()> {
|
||||
trace!("mounting {:?} image {:?} to {:?}", format, from, to);
|
||||
if !to.is_dir() {
|
||||
fs::create_dir(to).await?;
|
||||
}
|
||||
Mount::builder()
|
||||
.fstype(FilesystemType::Manual("squashfs"))
|
||||
.fstype(FilesystemType::Manual(match format {
|
||||
LaunchPackedFormat::Squashfs => "squashfs",
|
||||
LaunchPackedFormat::Erofs => "erofs",
|
||||
}))
|
||||
.flags(MountFlags::RDONLY)
|
||||
.mount(from, to)?;
|
||||
Ok(())
|
||||
@ -287,7 +314,7 @@ impl GuestInit {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn network_setup(&mut self, network: &LaunchNetwork) -> Result<()> {
|
||||
async fn network_setup(&mut self, cfg: &LaunchInfo, network: &LaunchNetwork) -> Result<()> {
|
||||
trace!("setting up network for link");
|
||||
|
||||
let etc = PathBuf::from_str("/etc")?;
|
||||
@ -295,14 +322,33 @@ impl GuestInit {
|
||||
fs::create_dir(etc).await?;
|
||||
}
|
||||
let resolv = PathBuf::from_str("/etc/resolv.conf")?;
|
||||
let mut lines = vec!["# krata resolver configuration".to_string()];
|
||||
for nameserver in &network.resolver.nameservers {
|
||||
lines.push(format!("nameserver {}", nameserver));
|
||||
|
||||
{
|
||||
let mut lines = vec!["# krata resolver configuration".to_string()];
|
||||
for nameserver in &network.resolver.nameservers {
|
||||
lines.push(format!("nameserver {}", nameserver));
|
||||
}
|
||||
|
||||
let mut conf = lines.join("\n");
|
||||
conf.push('\n');
|
||||
fs::write(resolv, conf).await?;
|
||||
}
|
||||
|
||||
let hosts = PathBuf::from_str("/etc/hosts")?;
|
||||
if let Some(ref hostname) = cfg.hostname {
|
||||
let mut lines = if hosts.exists() {
|
||||
fs::read_to_string(&hosts)
|
||||
.await?
|
||||
.lines()
|
||||
.map(|x| x.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
} else {
|
||||
vec!["127.0.0.1 localhost".to_string()]
|
||||
};
|
||||
lines.push(format!("127.0.1.1 {}", hostname));
|
||||
fs::write(&hosts, lines.join("\n") + "\n").await?;
|
||||
}
|
||||
|
||||
let mut conf = lines.join("\n");
|
||||
conf.push('\n');
|
||||
fs::write(resolv, conf).await?;
|
||||
self.network_configure_ethtool(network).await?;
|
||||
self.network_configure_link(network).await?;
|
||||
Ok(())
|
||||
|
@ -2,24 +2,30 @@ use std::collections::HashMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub enum LaunchPackedFormat {
|
||||
Squashfs,
|
||||
Erofs,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchNetworkIpv4 {
|
||||
pub address: String,
|
||||
pub gateway: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchNetworkIpv6 {
|
||||
pub address: String,
|
||||
pub gateway: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchNetworkResolver {
|
||||
pub nameservers: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchNetwork {
|
||||
pub link: String,
|
||||
pub ipv4: LaunchNetworkIpv4,
|
||||
@ -27,8 +33,14 @@ pub struct LaunchNetwork {
|
||||
pub resolver: LaunchNetworkResolver,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchRoot {
|
||||
pub format: LaunchPackedFormat,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||
pub struct LaunchInfo {
|
||||
pub root: LaunchRoot,
|
||||
pub hostname: Option<String>,
|
||||
pub network: Option<LaunchNetwork>,
|
||||
pub env: HashMap<String, String>,
|
||||
|
@ -14,11 +14,13 @@ async-compression = { workspace = true, features = ["tokio", "gzip", "zstd"] }
|
||||
async-trait = { workspace = true }
|
||||
backhand = { workspace = true }
|
||||
bytes = { workspace = true }
|
||||
indexmap = { workspace = true }
|
||||
krata-tokio-tar = { workspace = true }
|
||||
log = { workspace = true }
|
||||
oci-spec = { workspace = true }
|
||||
path-clean = { workspace = true }
|
||||
reqwest = { workspace = true }
|
||||
scopeguard = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
sha256 = { workspace = true }
|
||||
|
@ -3,7 +3,11 @@ use std::{env::args, path::PathBuf};
|
||||
use anyhow::Result;
|
||||
use env_logger::Env;
|
||||
use krataoci::{
|
||||
cache::ImageCache, compiler::ImageCompiler, name::ImageName, progress::OciProgressContext,
|
||||
cache::ImageCache,
|
||||
compiler::OciImageCompiler,
|
||||
name::ImageName,
|
||||
packer::OciPackerFormat,
|
||||
progress::{OciProgress, OciProgressContext},
|
||||
};
|
||||
use tokio::{fs, sync::broadcast};
|
||||
|
||||
@ -21,21 +25,30 @@ async fn main() -> Result<()> {
|
||||
|
||||
let cache = ImageCache::new(&cache_dir)?;
|
||||
|
||||
let (sender, mut receiver) = broadcast::channel(1000);
|
||||
let (sender, mut receiver) = broadcast::channel::<OciProgress>(1000);
|
||||
tokio::task::spawn(async move {
|
||||
loop {
|
||||
let Some(_) = receiver.recv().await.ok() else {
|
||||
let Some(progress) = receiver.recv().await.ok() else {
|
||||
break;
|
||||
};
|
||||
println!("phase {:?}", progress.phase);
|
||||
for (id, layer) in progress.layers {
|
||||
println!(
|
||||
"{} {:?} {} of {}",
|
||||
id, layer.phase, layer.value, layer.total
|
||||
)
|
||||
}
|
||||
}
|
||||
});
|
||||
let context = OciProgressContext::new(sender);
|
||||
let compiler = ImageCompiler::new(&cache, seed, context)?;
|
||||
let info = compiler.compile(&image.to_string(), &image).await?;
|
||||
let compiler = OciImageCompiler::new(&cache, seed, context)?;
|
||||
let info = compiler
|
||||
.compile(&image.to_string(), &image, OciPackerFormat::Squashfs)
|
||||
.await?;
|
||||
println!(
|
||||
"generated squashfs of {} to {}",
|
||||
image,
|
||||
info.image_squashfs.to_string_lossy()
|
||||
info.image.to_string_lossy()
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,3 +1,5 @@
|
||||
use crate::packer::OciPackerFormat;
|
||||
|
||||
use super::compiler::ImageInfo;
|
||||
use anyhow::Result;
|
||||
use log::debug;
|
||||
@ -17,19 +19,19 @@ impl ImageCache {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn recall(&self, digest: &str) -> Result<Option<ImageInfo>> {
|
||||
let mut squashfs_path = self.cache_dir.clone();
|
||||
pub async fn recall(&self, digest: &str, format: OciPackerFormat) -> Result<Option<ImageInfo>> {
|
||||
let mut fs_path = self.cache_dir.clone();
|
||||
let mut config_path = self.cache_dir.clone();
|
||||
let mut manifest_path = self.cache_dir.clone();
|
||||
squashfs_path.push(format!("{}.squashfs", digest));
|
||||
fs_path.push(format!("{}.{}", digest, format.extension()));
|
||||
manifest_path.push(format!("{}.manifest.json", digest));
|
||||
config_path.push(format!("{}.config.json", digest));
|
||||
Ok(
|
||||
if squashfs_path.exists() && manifest_path.exists() && config_path.exists() {
|
||||
let squashfs_metadata = fs::metadata(&squashfs_path).await?;
|
||||
if fs_path.exists() && manifest_path.exists() && config_path.exists() {
|
||||
let image_metadata = fs::metadata(&fs_path).await?;
|
||||
let manifest_metadata = fs::metadata(&manifest_path).await?;
|
||||
let config_metadata = fs::metadata(&config_path).await?;
|
||||
if squashfs_metadata.is_file()
|
||||
if image_metadata.is_file()
|
||||
&& manifest_metadata.is_file()
|
||||
&& config_metadata.is_file()
|
||||
{
|
||||
@ -38,7 +40,7 @@ impl ImageCache {
|
||||
let config_text = fs::read_to_string(&config_path).await?;
|
||||
let config: ImageConfiguration = serde_json::from_str(&config_text)?;
|
||||
debug!("cache hit digest={}", digest);
|
||||
Some(ImageInfo::new(squashfs_path.clone(), manifest, config)?)
|
||||
Some(ImageInfo::new(fs_path.clone(), manifest, config)?)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -49,23 +51,24 @@ impl ImageCache {
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn store(&self, digest: &str, info: &ImageInfo) -> Result<ImageInfo> {
|
||||
pub async fn store(
|
||||
&self,
|
||||
digest: &str,
|
||||
info: &ImageInfo,
|
||||
format: OciPackerFormat,
|
||||
) -> Result<ImageInfo> {
|
||||
debug!("cache store digest={}", digest);
|
||||
let mut squashfs_path = self.cache_dir.clone();
|
||||
let mut fs_path = self.cache_dir.clone();
|
||||
let mut manifest_path = self.cache_dir.clone();
|
||||
let mut config_path = self.cache_dir.clone();
|
||||
squashfs_path.push(format!("{}.squashfs", digest));
|
||||
fs_path.push(format!("{}.{}", digest, format.extension()));
|
||||
manifest_path.push(format!("{}.manifest.json", digest));
|
||||
config_path.push(format!("{}.config.json", digest));
|
||||
fs::copy(&info.image_squashfs, &squashfs_path).await?;
|
||||
fs::copy(&info.image, &fs_path).await?;
|
||||
let manifest_text = serde_json::to_string_pretty(&info.manifest)?;
|
||||
fs::write(&manifest_path, manifest_text).await?;
|
||||
let config_text = serde_json::to_string_pretty(&info.config)?;
|
||||
fs::write(&config_path, config_text).await?;
|
||||
ImageInfo::new(
|
||||
squashfs_path.clone(),
|
||||
info.manifest.clone(),
|
||||
info.config.clone(),
|
||||
)
|
||||
ImageInfo::new(fs_path.clone(), info.manifest.clone(), info.config.clone())
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,14 @@
|
||||
use crate::cache::ImageCache;
|
||||
use crate::fetch::{OciImageDownloader, OciImageLayer};
|
||||
use crate::name::ImageName;
|
||||
use crate::packer::OciPackerFormat;
|
||||
use crate::progress::{OciProgress, OciProgressContext, OciProgressPhase};
|
||||
use crate::registry::OciRegistryPlatform;
|
||||
use anyhow::{anyhow, Result};
|
||||
use backhand::compression::Compressor;
|
||||
use backhand::{FilesystemCompressor, FilesystemWriter, NodeHeader};
|
||||
use log::{debug, trace, warn};
|
||||
use indexmap::IndexMap;
|
||||
use log::{debug, trace};
|
||||
use oci_spec::image::{ImageConfiguration, ImageManifest};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{BufWriter, ErrorKind, Read};
|
||||
use std::os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::pin::Pin;
|
||||
use tokio::fs;
|
||||
@ -20,51 +16,55 @@ use tokio::io::AsyncRead;
|
||||
use tokio_stream::StreamExt;
|
||||
use tokio_tar::{Archive, Entry};
|
||||
use uuid::Uuid;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
pub const IMAGE_SQUASHFS_VERSION: u64 = 2;
|
||||
pub const IMAGE_PACKER_VERSION: u64 = 2;
|
||||
|
||||
pub struct ImageInfo {
|
||||
pub image_squashfs: PathBuf,
|
||||
pub image: PathBuf,
|
||||
pub manifest: ImageManifest,
|
||||
pub config: ImageConfiguration,
|
||||
}
|
||||
|
||||
impl ImageInfo {
|
||||
pub fn new(
|
||||
squashfs: PathBuf,
|
||||
image: PathBuf,
|
||||
manifest: ImageManifest,
|
||||
config: ImageConfiguration,
|
||||
) -> Result<ImageInfo> {
|
||||
Ok(ImageInfo {
|
||||
image_squashfs: squashfs,
|
||||
image,
|
||||
manifest,
|
||||
config,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImageCompiler<'a> {
|
||||
pub struct OciImageCompiler<'a> {
|
||||
cache: &'a ImageCache,
|
||||
seed: Option<PathBuf>,
|
||||
progress: OciProgressContext,
|
||||
}
|
||||
|
||||
impl ImageCompiler<'_> {
|
||||
impl OciImageCompiler<'_> {
|
||||
pub fn new(
|
||||
cache: &ImageCache,
|
||||
seed: Option<PathBuf>,
|
||||
progress: OciProgressContext,
|
||||
) -> Result<ImageCompiler> {
|
||||
Ok(ImageCompiler {
|
||||
) -> Result<OciImageCompiler> {
|
||||
Ok(OciImageCompiler {
|
||||
cache,
|
||||
seed,
|
||||
progress,
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn compile(&self, id: &str, image: &ImageName) -> Result<ImageInfo> {
|
||||
debug!("compile image={image}");
|
||||
pub async fn compile(
|
||||
&self,
|
||||
id: &str,
|
||||
image: &ImageName,
|
||||
format: OciPackerFormat,
|
||||
) -> Result<ImageInfo> {
|
||||
debug!("compile image={image} format={:?}", format);
|
||||
let mut tmp_dir = std::env::temp_dir().clone();
|
||||
tmp_dir.push(format!("krata-compile-{}", Uuid::new_v4()));
|
||||
|
||||
@ -76,12 +76,17 @@ impl ImageCompiler<'_> {
|
||||
layer_dir.push("layer");
|
||||
fs::create_dir_all(&layer_dir).await?;
|
||||
|
||||
let mut squash_file = tmp_dir.clone();
|
||||
squash_file.push("image.squashfs");
|
||||
let mut packed_file = tmp_dir.clone();
|
||||
packed_file.push("image.packed");
|
||||
|
||||
let _guard = scopeguard::guard(tmp_dir.to_path_buf(), |delete| {
|
||||
tokio::task::spawn(async move {
|
||||
let _ = fs::remove_dir_all(delete).await;
|
||||
});
|
||||
});
|
||||
let info = self
|
||||
.download_and_compile(id, image, &layer_dir, &image_dir, &squash_file)
|
||||
.download_and_compile(id, image, &layer_dir, &image_dir, &packed_file, format)
|
||||
.await?;
|
||||
fs::remove_dir_all(&tmp_dir).await?;
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
@ -91,12 +96,13 @@ impl ImageCompiler<'_> {
|
||||
image: &ImageName,
|
||||
layer_dir: &Path,
|
||||
image_dir: &Path,
|
||||
squash_file: &Path,
|
||||
packed_file: &Path,
|
||||
format: OciPackerFormat,
|
||||
) -> Result<ImageInfo> {
|
||||
let mut progress = OciProgress {
|
||||
id: id.to_string(),
|
||||
phase: OciProgressPhase::Resolving,
|
||||
layers: BTreeMap::new(),
|
||||
layers: IndexMap::new(),
|
||||
value: 0,
|
||||
total: 0,
|
||||
};
|
||||
@ -109,14 +115,14 @@ impl ImageCompiler<'_> {
|
||||
);
|
||||
let resolved = downloader.resolve(image.clone()).await?;
|
||||
let cache_key = format!(
|
||||
"manifest={}:squashfs-version={}\n",
|
||||
resolved.digest, IMAGE_SQUASHFS_VERSION
|
||||
"manifest={}:version={}:format={}\n",
|
||||
resolved.digest,
|
||||
IMAGE_PACKER_VERSION,
|
||||
format.id(),
|
||||
);
|
||||
let cache_digest = sha256::digest(cache_key);
|
||||
|
||||
progress.phase = OciProgressPhase::Complete;
|
||||
self.progress.update(&progress);
|
||||
if let Some(cached) = self.cache.recall(&cache_digest).await? {
|
||||
if let Some(cached) = self.cache.recall(&cache_digest, format).await? {
|
||||
return Ok(cached);
|
||||
}
|
||||
|
||||
@ -132,7 +138,7 @@ impl ImageCompiler<'_> {
|
||||
"process layer digest={} compression={:?}",
|
||||
&layer.digest, layer.compression,
|
||||
);
|
||||
progress.extracting_layer(&layer.digest, 0, 0);
|
||||
progress.extracting_layer(&layer.digest, 0, 1);
|
||||
self.progress.update(&progress);
|
||||
let (whiteouts, count) = self.process_layer_whiteout(layer, image_dir).await?;
|
||||
progress.extracting_layer(&layer.digest, 0, count);
|
||||
@ -149,7 +155,9 @@ impl ImageCompiler<'_> {
|
||||
let path = entry.path()?;
|
||||
let mut maybe_whiteout_path_str =
|
||||
path.to_str().map(|x| x.to_string()).unwrap_or_default();
|
||||
progress.extracting_layer(&layer.digest, completed, count);
|
||||
if (completed % 10) == 0 {
|
||||
progress.extracting_layer(&layer.digest, completed, count);
|
||||
}
|
||||
completed += 1;
|
||||
self.progress.update(&progress);
|
||||
if whiteouts.contains(&maybe_whiteout_path_str) {
|
||||
@ -183,26 +191,28 @@ impl ImageCompiler<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
let image_dir_squash = image_dir.to_path_buf();
|
||||
let squash_file_squash = squash_file.to_path_buf();
|
||||
let progress_squash = progress.clone();
|
||||
let image_dir_pack = image_dir.to_path_buf();
|
||||
let packed_file_pack = packed_file.to_path_buf();
|
||||
let progress_pack = progress.clone();
|
||||
let progress_context = self.progress.clone();
|
||||
let format_pack = format;
|
||||
progress = tokio::task::spawn_blocking(move || {
|
||||
ImageCompiler::squash(
|
||||
&image_dir_squash,
|
||||
&squash_file_squash,
|
||||
progress_squash,
|
||||
OciImageCompiler::pack(
|
||||
format_pack,
|
||||
&image_dir_pack,
|
||||
&packed_file_pack,
|
||||
progress_pack,
|
||||
progress_context,
|
||||
)
|
||||
})
|
||||
.await??;
|
||||
|
||||
let info = ImageInfo::new(
|
||||
squash_file.to_path_buf(),
|
||||
packed_file.to_path_buf(),
|
||||
local.image.manifest,
|
||||
local.config,
|
||||
)?;
|
||||
let info = self.cache.store(&cache_digest, &info).await?;
|
||||
let info = self.cache.store(&cache_digest, &info, format).await?;
|
||||
progress.phase = OciProgressPhase::Complete;
|
||||
progress.value = 0;
|
||||
progress.total = 0;
|
||||
@ -359,128 +369,20 @@ impl ImageCompiler<'_> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn squash(
|
||||
fn pack(
|
||||
format: OciPackerFormat,
|
||||
image_dir: &Path,
|
||||
squash_file: &Path,
|
||||
packed_file: &Path,
|
||||
mut progress: OciProgress,
|
||||
progress_context: OciProgressContext,
|
||||
) -> Result<OciProgress> {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 2;
|
||||
progress.value = 0;
|
||||
progress_context.update(&progress);
|
||||
let mut writer = FilesystemWriter::default();
|
||||
writer.set_compressor(FilesystemCompressor::new(Compressor::Gzip, None)?);
|
||||
let walk = WalkDir::new(image_dir).follow_links(false);
|
||||
for entry in walk {
|
||||
let entry = entry?;
|
||||
let rel = entry
|
||||
.path()
|
||||
.strip_prefix(image_dir)?
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to strip prefix of tmpdir"))?;
|
||||
let rel = format!("/{}", rel);
|
||||
trace!("squash write {}", rel);
|
||||
let typ = entry.file_type();
|
||||
let metadata = std::fs::symlink_metadata(entry.path())?;
|
||||
let uid = metadata.uid();
|
||||
let gid = metadata.gid();
|
||||
let mode = metadata.permissions().mode();
|
||||
let mtime = metadata.mtime();
|
||||
|
||||
if rel == "/" {
|
||||
writer.set_root_uid(uid);
|
||||
writer.set_root_gid(gid);
|
||||
writer.set_root_mode(mode as u16);
|
||||
continue;
|
||||
}
|
||||
|
||||
let header = NodeHeader {
|
||||
permissions: mode as u16,
|
||||
uid,
|
||||
gid,
|
||||
mtime: mtime as u32,
|
||||
};
|
||||
if typ.is_symlink() {
|
||||
let symlink = std::fs::read_link(entry.path())?;
|
||||
let symlink = symlink
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to read symlink"))?;
|
||||
writer.push_symlink(symlink, rel, header)?;
|
||||
} else if typ.is_dir() {
|
||||
writer.push_dir(rel, header)?;
|
||||
} else if typ.is_file() {
|
||||
writer.push_file(ConsumingFileReader::new(entry.path()), rel, header)?;
|
||||
} else if typ.is_block_device() {
|
||||
let device = metadata.dev();
|
||||
writer.push_block_device(device as u32, rel, header)?;
|
||||
} else if typ.is_char_device() {
|
||||
let device = metadata.dev();
|
||||
writer.push_char_device(device as u32, rel, header)?;
|
||||
} else if typ.is_fifo() {
|
||||
writer.push_fifo(rel, header)?;
|
||||
} else if typ.is_socket() {
|
||||
writer.push_socket(rel, header)?;
|
||||
} else {
|
||||
return Err(anyhow!("invalid file type"));
|
||||
}
|
||||
}
|
||||
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.value = 1;
|
||||
progress_context.update(&progress);
|
||||
|
||||
let squash_file_path = squash_file
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to convert squashfs string"))?;
|
||||
|
||||
let file = File::create(squash_file)?;
|
||||
let mut bufwrite = BufWriter::new(file);
|
||||
trace!("squash generate: {}", squash_file_path);
|
||||
writer.write(&mut bufwrite)?;
|
||||
let backend = format.detect_best_backend();
|
||||
let backend = backend.create();
|
||||
backend.pack(&mut progress, &progress_context, image_dir, packed_file)?;
|
||||
std::fs::remove_dir_all(image_dir)?;
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.value = 2;
|
||||
progress.value = progress.total;
|
||||
progress_context.update(&progress);
|
||||
Ok(progress)
|
||||
}
|
||||
}
|
||||
|
||||
struct ConsumingFileReader {
|
||||
path: PathBuf,
|
||||
file: Option<File>,
|
||||
}
|
||||
|
||||
impl ConsumingFileReader {
|
||||
fn new(path: &Path) -> ConsumingFileReader {
|
||||
ConsumingFileReader {
|
||||
path: path.to_path_buf(),
|
||||
file: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for ConsumingFileReader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
if self.file.is_none() {
|
||||
self.file = Some(File::open(&self.path)?);
|
||||
}
|
||||
let Some(ref mut file) = self.file else {
|
||||
return Err(std::io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
"file was not opened",
|
||||
));
|
||||
};
|
||||
file.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ConsumingFileReader {
|
||||
fn drop(&mut self) {
|
||||
let file = self.file.take();
|
||||
drop(file);
|
||||
if let Err(error) = std::fs::remove_file(&self.path) {
|
||||
warn!("failed to delete consuming file {:?}: {}", self.path, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,6 @@ pub mod cache;
|
||||
pub mod compiler;
|
||||
pub mod fetch;
|
||||
pub mod name;
|
||||
pub mod packer;
|
||||
pub mod progress;
|
||||
pub mod registry;
|
||||
|
307
crates/oci/src/packer.rs
Normal file
307
crates/oci/src/packer.rs
Normal file
@ -0,0 +1,307 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, ErrorKind, Read},
|
||||
os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt},
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use backhand::{compression::Compressor, FilesystemCompressor, FilesystemWriter, NodeHeader};
|
||||
use log::{trace, warn};
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::progress::{OciProgress, OciProgressContext, OciProgressPhase};
|
||||
|
||||
#[derive(Debug, Default, Clone, Copy)]
|
||||
pub enum OciPackerFormat {
|
||||
#[default]
|
||||
Squashfs,
|
||||
Erofs,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum OciPackerBackendType {
|
||||
Backhand,
|
||||
MkSquashfs,
|
||||
MkfsErofs,
|
||||
}
|
||||
|
||||
impl OciPackerFormat {
|
||||
pub fn id(&self) -> u8 {
|
||||
match self {
|
||||
OciPackerFormat::Squashfs => 0,
|
||||
OciPackerFormat::Erofs => 1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extension(&self) -> &str {
|
||||
match self {
|
||||
OciPackerFormat::Squashfs => "erofs",
|
||||
OciPackerFormat::Erofs => "erofs",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn detect_best_backend(&self) -> OciPackerBackendType {
|
||||
match self {
|
||||
OciPackerFormat::Squashfs => {
|
||||
let status = Command::new("mksquashfs")
|
||||
.arg("-version")
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.status()
|
||||
.ok();
|
||||
|
||||
let Some(code) = status.and_then(|x| x.code()) else {
|
||||
return OciPackerBackendType::Backhand;
|
||||
};
|
||||
|
||||
if code == 0 {
|
||||
OciPackerBackendType::MkSquashfs
|
||||
} else {
|
||||
OciPackerBackendType::Backhand
|
||||
}
|
||||
}
|
||||
OciPackerFormat::Erofs => OciPackerBackendType::MkfsErofs,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl OciPackerBackendType {
|
||||
pub fn format(&self) -> OciPackerFormat {
|
||||
match self {
|
||||
OciPackerBackendType::Backhand => OciPackerFormat::Squashfs,
|
||||
OciPackerBackendType::MkSquashfs => OciPackerFormat::Squashfs,
|
||||
OciPackerBackendType::MkfsErofs => OciPackerFormat::Erofs,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create(&self) -> Box<dyn OciPackerBackend> {
|
||||
match self {
|
||||
OciPackerBackendType::Backhand => {
|
||||
Box::new(OciPackerBackhand {}) as Box<dyn OciPackerBackend>
|
||||
}
|
||||
OciPackerBackendType::MkSquashfs => {
|
||||
Box::new(OciPackerMkSquashfs {}) as Box<dyn OciPackerBackend>
|
||||
}
|
||||
OciPackerBackendType::MkfsErofs => {
|
||||
Box::new(OciPackerMkfsErofs {}) as Box<dyn OciPackerBackend>
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait OciPackerBackend {
|
||||
fn pack(
|
||||
&self,
|
||||
progress: &mut OciProgress,
|
||||
progress_context: &OciProgressContext,
|
||||
directory: &Path,
|
||||
file: &Path,
|
||||
) -> Result<()>;
|
||||
}
|
||||
|
||||
pub struct OciPackerBackhand {}
|
||||
|
||||
impl OciPackerBackend for OciPackerBackhand {
|
||||
fn pack(
|
||||
&self,
|
||||
progress: &mut OciProgress,
|
||||
progress_context: &OciProgressContext,
|
||||
directory: &Path,
|
||||
file: &Path,
|
||||
) -> Result<()> {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 1;
|
||||
progress.value = 0;
|
||||
progress_context.update(progress);
|
||||
let mut writer = FilesystemWriter::default();
|
||||
writer.set_compressor(FilesystemCompressor::new(Compressor::Gzip, None)?);
|
||||
let walk = WalkDir::new(directory).follow_links(false);
|
||||
for entry in walk {
|
||||
let entry = entry?;
|
||||
let rel = entry
|
||||
.path()
|
||||
.strip_prefix(directory)?
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to strip prefix of tmpdir"))?;
|
||||
let rel = format!("/{}", rel);
|
||||
trace!("squash write {}", rel);
|
||||
let typ = entry.file_type();
|
||||
let metadata = std::fs::symlink_metadata(entry.path())?;
|
||||
let uid = metadata.uid();
|
||||
let gid = metadata.gid();
|
||||
let mode = metadata.permissions().mode();
|
||||
let mtime = metadata.mtime();
|
||||
|
||||
if rel == "/" {
|
||||
writer.set_root_uid(uid);
|
||||
writer.set_root_gid(gid);
|
||||
writer.set_root_mode(mode as u16);
|
||||
continue;
|
||||
}
|
||||
|
||||
let header = NodeHeader {
|
||||
permissions: mode as u16,
|
||||
uid,
|
||||
gid,
|
||||
mtime: mtime as u32,
|
||||
};
|
||||
if typ.is_symlink() {
|
||||
let symlink = std::fs::read_link(entry.path())?;
|
||||
let symlink = symlink
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to read symlink"))?;
|
||||
writer.push_symlink(symlink, rel, header)?;
|
||||
} else if typ.is_dir() {
|
||||
writer.push_dir(rel, header)?;
|
||||
} else if typ.is_file() {
|
||||
writer.push_file(ConsumingFileReader::new(entry.path()), rel, header)?;
|
||||
} else if typ.is_block_device() {
|
||||
let device = metadata.dev();
|
||||
writer.push_block_device(device as u32, rel, header)?;
|
||||
} else if typ.is_char_device() {
|
||||
let device = metadata.dev();
|
||||
writer.push_char_device(device as u32, rel, header)?;
|
||||
} else if typ.is_fifo() {
|
||||
writer.push_fifo(rel, header)?;
|
||||
} else if typ.is_socket() {
|
||||
writer.push_socket(rel, header)?;
|
||||
} else {
|
||||
return Err(anyhow!("invalid file type"));
|
||||
}
|
||||
}
|
||||
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.value = 1;
|
||||
progress_context.update(progress);
|
||||
|
||||
let squash_file_path = file
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to convert squashfs string"))?;
|
||||
|
||||
let file = File::create(file)?;
|
||||
let mut bufwrite = BufWriter::new(file);
|
||||
trace!("squash generate: {}", squash_file_path);
|
||||
writer.write(&mut bufwrite)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
struct ConsumingFileReader {
|
||||
path: PathBuf,
|
||||
file: Option<File>,
|
||||
}
|
||||
|
||||
impl ConsumingFileReader {
|
||||
fn new(path: &Path) -> ConsumingFileReader {
|
||||
ConsumingFileReader {
|
||||
path: path.to_path_buf(),
|
||||
file: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Read for ConsumingFileReader {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
if self.file.is_none() {
|
||||
self.file = Some(File::open(&self.path)?);
|
||||
}
|
||||
let Some(ref mut file) = self.file else {
|
||||
return Err(std::io::Error::new(
|
||||
ErrorKind::NotFound,
|
||||
"file was not opened",
|
||||
));
|
||||
};
|
||||
file.read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for ConsumingFileReader {
|
||||
fn drop(&mut self) {
|
||||
let file = self.file.take();
|
||||
drop(file);
|
||||
if let Err(error) = std::fs::remove_file(&self.path) {
|
||||
warn!("failed to delete consuming file {:?}: {}", self.path, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OciPackerMkSquashfs {}
|
||||
|
||||
impl OciPackerBackend for OciPackerMkSquashfs {
|
||||
fn pack(
|
||||
&self,
|
||||
progress: &mut OciProgress,
|
||||
progress_context: &OciProgressContext,
|
||||
directory: &Path,
|
||||
file: &Path,
|
||||
) -> Result<()> {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 1;
|
||||
progress.value = 0;
|
||||
progress_context.update(progress);
|
||||
let mut child = Command::new("mksquashfs")
|
||||
.arg(directory)
|
||||
.arg(file)
|
||||
.arg("-comp")
|
||||
.arg("gzip")
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.spawn()?;
|
||||
let status = child.wait()?;
|
||||
if !status.success() {
|
||||
Err(anyhow!(
|
||||
"mksquashfs failed with exit code: {}",
|
||||
status.code().unwrap()
|
||||
))
|
||||
} else {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 1;
|
||||
progress.value = 1;
|
||||
progress_context.update(progress);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OciPackerMkfsErofs {}
|
||||
|
||||
impl OciPackerBackend for OciPackerMkfsErofs {
|
||||
fn pack(
|
||||
&self,
|
||||
progress: &mut OciProgress,
|
||||
progress_context: &OciProgressContext,
|
||||
directory: &Path,
|
||||
file: &Path,
|
||||
) -> Result<()> {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 1;
|
||||
progress.value = 0;
|
||||
progress_context.update(progress);
|
||||
let mut child = Command::new("mkfs.erofs")
|
||||
.arg("-L")
|
||||
.arg("root")
|
||||
.arg(file)
|
||||
.arg(directory)
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.spawn()?;
|
||||
let status = child.wait()?;
|
||||
if !status.success() {
|
||||
Err(anyhow!(
|
||||
"mkfs.erofs failed with exit code: {}",
|
||||
status.code().unwrap()
|
||||
))
|
||||
} else {
|
||||
progress.phase = OciProgressPhase::Packing;
|
||||
progress.total = 1;
|
||||
progress.value = 1;
|
||||
progress_context.update(progress);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,12 +1,11 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use indexmap::IndexMap;
|
||||
use tokio::sync::broadcast::Sender;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct OciProgress {
|
||||
pub id: String,
|
||||
pub phase: OciProgressPhase,
|
||||
pub layers: BTreeMap<String, OciProgressLayer>,
|
||||
pub layers: IndexMap<String, OciProgressLayer>,
|
||||
pub value: u64,
|
||||
pub total: u64,
|
||||
}
|
||||
|
@ -8,7 +8,9 @@ use anyhow::{anyhow, Result};
|
||||
use ipnetwork::{IpNetwork, Ipv4Network};
|
||||
use krata::launchcfg::{
|
||||
LaunchInfo, LaunchNetwork, LaunchNetworkIpv4, LaunchNetworkIpv6, LaunchNetworkResolver,
|
||||
LaunchPackedFormat, LaunchRoot,
|
||||
};
|
||||
use krataoci::packer::OciPackerFormat;
|
||||
use krataoci::progress::OciProgressContext;
|
||||
use tokio::sync::Semaphore;
|
||||
use uuid::Uuid;
|
||||
@ -19,13 +21,14 @@ use crate::cfgblk::ConfigBlock;
|
||||
use crate::RuntimeContext;
|
||||
use krataoci::{
|
||||
cache::ImageCache,
|
||||
compiler::{ImageCompiler, ImageInfo},
|
||||
compiler::{ImageInfo, OciImageCompiler},
|
||||
name::ImageName,
|
||||
};
|
||||
|
||||
use super::{GuestInfo, GuestState};
|
||||
|
||||
pub struct GuestLaunchRequest<'a> {
|
||||
pub format: LaunchPackedFormat,
|
||||
pub uuid: Option<Uuid>,
|
||||
pub name: Option<&'a str>,
|
||||
pub image: &'a str,
|
||||
@ -58,6 +61,10 @@ impl GuestLauncher {
|
||||
request.image,
|
||||
&context.image_cache,
|
||||
&context.oci_progress_context,
|
||||
match request.format {
|
||||
LaunchPackedFormat::Squashfs => OciPackerFormat::Squashfs,
|
||||
LaunchPackedFormat::Erofs => OciPackerFormat::Erofs,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
@ -77,6 +84,9 @@ impl GuestLauncher {
|
||||
let ipv6_network_mask: u32 = 10;
|
||||
|
||||
let launch_config = LaunchInfo {
|
||||
root: LaunchRoot {
|
||||
format: request.format.clone(),
|
||||
},
|
||||
hostname: Some(
|
||||
request
|
||||
.name
|
||||
@ -110,9 +120,9 @@ impl GuestLauncher {
|
||||
cfgblk.build(&launch_config)?;
|
||||
|
||||
let image_squashfs_path = image_info
|
||||
.image_squashfs
|
||||
.image
|
||||
.to_str()
|
||||
.ok_or_else(|| anyhow!("failed to convert image squashfs path to string"))?;
|
||||
.ok_or_else(|| anyhow!("failed to convert image path to string"))?;
|
||||
|
||||
let cfgblk_dir_path = cfgblk
|
||||
.dir
|
||||
@ -257,10 +267,11 @@ impl GuestLauncher {
|
||||
image: &str,
|
||||
image_cache: &ImageCache,
|
||||
progress: &OciProgressContext,
|
||||
format: OciPackerFormat,
|
||||
) -> Result<ImageInfo> {
|
||||
let image = ImageName::parse(image)?;
|
||||
let compiler = ImageCompiler::new(image_cache, None, progress.clone())?;
|
||||
compiler.compile(id, &image).await
|
||||
let compiler = OciImageCompiler::new(image_cache, None, progress.clone())?;
|
||||
compiler.compile(id, &image, format).await
|
||||
}
|
||||
|
||||
async fn allocate_ipv4(&self, context: &RuntimeContext) -> Result<Ipv4Addr> {
|
||||
|
2
hack/dist/apk.sh
vendored
2
hack/dist/apk.sh
vendored
@ -19,6 +19,8 @@ fpm -s tar -t apk \
|
||||
--license agpl3 \
|
||||
--version "${KRATA_VERSION}" \
|
||||
--architecture "${TARGET_ARCH}" \
|
||||
--depends "squashfs-tools" \
|
||||
--depends "erofs-utils" \
|
||||
--description "Krata Hypervisor" \
|
||||
--url "https://krata.dev" \
|
||||
--maintainer "Edera Team <contact@edera.dev>" \
|
||||
|
2
hack/dist/deb.sh
vendored
2
hack/dist/deb.sh
vendored
@ -20,6 +20,8 @@ fpm -s tar -t deb \
|
||||
--version "${KRATA_VERSION}" \
|
||||
--architecture "${TARGET_ARCH_DEBIAN}" \
|
||||
--depends "xen-system-${TARGET_ARCH_DEBIAN}" \
|
||||
--depends "squashfs-tools" \
|
||||
--depends "erofs-utils" \
|
||||
--description "Krata Hypervisor" \
|
||||
--url "https://krata.dev" \
|
||||
--maintainer "Edera Team <contact@edera.dev>" \
|
||||
|
@ -26,7 +26,7 @@ KERNEL_SRC="${KERNEL_DIR}/linux-${KERNEL_VERSION}-${TARGET_ARCH_STANDARD}"
|
||||
|
||||
if [ -z "${KRATA_KERNEL_BUILD_JOBS}" ]
|
||||
then
|
||||
KRATA_KERNEL_BUILD_JOBS="2"
|
||||
KRATA_KERNEL_BUILD_JOBS="$(nproc)"
|
||||
fi
|
||||
|
||||
if [ ! -f "${KERNEL_SRC}/Makefile" ]
|
||||
|
@ -1,6 +1,6 @@
|
||||
#
|
||||
# Automatically generated file; DO NOT EDIT.
|
||||
# Linux/x86_64 6.8.2 Kernel Configuration
|
||||
# Linux/x86 6.7.2 Kernel Configuration
|
||||
#
|
||||
CONFIG_CC_VERSION_TEXT="gcc (Debian 13.2.0-23) 13.2.0"
|
||||
CONFIG_CC_IS_GCC=y
|
||||
@ -15,7 +15,6 @@ CONFIG_CC_CAN_LINK=y
|
||||
CONFIG_CC_CAN_LINK_STATIC=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_OUTPUT=y
|
||||
CONFIG_CC_HAS_ASM_GOTO_TIED_OUTPUT=y
|
||||
CONFIG_GCC_ASM_GOTO_OUTPUT_WORKAROUND=y
|
||||
CONFIG_TOOLS_SUPPORT_RELR=y
|
||||
CONFIG_CC_HAS_ASM_INLINE=y
|
||||
CONFIG_CC_HAS_NO_PROFILE_FN_ATTR=y
|
||||
@ -188,10 +187,8 @@ CONFIG_ARCH_SUPPORTS_NUMA_BALANCING=y
|
||||
CONFIG_ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH=y
|
||||
CONFIG_CC_HAS_INT128=y
|
||||
CONFIG_CC_IMPLICIT_FALLTHROUGH="-Wimplicit-fallthrough=5"
|
||||
CONFIG_GCC10_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_GCC11_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_CC_NO_ARRAY_BOUNDS=y
|
||||
CONFIG_GCC_NO_STRINGOP_OVERFLOW=y
|
||||
CONFIG_CC_NO_STRINGOP_OVERFLOW=y
|
||||
CONFIG_ARCH_SUPPORTS_INT128=y
|
||||
CONFIG_CGROUPS=y
|
||||
CONFIG_PAGE_COUNTER=y
|
||||
@ -270,19 +267,19 @@ CONFIG_AIO=y
|
||||
CONFIG_IO_URING=y
|
||||
CONFIG_ADVISE_SYSCALLS=y
|
||||
CONFIG_MEMBARRIER=y
|
||||
CONFIG_KCMP=y
|
||||
CONFIG_RSEQ=y
|
||||
# CONFIG_DEBUG_RSEQ is not set
|
||||
CONFIG_CACHESTAT_SYSCALL=y
|
||||
# CONFIG_PC104 is not set
|
||||
CONFIG_KALLSYMS=y
|
||||
# CONFIG_KALLSYMS_SELFTEST is not set
|
||||
CONFIG_KALLSYMS_ALL=y
|
||||
CONFIG_KALLSYMS_ABSOLUTE_PERCPU=y
|
||||
CONFIG_KALLSYMS_BASE_RELATIVE=y
|
||||
CONFIG_ARCH_HAS_MEMBARRIER_SYNC_CORE=y
|
||||
CONFIG_KCMP=y
|
||||
CONFIG_RSEQ=y
|
||||
CONFIG_CACHESTAT_SYSCALL=y
|
||||
# CONFIG_DEBUG_RSEQ is not set
|
||||
CONFIG_HAVE_PERF_EVENTS=y
|
||||
CONFIG_GUEST_PERF_EVENTS=y
|
||||
# CONFIG_PC104 is not set
|
||||
|
||||
#
|
||||
# Kernel Performance Events And Counters
|
||||
@ -382,7 +379,6 @@ CONFIG_GENERIC_CPU=y
|
||||
CONFIG_X86_INTERNODE_CACHE_SHIFT=6
|
||||
CONFIG_X86_L1_CACHE_SHIFT=6
|
||||
CONFIG_X86_TSC=y
|
||||
CONFIG_X86_HAVE_PAE=y
|
||||
CONFIG_X86_CMPXCHG64=y
|
||||
CONFIG_X86_CMOV=y
|
||||
CONFIG_X86_MINIMUM_CPU_FAMILY=64
|
||||
@ -460,6 +456,7 @@ CONFIG_X86_INTEL_TSX_MODE_OFF=y
|
||||
# CONFIG_X86_INTEL_TSX_MODE_AUTO is not set
|
||||
# CONFIG_X86_SGX is not set
|
||||
# CONFIG_X86_USER_SHADOW_STACK is not set
|
||||
# CONFIG_INTEL_TDX_HOST is not set
|
||||
CONFIG_EFI=y
|
||||
CONFIG_EFI_STUB=y
|
||||
CONFIG_EFI_HANDOVER_PROTOCOL=y
|
||||
@ -522,7 +519,6 @@ CONFIG_CPU_IBRS_ENTRY=y
|
||||
CONFIG_CPU_SRSO=y
|
||||
# CONFIG_SLS is not set
|
||||
# CONFIG_GDS_FORCE_MITIGATION is not set
|
||||
CONFIG_MITIGATION_RFDS=y
|
||||
CONFIG_ARCH_HAS_ADD_PAGES=y
|
||||
|
||||
#
|
||||
@ -547,7 +543,6 @@ CONFIG_ACPI=y
|
||||
CONFIG_ACPI_LEGACY_TABLES_LOOKUP=y
|
||||
CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC=y
|
||||
CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT=y
|
||||
CONFIG_ACPI_THERMAL_LIB=y
|
||||
# CONFIG_ACPI_DEBUGGER is not set
|
||||
CONFIG_ACPI_SPCR_TABLE=y
|
||||
# CONFIG_ACPI_FPDT is not set
|
||||
@ -674,13 +669,14 @@ CONFIG_COMPAT_FOR_U64_ALIGNMENT=y
|
||||
# end of Binary Emulations
|
||||
|
||||
CONFIG_HAVE_KVM=y
|
||||
CONFIG_KVM_COMMON=y
|
||||
CONFIG_HAVE_KVM_PFNCACHE=y
|
||||
CONFIG_HAVE_KVM_IRQCHIP=y
|
||||
CONFIG_HAVE_KVM_IRQFD=y
|
||||
CONFIG_HAVE_KVM_IRQ_ROUTING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING_TSO=y
|
||||
CONFIG_HAVE_KVM_DIRTY_RING_ACQ_REL=y
|
||||
CONFIG_HAVE_KVM_EVENTFD=y
|
||||
CONFIG_KVM_MMIO=y
|
||||
CONFIG_KVM_ASYNC_PF=y
|
||||
CONFIG_HAVE_KVM_MSI=y
|
||||
@ -693,16 +689,13 @@ CONFIG_HAVE_KVM_NO_POLL=y
|
||||
CONFIG_KVM_XFER_TO_GUEST_WORK=y
|
||||
CONFIG_HAVE_KVM_PM_NOTIFIER=y
|
||||
CONFIG_KVM_GENERIC_HARDWARE_ENABLING=y
|
||||
CONFIG_KVM_GENERIC_MMU_NOTIFIER=y
|
||||
CONFIG_VIRTUALIZATION=y
|
||||
CONFIG_KVM=m
|
||||
CONFIG_KVM_WERROR=y
|
||||
# CONFIG_KVM_SW_PROTECTED_VM is not set
|
||||
CONFIG_KVM_INTEL=m
|
||||
CONFIG_KVM_AMD=m
|
||||
CONFIG_KVM_AMD_SEV=y
|
||||
CONFIG_KVM_SMM=y
|
||||
CONFIG_KVM_HYPERV=y
|
||||
# CONFIG_KVM_XEN is not set
|
||||
# CONFIG_KVM_PROVE_MMU is not set
|
||||
CONFIG_KVM_MAX_NR_VCPUS=1024
|
||||
@ -853,7 +846,6 @@ CONFIG_ARCH_SUPPORTS_PAGE_TABLE_CHECK=y
|
||||
CONFIG_ARCH_HAS_ELFCORE_COMPAT=y
|
||||
CONFIG_ARCH_HAS_PARANOID_L1D_FLUSH=y
|
||||
CONFIG_DYNAMIC_SIGFRAME=y
|
||||
CONFIG_ARCH_HAS_HW_PTE_YOUNG=y
|
||||
CONFIG_ARCH_HAS_NONLEAF_PMD_YOUNG=y
|
||||
|
||||
#
|
||||
@ -910,7 +902,6 @@ CONFIG_BLK_ICQ=y
|
||||
CONFIG_BLK_DEV_BSGLIB=y
|
||||
CONFIG_BLK_DEV_INTEGRITY=y
|
||||
CONFIG_BLK_DEV_INTEGRITY_T10=m
|
||||
CONFIG_BLK_DEV_WRITE_MOUNTED=y
|
||||
# CONFIG_BLK_DEV_ZONED is not set
|
||||
CONFIG_BLK_DEV_THROTTLING=y
|
||||
# CONFIG_BLK_DEV_THROTTLING_LOW is not set
|
||||
@ -1000,7 +991,6 @@ CONFIG_SWAP=y
|
||||
CONFIG_ZSWAP=y
|
||||
# CONFIG_ZSWAP_DEFAULT_ON is not set
|
||||
# CONFIG_ZSWAP_EXCLUSIVE_LOADS_DEFAULT_ON is not set
|
||||
# CONFIG_ZSWAP_SHRINKER_DEFAULT_ON is not set
|
||||
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_DEFLATE is not set
|
||||
CONFIG_ZSWAP_COMPRESSOR_DEFAULT_LZO=y
|
||||
# CONFIG_ZSWAP_COMPRESSOR_DEFAULT_842 is not set
|
||||
@ -1019,8 +1009,9 @@ CONFIG_ZSMALLOC=y
|
||||
CONFIG_ZSMALLOC_CHAIN_SIZE=8
|
||||
|
||||
#
|
||||
# Slab allocator options
|
||||
# SLAB allocator options
|
||||
#
|
||||
# CONFIG_SLAB_DEPRECATED is not set
|
||||
CONFIG_SLUB=y
|
||||
# CONFIG_SLUB_TINY is not set
|
||||
CONFIG_SLAB_MERGE_DEFAULT=y
|
||||
@ -1029,7 +1020,7 @@ CONFIG_SLAB_FREELIST_RANDOM=y
|
||||
# CONFIG_SLUB_STATS is not set
|
||||
CONFIG_SLUB_CPU_PARTIAL=y
|
||||
# CONFIG_RANDOM_KMALLOC_CACHES is not set
|
||||
# end of Slab allocator options
|
||||
# end of SLAB allocator options
|
||||
|
||||
# CONFIG_SHUFFLE_PAGE_ALLOCATOR is not set
|
||||
# CONFIG_COMPAT_BRK is not set
|
||||
@ -1071,7 +1062,6 @@ CONFIG_ARCH_WANTS_THP_SWAP=y
|
||||
CONFIG_TRANSPARENT_HUGEPAGE=y
|
||||
CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
|
||||
# CONFIG_TRANSPARENT_HUGEPAGE_MADVISE is not set
|
||||
# CONFIG_TRANSPARENT_HUGEPAGE_NEVER is not set
|
||||
CONFIG_THP_SWAP=y
|
||||
# CONFIG_READ_ONLY_THP_FOR_FS is not set
|
||||
CONFIG_NEED_PER_CPU_EMBED_FIRST_CHUNK=y
|
||||
@ -1102,7 +1092,6 @@ CONFIG_SECRETMEM=y
|
||||
CONFIG_LRU_GEN=y
|
||||
CONFIG_LRU_GEN_ENABLED=y
|
||||
# CONFIG_LRU_GEN_STATS is not set
|
||||
CONFIG_LRU_GEN_WALKS_MMU=y
|
||||
CONFIG_ARCH_SUPPORTS_PER_VMA_LOCK=y
|
||||
CONFIG_PER_VMA_LOCK=y
|
||||
CONFIG_LOCK_MM_AND_FIND_VMA=y
|
||||
@ -1600,6 +1589,7 @@ CONFIG_BRIDGE_EBT_REDIRECT=m
|
||||
CONFIG_BRIDGE_EBT_SNAT=m
|
||||
CONFIG_BRIDGE_EBT_LOG=m
|
||||
CONFIG_BRIDGE_EBT_NFLOG=m
|
||||
# CONFIG_BPFILTER is not set
|
||||
CONFIG_IP_DCCP=m
|
||||
CONFIG_INET_DCCP_DIAG=m
|
||||
|
||||
@ -1935,7 +1925,6 @@ CONFIG_ALLOW_DEV_COREDUMP=y
|
||||
# CONFIG_DEBUG_TEST_DRIVER_REMOVE is not set
|
||||
# CONFIG_TEST_ASYNC_DRIVER_PROBE is not set
|
||||
CONFIG_SYS_HYPERVISOR=y
|
||||
CONFIG_GENERIC_CPU_DEVICES=y
|
||||
CONFIG_GENERIC_CPU_AUTOPROBE=y
|
||||
CONFIG_GENERIC_CPU_VULNERABILITIES=y
|
||||
CONFIG_REGMAP=y
|
||||
@ -2040,7 +2029,6 @@ CONFIG_ZRAM_DEF_COMP_LZ4=y
|
||||
# CONFIG_ZRAM_DEF_COMP_LZ4HC is not set
|
||||
CONFIG_ZRAM_DEF_COMP="lz4"
|
||||
# CONFIG_ZRAM_WRITEBACK is not set
|
||||
# CONFIG_ZRAM_TRACK_ENTRY_ACTIME is not set
|
||||
# CONFIG_ZRAM_MEMORY_TRACKING is not set
|
||||
# CONFIG_ZRAM_MULTI_COMP is not set
|
||||
CONFIG_BLK_DEV_LOOP=m
|
||||
@ -2101,7 +2089,6 @@ CONFIG_VMWARE_BALLOON=m
|
||||
# CONFIG_DW_XDATA_PCIE is not set
|
||||
# CONFIG_PCI_ENDPOINT_TEST is not set
|
||||
# CONFIG_XILINX_SDFEC is not set
|
||||
# CONFIG_NSM is not set
|
||||
# CONFIG_C2PORT is not set
|
||||
|
||||
#
|
||||
@ -2128,6 +2115,8 @@ CONFIG_VMWARE_BALLOON=m
|
||||
#
|
||||
# CONFIG_ALTERA_STAPL is not set
|
||||
# CONFIG_INTEL_MEI is not set
|
||||
# CONFIG_INTEL_MEI_ME is not set
|
||||
# CONFIG_INTEL_MEI_TXE is not set
|
||||
CONFIG_VMWARE_VMCI=m
|
||||
# CONFIG_GENWQE is not set
|
||||
# CONFIG_ECHO is not set
|
||||
@ -2341,10 +2330,13 @@ CONFIG_MD=y
|
||||
CONFIG_BLK_DEV_MD=y
|
||||
# CONFIG_MD_AUTODETECT is not set
|
||||
CONFIG_MD_BITMAP_FILE=y
|
||||
# CONFIG_MD_LINEAR is not set
|
||||
CONFIG_MD_RAID0=m
|
||||
CONFIG_MD_RAID1=m
|
||||
CONFIG_MD_RAID10=m
|
||||
CONFIG_MD_RAID456=m
|
||||
# CONFIG_MD_MULTIPATH is not set
|
||||
# CONFIG_MD_FAULTY is not set
|
||||
# CONFIG_MD_CLUSTER is not set
|
||||
CONFIG_BCACHE=m
|
||||
# CONFIG_BCACHE_DEBUG is not set
|
||||
@ -2564,6 +2556,7 @@ CONFIG_NET_VENDOR_WANGXUN=y
|
||||
# CONFIG_NET_VENDOR_WIZNET is not set
|
||||
CONFIG_NET_VENDOR_XILINX=y
|
||||
# CONFIG_XILINX_EMACLITE is not set
|
||||
# CONFIG_XILINX_AXI_EMAC is not set
|
||||
# CONFIG_XILINX_LL_TEMAC is not set
|
||||
# CONFIG_FDDI is not set
|
||||
# CONFIG_HIPPI is not set
|
||||
@ -2622,7 +2615,6 @@ CONFIG_FIXED_PHY=m
|
||||
# CONFIG_DP83867_PHY is not set
|
||||
# CONFIG_DP83869_PHY is not set
|
||||
# CONFIG_DP83TD510_PHY is not set
|
||||
# CONFIG_DP83TG720_PHY is not set
|
||||
# CONFIG_VITESSE_PHY is not set
|
||||
# CONFIG_XILINX_GMII2RGMII is not set
|
||||
# CONFIG_PSE_CONTROLLER is not set
|
||||
@ -3081,13 +3073,13 @@ CONFIG_HWMON=m
|
||||
# CONFIG_SENSORS_DRIVETEMP is not set
|
||||
# CONFIG_SENSORS_DS620 is not set
|
||||
# CONFIG_SENSORS_DS1621 is not set
|
||||
# CONFIG_SENSORS_DELL_SMM is not set
|
||||
# CONFIG_SENSORS_I5K_AMB is not set
|
||||
# CONFIG_SENSORS_F71805F is not set
|
||||
# CONFIG_SENSORS_F71882FG is not set
|
||||
# CONFIG_SENSORS_F75375S is not set
|
||||
# CONFIG_SENSORS_FSCHMD is not set
|
||||
# CONFIG_SENSORS_FTSTEUTATES is not set
|
||||
# CONFIG_SENSORS_GIGABYTE_WATERFORCE is not set
|
||||
# CONFIG_SENSORS_GL518SM is not set
|
||||
# CONFIG_SENSORS_GL520SM is not set
|
||||
# CONFIG_SENSORS_G760A is not set
|
||||
@ -3219,7 +3211,6 @@ CONFIG_SENSORS_ACPI_POWER=m
|
||||
CONFIG_THERMAL=y
|
||||
# CONFIG_THERMAL_NETLINK is not set
|
||||
# CONFIG_THERMAL_STATISTICS is not set
|
||||
# CONFIG_THERMAL_DEBUGFS is not set
|
||||
CONFIG_THERMAL_EMERGENCY_POWEROFF_DELAY_MS=0
|
||||
# CONFIG_THERMAL_WRITABLE_TRIPS is not set
|
||||
CONFIG_THERMAL_DEFAULT_GOV_STEP_WISE=y
|
||||
@ -3369,6 +3360,7 @@ CONFIG_BCMA_POSSIBLE=y
|
||||
# CONFIG_MFD_SM501 is not set
|
||||
# CONFIG_MFD_SKY81452 is not set
|
||||
# CONFIG_MFD_SYSCON is not set
|
||||
# CONFIG_MFD_TI_AM335X_TSCADC is not set
|
||||
# CONFIG_MFD_LP3943 is not set
|
||||
# CONFIG_MFD_TI_LMU is not set
|
||||
# CONFIG_TPS6105X is not set
|
||||
@ -3436,7 +3428,6 @@ CONFIG_DRM_GEM_SHMEM_HELPER=m
|
||||
# CONFIG_DRM_AMDGPU is not set
|
||||
# CONFIG_DRM_NOUVEAU is not set
|
||||
# CONFIG_DRM_I915 is not set
|
||||
# CONFIG_DRM_XE is not set
|
||||
# CONFIG_DRM_VGEM is not set
|
||||
# CONFIG_DRM_VKMS is not set
|
||||
CONFIG_DRM_VMWGFX=m
|
||||
@ -3464,6 +3455,7 @@ CONFIG_DRM_PANEL_BRIDGE=y
|
||||
# CONFIG_DRM_ANALOGIX_ANX78XX is not set
|
||||
# end of Display Interface Bridges
|
||||
|
||||
# CONFIG_DRM_LOONGSON is not set
|
||||
# CONFIG_DRM_ETNAVIV is not set
|
||||
CONFIG_DRM_BOCHS=m
|
||||
CONFIG_DRM_CIRRUS_QEMU=m
|
||||
@ -3475,6 +3467,7 @@ CONFIG_DRM_VBOXVIDEO=m
|
||||
# CONFIG_DRM_GUD is not set
|
||||
# CONFIG_DRM_SSD130X is not set
|
||||
CONFIG_DRM_HYPERV=m
|
||||
# CONFIG_DRM_LEGACY is not set
|
||||
CONFIG_DRM_PANEL_ORIENTATION_QUIRKS=m
|
||||
|
||||
#
|
||||
@ -3494,6 +3487,7 @@ CONFIG_FB=m
|
||||
# CONFIG_FB_NVIDIA is not set
|
||||
# CONFIG_FB_RIVA is not set
|
||||
# CONFIG_FB_I740 is not set
|
||||
# CONFIG_FB_LE80578 is not set
|
||||
# CONFIG_FB_MATROX is not set
|
||||
# CONFIG_FB_RADEON is not set
|
||||
# CONFIG_FB_ATY128 is not set
|
||||
@ -3528,8 +3522,9 @@ CONFIG_FB_SYS_FILLRECT=m
|
||||
CONFIG_FB_SYS_COPYAREA=m
|
||||
CONFIG_FB_SYS_IMAGEBLIT=m
|
||||
# CONFIG_FB_FOREIGN_ENDIAN is not set
|
||||
CONFIG_FB_SYSMEM_FOPS=m
|
||||
CONFIG_FB_SYS_FOPS=m
|
||||
CONFIG_FB_DEFERRED_IO=y
|
||||
CONFIG_FB_IOMEM_FOPS=m
|
||||
CONFIG_FB_SYSMEM_HELPERS=y
|
||||
CONFIG_FB_SYSMEM_HELPERS_DEFERRED=y
|
||||
# CONFIG_FB_MODE_HELPERS is not set
|
||||
@ -4132,7 +4127,6 @@ CONFIG_VIRTIO_PCI_LIB=y
|
||||
CONFIG_VIRTIO_PCI_LIB_LEGACY=y
|
||||
CONFIG_VIRTIO_MENU=y
|
||||
CONFIG_VIRTIO_PCI=y
|
||||
CONFIG_VIRTIO_PCI_ADMIN_LEGACY=y
|
||||
CONFIG_VIRTIO_PCI_LEGACY=y
|
||||
CONFIG_VIRTIO_VDPA=m
|
||||
# CONFIG_VIRTIO_PMEM is not set
|
||||
@ -4312,7 +4306,6 @@ CONFIG_RPMSG_VIRTIO=m
|
||||
#
|
||||
# Qualcomm SoC drivers
|
||||
#
|
||||
# CONFIG_QCOM_PMIC_PDCHARGER_ULOG is not set
|
||||
# end of Qualcomm SoC drivers
|
||||
|
||||
# CONFIG_SOC_TI is not set
|
||||
@ -4387,7 +4380,6 @@ CONFIG_MEMORY=y
|
||||
#
|
||||
# Performance monitor support
|
||||
#
|
||||
# CONFIG_DWC_PCIE_PMU is not set
|
||||
# end of Performance monitor support
|
||||
|
||||
# CONFIG_RAS is not set
|
||||
@ -4408,7 +4400,14 @@ CONFIG_DAX=y
|
||||
# CONFIG_DEV_DAX is not set
|
||||
CONFIG_NVMEM=y
|
||||
CONFIG_NVMEM_SYSFS=y
|
||||
# CONFIG_NVMEM_LAYOUTS is not set
|
||||
|
||||
#
|
||||
# Layout Types
|
||||
#
|
||||
# CONFIG_NVMEM_LAYOUT_SL28_VPD is not set
|
||||
# CONFIG_NVMEM_LAYOUT_ONIE_TLV is not set
|
||||
# end of Layout Types
|
||||
|
||||
# CONFIG_NVMEM_RMEM is not set
|
||||
|
||||
#
|
||||
@ -4435,7 +4434,6 @@ CONFIG_NVMEM_SYSFS=y
|
||||
CONFIG_DCACHE_WORD_ACCESS=y
|
||||
# CONFIG_VALIDATE_FS_PARSER is not set
|
||||
CONFIG_FS_IOMAP=y
|
||||
CONFIG_FS_STACK=y
|
||||
CONFIG_BUFFER_HEAD=y
|
||||
CONFIG_LEGACY_DIRECT_IO=y
|
||||
CONFIG_EXT2_FS=m
|
||||
@ -4527,7 +4525,7 @@ CONFIG_QFMT_V1=m
|
||||
CONFIG_QFMT_V2=m
|
||||
CONFIG_QUOTACTL=y
|
||||
CONFIG_AUTOFS_FS=m
|
||||
CONFIG_FUSE_FS=m
|
||||
CONFIG_FUSE_FS=y
|
||||
# CONFIG_CUSE is not set
|
||||
CONFIG_VIRTIO_FS=m
|
||||
CONFIG_OVERLAY_FS=y
|
||||
@ -4598,9 +4596,9 @@ CONFIG_TMPFS_XATTR=y
|
||||
CONFIG_TMPFS_INODE64=y
|
||||
# CONFIG_TMPFS_QUOTA is not set
|
||||
CONFIG_HUGETLBFS=y
|
||||
# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
|
||||
CONFIG_HUGETLB_PAGE=y
|
||||
CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP=y
|
||||
# CONFIG_HUGETLB_PAGE_OPTIMIZE_VMEMMAP_DEFAULT_ON is not set
|
||||
CONFIG_ARCH_HAS_GIGANTIC_PAGE=y
|
||||
CONFIG_CONFIGFS_FS=y
|
||||
CONFIG_EFIVAR_FS=y
|
||||
@ -4656,7 +4654,16 @@ CONFIG_SYSV_FS=m
|
||||
CONFIG_UFS_FS=m
|
||||
# CONFIG_UFS_FS_WRITE is not set
|
||||
# CONFIG_UFS_DEBUG is not set
|
||||
# CONFIG_EROFS_FS is not set
|
||||
CONFIG_EROFS_FS=y
|
||||
# CONFIG_EROFS_FS_DEBUG is not set
|
||||
CONFIG_EROFS_FS_XATTR=y
|
||||
CONFIG_EROFS_FS_POSIX_ACL=y
|
||||
CONFIG_EROFS_FS_SECURITY=y
|
||||
CONFIG_EROFS_FS_ZIP=y
|
||||
CONFIG_EROFS_FS_ZIP_LZMA=y
|
||||
CONFIG_EROFS_FS_ZIP_DEFLATE=y
|
||||
CONFIG_EROFS_FS_PCPU_KTHREAD=y
|
||||
CONFIG_EROFS_FS_PCPU_KTHREAD_HIPRI=y
|
||||
CONFIG_VBOXSF_FS=m
|
||||
CONFIG_NETWORK_FILESYSTEMS=y
|
||||
CONFIG_NFS_FS=m
|
||||
@ -4688,7 +4695,6 @@ CONFIG_NFSD_SCSILAYOUT=y
|
||||
CONFIG_NFSD_FLEXFILELAYOUT=y
|
||||
# CONFIG_NFSD_V4_2_INTER_SSC is not set
|
||||
# CONFIG_NFSD_V4_SECURITY_LABEL is not set
|
||||
# CONFIG_NFSD_LEGACY_CLIENT_TRACKING is not set
|
||||
CONFIG_GRACE_PERIOD=m
|
||||
CONFIG_LOCKD=m
|
||||
CONFIG_LOCKD_V4=y
|
||||
@ -4948,12 +4954,14 @@ CONFIG_CRYPTO_TWOFISH_COMMON=m
|
||||
CONFIG_CRYPTO_ADIANTUM=m
|
||||
CONFIG_CRYPTO_CHACHA20=m
|
||||
CONFIG_CRYPTO_CBC=y
|
||||
# CONFIG_CRYPTO_CFB is not set
|
||||
CONFIG_CRYPTO_CTR=m
|
||||
CONFIG_CRYPTO_CTS=y
|
||||
CONFIG_CRYPTO_ECB=y
|
||||
CONFIG_CRYPTO_HCTR2=m
|
||||
CONFIG_CRYPTO_KEYWRAP=m
|
||||
CONFIG_CRYPTO_LRW=m
|
||||
# CONFIG_CRYPTO_OFB is not set
|
||||
CONFIG_CRYPTO_PCBC=m
|
||||
CONFIG_CRYPTO_XCTR=m
|
||||
CONFIG_CRYPTO_XTS=y
|
||||
@ -5002,7 +5010,7 @@ CONFIG_CRYPTO_XXHASH=m
|
||||
#
|
||||
# CRCs (cyclic redundancy checks)
|
||||
#
|
||||
CONFIG_CRYPTO_CRC32C=m
|
||||
CONFIG_CRYPTO_CRC32C=y
|
||||
CONFIG_CRYPTO_CRC32=m
|
||||
CONFIG_CRYPTO_CRCT10DIF=y
|
||||
CONFIG_CRYPTO_CRC64_ROCKSOFT=m
|
||||
@ -5108,7 +5116,6 @@ CONFIG_CRYPTO_DEV_QAT=m
|
||||
# CONFIG_CRYPTO_DEV_QAT_C3XXX is not set
|
||||
# CONFIG_CRYPTO_DEV_QAT_C62X is not set
|
||||
CONFIG_CRYPTO_DEV_QAT_4XXX=m
|
||||
# CONFIG_CRYPTO_DEV_QAT_420XX is not set
|
||||
CONFIG_CRYPTO_DEV_QAT_DH895xCCVF=m
|
||||
# CONFIG_CRYPTO_DEV_QAT_C3XXXVF is not set
|
||||
# CONFIG_CRYPTO_DEV_QAT_C62XVF is not set
|
||||
@ -5196,7 +5203,7 @@ CONFIG_CRC32_SLICEBY8=y
|
||||
CONFIG_CRC64=m
|
||||
# CONFIG_CRC4 is not set
|
||||
CONFIG_CRC7=m
|
||||
CONFIG_LIBCRC32C=m
|
||||
CONFIG_LIBCRC32C=y
|
||||
CONFIG_CRC8=m
|
||||
CONFIG_XXHASH=y
|
||||
# CONFIG_RANDOM32_SELFTEST is not set
|
||||
@ -5216,7 +5223,7 @@ CONFIG_XZ_DEC_POWERPC=y
|
||||
CONFIG_XZ_DEC_ARM=y
|
||||
CONFIG_XZ_DEC_ARMTHUMB=y
|
||||
CONFIG_XZ_DEC_SPARC=y
|
||||
# CONFIG_XZ_DEC_MICROLZMA is not set
|
||||
CONFIG_XZ_DEC_MICROLZMA=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
# CONFIG_XZ_DEC_TEST is not set
|
||||
CONFIG_DECOMPRESS_GZIP=y
|
||||
@ -5312,7 +5319,7 @@ CONFIG_DEBUG_MISC=y
|
||||
# Compile-time checks and compiler options
|
||||
#
|
||||
CONFIG_DEBUG_INFO=y
|
||||
CONFIG_AS_HAS_NON_CONST_ULEB128=y
|
||||
CONFIG_AS_HAS_NON_CONST_LEB128=y
|
||||
# CONFIG_DEBUG_INFO_NONE is not set
|
||||
# CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT is not set
|
||||
# CONFIG_DEBUG_INFO_DWARF4 is not set
|
||||
|
Loading…
Reference in New Issue
Block a user