Tag Archives: ext2fs

nbdkit linuxdisk plugin

I’m writing a new nbdkit plugin called linuxdisk. nbdkit is our flexible, plugin-based NBD server, and this new plugin lets you create a complete Linux-compatible virtual disk from a host directory on the fly.

One of the many uses for this is booting minimal VMs very quickly. Here’s an example you can set up in a few seconds. It boots to an interactive busybox shell:

$ mkdir /tmp/root /tmp/root/sbin /tmp/root/bin /tmp/root/dev
$ sudo mknod /tmp/root/dev/console c 5 1
$ cp /sbin/busybox /tmp/root/sbin/
$ ln /tmp/root/sbin/busybox /tmp/root/bin/sh
$ ln /tmp/root/sbin/busybox /tmp/root/bin/ls
$ ln /tmp/root/sbin/busybox /tmp/root/sbin/init
$ nbdkit -U - linuxdisk /tmp/root \
    --run 'qemu-kvm -display none -kernel /boot/vmlinuz-4.20.8-200.fc29.x86_64 -drive file=nbd:unix:$unixsocket,snapshot=on -append "console=ttyS0 root=/dev/sda1 rw" -serial stdio'

If you need any extra files in the VM just drop them straight into /tmp/root before booting it.

Edit: How the heck does /dev get populated in this VM?


Filed under Uncategorized

Notes on producing a minimal, compressed filesystem

You can save the minimal, compressed filesystem from a guest in a way that lets you reconstruct that filesystem (or guest) later very quickly. I’m writing an experimental tool called virt-builder which will make this automatic, but here’s how to make the minimal, compressed filesystem manually.

I’m starting here with a freshly installed Fedora 13 i686 guest. Firstly we see what filesystems it contains:

$ virt-list-filesystems -al /dev/vg_pin/TmpF13
/dev/sda1 ext4
/dev/vg_virtbuilder/lv_root ext4
/dev/vg_virtbuilder/lv_swap swap

We have a boot partition (/dev/sda1), a root filesystem (/dev/vg_virtbuilder/lv_root), and a swap partition. We can just ignore swap since it doesn’t contain any information and we can reconstruct it at will.

There is also some extra information “hidden” in the disk and not in a partition, namely the boot sector, partition table, and (maybe) GRUB stages. For this guest just the boot sector is interesting, other guests may have a boot loader located between the boot sector and the first partition. I’m going to ignore these for now, although virt-builder will need to restore this in order to make a bootable guest.

Let’s grab the boot and root partitions using guestfish:

$ guestfish --ro -i -a /dev/vg_pin/TmpF13 \
    download /dev/sda1 fedora-13-i686-boot.img
$ guestfish --progress --ro -i -a /dev/vg_pin/TmpF13 \
    download /dev/vg_virtbuilder/lv_root fedora-13-i686-root.img
 100% ⟦▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉▉⟧ 00:00

The boot partition is small enough that I’m just going to leave it as it is for now. But I need to shrink the root filesystem. The reason is that I might want to restore this to a different-sized, possibly smaller guest than the one I just created. There is only about 2GB of data in the root filesystem, but as an ext4 filesystem it is taking up about 6GB of space. The resize2fs command has a handy -M option which makes this very simple:

$ e2fsck -f fedora-13-i686-root.img
e2fsck 1.41.12 (17-May-2010)
Pass 1: Checking inodes, blocks, and sizes
Pass 2: Checking directory structure
Pass 3: Checking directory connectivity
Pass 4: Checking reference counts
Pass 5: Checking group summary information
Fedora-13-i686-L: 91151/368640 files (0.1% non-contiguous), 531701/1458176 blocks
$ resize2fs -M fedora-13-i686-root.img
resize2fs 1.41.12 (17-May-2010)
Resizing the filesystem on fedora-13-i686-root.img to 520344 (4k) blocks.
The filesystem on fedora-13-i686-root.img is now 520344 blocks long.

Note that new size: 520344 x 4k blocks = 2081376k. We can therefore truncate the file down to the new size without any loss of information:

$ truncate -s 2081376k fedora-13-i686-root.img
$ ls -lh
total 2.5G
-rw-rw-r--. 1 rjones rjones 500M Oct 30 10:21 fedora-13-i686-boot.img
-rw-rw-r--. 1 rjones rjones 2.0G Oct 30 10:30 fedora-13-i686-root.img

I haven’t finished yet. I now need to compress both filesystems so I have something small(ish) and portable. I performed some tests, and xz was the clear winner in terms of final compressed size, although it does take a very long time to run with the -9 option.

$ xz -9 *.img
$ ls -lh
total 652M
-rw-rw-r--. 1 rjones rjones 250M Oct 30 10:21 fedora-13-i686-boot.img.xz
-rw-rw-r--. 1 rjones rjones 403M Oct 30 10:30 fedora-13-i686-root.img.xz

From the two files above, plus the boot sector stuff that I glossed over, it is possible to reconstruct a Fedora 13 VM of any dimensions quickly (in about 1 minute 15 seconds on my machine). Note the comments are not part of the command, and the guest is fully bootable:

guestfish -x -- \
# create a disk image of any size
  alloc test.img 10G : \
  run : \
# create the partitions
  part-init /dev/sda mbr : \
  part-add /dev/sda primary 2048 1026047 : \
  part-add /dev/sda primary 1026048 -64 : \
# upload the boot loader
  upload fedora-13-i686-grub.img /dev/sda : \
# upload the boot partition
  upload <( xzcat fedora-13-i686-boot.img.xz ) /dev/sda1 : \
# create the logical volumes for root and swap
  pvcreate /dev/sda2 : \
  vgcreate vg_virtbuilder /dev/sda2 : \
  lvcreate lv_swap vg_virtbuilder 512 : \
  lvcreate lv_root vg_virtbuilder 256 : \
  lvresize-free /dev/vg_virtbuilder/lv_root 100 : \
# make fresh swap
  mkswap /dev/vg_virtbuilder/lv_swap : \
# upload and resize the root filesystem
  upload <( xzcat fedora-13-i686-root.img.xz ) /dev/vg_virtbuilder/lv_root : \
  resize2fs /dev/vg_virtbuilder/lv_root


Filed under Uncategorized