Monday, October 22, 2012

Running Linux from RAM

Computers nowadays usually have a lot of memory, and a basic Linux system can fit in RAM. I started out by installing from the Ubuntu 12.10 Minimal CD. There I chose x86, because it's smaller and the speed difference isn't very dramatic.

I performed a normal installation into a 1 GB partition. Because of the small size, Lubuntu and even tasksel were out of the question, and manual package selection was necessary. Initially, I was disappointed, because just the minimal install took up over 700 MB. After uninstalling Linux headers, I could easily fit LXDE basics plus Firefox. The hardest part was manually configuring wireless, but that's another story.

I now had a usable system, and it was time to get it running from RAM. I did that from a shell started by adding init=/bin/sh to the kernel command line. Here is a script. The comments explain what is being done.

# Script to copy / to tmpfs and continue boot from there
# Do not run this from a child shell. Use ". ramify" or exec.
# The shell running this script must be the only process on the system.
# Ensure this runs in /
cd /
# Create and mount tmpfs file system for /
mount -t tmpfs tmpfs mnt
# Copy everything from / filesystem to tmpfs
# Tar will restore proper owners and permissions when run as root
# FIXME: This is very slow because it reads / in many small pieces
# TODO: Add --exclude to prevent copying unneeded stuff
tar --one-file-system -c . | tar -C /mnt -x
# Move other mounts
mount --move dev mnt/dev
mount --move proc mnt/proc
mount --move run mnt/run
mount --move sys mnt/sys
# Create fstab with just new root file system
sed -i '/^[^#]/d;' mnt/etc/fstab
echo 'tmpfs / tmpfs defaults 0 0' >> mnt/etc/fstab
# Pivot root using instructions from pivot_root(8) man page
cd mnt
mkdir old_root
pivot_root . old_root
# Old root can only be unmounted once sh running from old root
# finishes. Continue startup normally using init.
exec chroot . bin/sh -c "umount old_root ; exec sbin/init"


karnd01 said...

Awesome! I'm doing something very similar only using a custom initrd image, but this seem simpler to maintain than my solution.. is there a way to execute your script right after you get dropped into the shell by using init=/bin/sh?

B.X said...

Great code. Thank you!!!
If need more then 10GB rootfs, need small change:

# Create and mount tmpfs file system for /
mount -t tmpfs -o size=80% tmpfs mnt