Running Linux from RAM
Base installation
This guide assumes a base Linux installation similar to the one described in https://barn.bigstool.com/post/arch-linux-installation-guide/ on a hard drive, but with several important distinctions outlined below.
The partition layout is as follows:
+-----------------------+------------------------+
| EFI system partition | Linux root partition |
| | |
| | |
| /efi | / |
| | |
| | |
| | |
| /dev/sdx1 | /dev/sdx2 |
+-----------------------+------------------------+
Due to the additional unified kernel image for the Linux form RAM option, alongside with the existing UKI for booting the system normally from the hard drive, the EFI system partition can be reasonably larger (e.g., 2G).
There will be no LUKS encryption.
The filesystem for the Linux root partition will be ext4 instead of Btrfs, created with:
mkfs.ext4 /dev/sdx2
The following HOOKS will be used in /etc/mkinitcpio.conf instead (without sd-encrypt):
HOOKS=(base systemd autodetect microcode modconf kms keyboard sd-vconsole block filesystems fsck)
Any LUKS or Btrfs-related flags will be removed from /etc/kernel/cmdline.
Since the root filesystem is not encrypted, it makes little sense to configure secure boot, as the keys generated for secure boot are not protected by encryption and can be directly accessed. Similarly, TPM will not be configured.
Snapper and Btrfs Assistant rely on the Btrfs filesystem, hence will not be configured.
Configuration
mkinitcpio hook
Create the hook:
sudo nano /etc/initcpio/install/copytoram
With the following content:
#!/bin/bash
build() {
add_binary "/usr/bin/bash"
add_binary "/usr/bin/cp"
add_binary "/usr/bin/mount"
add_binary "/usr/bin/umount"
add_file "/etc/initcpio/copytoram.sh" "/usr/lib/initcpio/copytoram.sh" 755
add_file "/etc/initcpio/copytoram.service" "/usr/lib/systemd/system/copytoram.service" 644
add_symlink "/usr/lib/systemd/system/initrd-fs.target.requires/copytoram.service" \
"/usr/lib/systemd/system/copytoram.service"
}
help() {
cat <<HELPEOF
copytoram
---------
Copies the root filesystem into a tmpfs before switch_root, so the system
boots and runs entirely from RAM. Only activates when "rd.copytoram" is
present on the kernel command line; otherwise it's a no-op.
Optional kernel parameter:
rd.copytoram.size=SIZE tmpfs size cap, e.g. "8G" or "75%" (default 90%)
HELPEOF
}
Copy to RAM script
Create the script:
sudo nano /etc/initcpio/copytoram.sh
With the following content:
#!/usr/bin/env bash
set -e
# systemd marks the initrd's root as a shared mount, and the kernel refuses
# to "mount --move" anything under a shared mount. Detach from propagation
# so the move below is allowed.
mount --make-rprivate /
SIZE="90%"
for arg in $(cat /proc/cmdline); do
case "$arg" in
rd.copytoram.size=*)
SIZE="${arg#rd.copytoram.size=}"
;;
esac
done
echo "copytoram: mounting tmpfs (size=${SIZE})"
mkdir -p /run/rootram
mount -t tmpfs -o "size=${SIZE},mode=0755" tmpfs /run/rootram
echo "copytoram: copying root filesystem to RAM, please wait..."
cp -a -x /sysroot/. /run/rootram/
echo "copytoram: swapping in RAM copy"
umount /sysroot
mount --move /run/rootram /sysroot
echo "copytoram: done"
systemd unit
Create the unit:
sudo nano /etc/initcpio/copytoram.service
With the following content:
[Unit]
Description=Copy root filesystem to tmpfs (RAM)
DefaultDependencies=no
After=sysroot.mount
Before=initrd-fs.target
ConditionKernelCommandLine=rd.copytoram
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/lib/initcpio/copytoram.sh
StandardOutput=journal+console
[Install]
RequiredBy=initrd-fs.target
Here, ConditionKernelCommandLine=rd.copytoram specifies that the system will only be loaded to RAM if the rd.copytoram flag is set in kernel parameters.
Enable the hook
Edit the mkinitcpio configurations:
sudo nano /etc/mkinitcpio.conf
Add the copytoram hook right after systemd:
HOOKS=(base systemd copytoram autodetect microcode modconf kms keyboard sd-vconsole block filesystems fsck)
Kernel parameters
Create a separate set of kernel parameters for Linux from RAM by making a copy of the existing kernel parameters first:
sudo cp /etc/kernel/cmdline /etc/kernel/cmdline-ram
Then, edit the newly created parameters:
sudo nano /etc/kernel/cmdline-ram
Append the copy to RAM flag:
rd.copytoram rd.copytoram.size=20G
Adjust the rd.copytoram.size as needed. It can either be a percentage of the total available RAM (i.e., 80%) or an absolute value (i.e., 20G).
mkinitcpio preset
Add another preset to mkinitcpio to build the Linux from RAM unified kernel image. Edit the existing preset:
sudo nano /etc/mkinitcpio.d/linux-lts.preset
Append 'ram' to PRESETS. Example:
PRESETS=('default' 'fallback' 'ram')
Append the following at the end of the file:
ram_uki="/efi/EFI/Linux/arch-linux-lts-ram.efi"
ram_options="--cmdline /etc/kernel/cmdline-ram --splash /usr/share/systemd/bootctl/splash-arch.bmp"
Rebuild initramfs
Rebuild initramfs with:
sudo mkinitcpio -P
The build hook [copytoram] should appear and complete with no errors. To verify the resulting UKIs, execute:
sudo ls /efi/EFI/Linux
Expected result:
arch-linux-lts.efi arch-linux-lts-fallback.efi arch-linux-lts-ram.efi
Reboot and check
Reboot. The boot menu should now show the additional entry. Pick the RAM one to load the system to RAM, or pick the default one to boot from the hard drive normally.
References
Claude