## Compress the initramfs with zstd by default on Fedora
Use `zstd` to compress the initramfs for all Fedora variants by default when built with `dracut`.
For more information about the change, see https://fedoraproject.org/wiki/Changes/InitrdZstdDefault.
I have tested the commands available below for `initramfs-6.15.4-200.fc42.x86_64.img` on several platforms.
For the Zstandard compression algorithm, the commands executed to compress images are:
```bash=
sudo dracut --force --regenerate-all --parallel "--compress=zstd -3 --threads=0"
sudo dracut --force --regenerate-all --parallel "--compress=zstd -5 --threads=0"
sudo dracut --force --regenerate-all --parallel "--compress=zstd -10 --threads=0"
sudo dracut --force --regenerate-all --parallel "--compress=zstd -15 --threads=0"
sudo dracut --force --regenerate-all --parallel "--compress=zstd -19 --threads=0"
```
For the Gzip compression algorithm, the command executed to decompress the image is:
`gzip --decompress --stdout > /dev/null initramfs-6.15.4-200.fc42.x86_64.img`
For the Zstandard compression algorithm, the command executed to decompress the images is:
`unzstd --stdout > /dev/null initramfs-6.15.4-200.fc42.x86_64.img`
**Note:** The times listed in the "Mean [ms]", "Min. [ms]", and "Max. [ms]" columns in the following tables are for decompression.
### Fedora Cloud 42 on QEMU/KVM VM with 2 vCPUs and 4 GB RAM
| Size [MiB] | Tool | Algorithm | Level | Mean [ms] | Min [ms] | Max [ms] |
|:--- |:--- |:--- |:--- |---: |---: |---: |
| 48 |`gzip`| Gzip | 9 |467.8 ± 1.5| 465.8 | 471.3 |
| 47 |`zstd`| Zstandard | 3 |60.4 ± 1.2 | 58.8 | 67.1 |
| 46 |`zstd`| Zstandard | 5 |62.9 ± 1.7 | 60.6 | 69.3 |
| 45 |`zstd`| Zstandard | 10 |62.2 ± 1.4 | 60.2 | 67.3 |
| 45 |`zstd`| Zstandard | 15 |61.8 ± 1.2 | 59.5 | 66.1 |
| 43 |`zstd`| Zstandard | 19 |78.3 ± 1.2 | 76.8 | 82.8 |
### Fedora KDE 42 on bare metal machine with Intel Pentium CPU G4560 and 12 GB RAM
| Size [MiB] | Tool | Algorithm | Level | Mean [ms] | Min [ms] | Max [ms] |
|:--- |:--- |:--- |:--- |---: |---: |---: |
| 75 |`gzip`| Gzip | 9 |807.1 ± 2.0| 805.7 | 812.0 |
| 75 |`zstd`| Zstandard | 3 |134.6 ± 3.0| 131.0 | 141.4 |
| 74 |`zstd`| Zstandard | 5 |141.2 ± 2.2| 136.9 | 143.6 |
| 73 |`zstd`| Zstandard | 10 |146.8 ± 1.6| 144.4 | 148.9 |
| 73 |`zstd`| Zstandard | 15 |148.1 ± 2.7| 145.0 | 155.1 |
| 71 |`zstd`| Zstandard | 19 |177.0 ± 1.9| 174.1 | 179.5 |
---
### Testing initramfs with zstd on Fedora Atomic Desktops
**Note:** Fedora Atomic Desktops bootable container images are still considered experimental. It is recommended to use a discarded or virtual machine.
Install Fedora Kinoite and create the directory `~/initrd_with_zstd_by_default` and in it a `Containerfile` with the following content:
```=
FROM quay.io/fedora-ostree-desktops/kinoite:42
RUN <<EORUN
set -xeuo pipefail
dnf --assumeyes --refresh install zstd
kver=$(ls /usr/lib/modules)
stock_arguments=$(lsinitrd "/lib/modules/${kver}/initramfs.img" |\
grep --extended-regexp '^Arguments: ' |\
sed 's/^Arguments: //')
mkdir --parents /tmp/dracut /var/roothome
bash <(/usr/bin/echo "dracut ${stock_arguments}")
mv --verbose /boot/initramfs*.img "/lib/modules/${kver}/initramfs.img"
dnf clean all
rm --recursive --force /var/* /tmp/*
bootc container lint --no-truncate
EORUN
```
Build a bootable container image:
`sudo podman image build --tag localhost/fedora-kinoite:42-initramfs-zstd --file ~/initrd_with_zstd_by_default/Containerfile`
Switch to the built container image and reboot the system:
`sudo bootc switch --apply --transport containers-storage localhost/fedora-kinoite:42-initramfs-zstd`
---
### Testing initramfs with zstd on Fedora Cloud
I modified [fedora-kiwi-descriptions](https://pagure.io/fedora-kiwi-descriptions) for the `Cloud-Base-Generic` image profile to include a local repository containing the RPMs from the x86_64 build of the [Draft: Add require on zstd to use it for initrd compression](https://src.fedoraproject.org/rpms/dracut/pull-request/85) PR, and the file `initramfs-compression-test.py`, the contents of which are at the bottom of this page.
---
### Testing initramfs with zstd on Fedora IoT
When I build a container image from the following Containerfile and a qcow2 image from it, the initramfs in the virtual machine is compressed using Zstandard. The `dracut-rpms` directory contains the x86_64 build of the [Draft: Add require on zstd to use it for initrd compression](https://src.fedoraproject.org/rpms/dracut/pull-request/85) PR, and the contents of `initramfs-compression-test.py` are at the bottom of this page.
```=
FROM quay.io/fedora/fedora-iot:rawhide
COPY initramfs-compression-test.py /usr/libexec/
COPY dracut-rpms /tmp/dracut-rpms
RUN <<EORUN
set -xeuo pipefail
export DRACUT_NO_XATTR=1
dnf --assumeyes reinstall --allowerasing /tmp/dracut-rpms/dracut*
kver=$(ls /usr/lib/modules)
stock_arguments=$(lsinitrd "/lib/modules/${kver}/initramfs.img" |\
grep --extended-regexp '^Arguments: ' |\
sed 's/^Arguments: //')
mkdir --parents /tmp/dracut /var/roothome
bash <(/usr/bin/echo "dracut ${stock_arguments}")
mv --verbose /boot/initramfs*.img "/lib/modules/${kver}/initramfs.img"
dnf clean all
rm --recursive --force /var/* /tmp/* /boot/*
bootc container lint --no-truncate
EORUN
```
---
The following Python script aims to simplify and automate to some extent the testing of initramfs compression on Fedora Linux.
```python=
#! /usr/bin/env python3
import os
from pathlib import Path
import re
import subprocess
def main():
if os.getuid() != 0:
raise SystemExit(f"\n Root access is required to test initramfs compression.\n")
determine_initramfs_compression()
def get_initramfs_paths():
initramfs_paths = []
ostree_booted = Path("/run/ostree-booted")
if ostree_booted.exists():
print(f"\n Fedora Linux operates in image mode.\n")
entries_dir = Path("/boot/loader/entries")
for entry in entries_dir.iterdir():
ostree_conf = entry.read_text()
initrd_re_compile = re.compile(r"^initrd\b.+\.img.*", re.MULTILINE)
initrd_line = re.search(initrd_re_compile, ostree_conf)
initramfs_path_image_mode = ostree_conf[initrd_line.start():initrd_line.end():].replace("initrd ", "/boot")
initramfs_paths.append(initramfs_path_image_mode)
else:
print(f"\n Fedora Linux operates in package mode.\n")
initramfs_paths_package_mode = list(Path("/boot").glob("initramfs*"))
for initramfs_path in initramfs_paths_package_mode:
initramfs_paths.append(str(initramfs_path))
return initramfs_paths
def determine_initramfs_compression():
FILE_SIGNATURES = {
"Gzip": r"\x1f\x8b\x08",
"XZ": r"\xfd\x37\x7a\x58\x5a\x00",
"Zstandard": r"\x28\xb5\x2f\xfd",
}
for initramfs_path in get_initramfs_paths():
extract_initramfs = subprocess.run(
["/usr/lib/dracut/skipcpio",
initramfs_path],
capture_output=True, check=True)
for compression, file_signature in FILE_SIGNATURES.items():
if re.search(bytes(file_signature, encoding="UTF-8"), extract_initramfs.stdout[:8]):
print(f" Initramfs: {Path(initramfs_path)}")
print(f" Compression: {compression}\n")
if __name__ == "__main__":
raise SystemExit(main())
```