This seems to be completely undocumented which is why I’m writing this … It is possible to boot a Linux guest (Fedora in this case) from a live CD on a website without downloading it. I’m using our favourite flexible NBD server, nbdkit and virt-install.
First of all we’ll run nbdkit and attach it to the Fedora 29 live workstation ISO. To make this work more efficiently I’m going to place a couple of filters on top — one is the readahead (prefetch) filter recently added to nbdkit 1.12, and the other is the cache filter. In combination these filters should reduce the load on the website and improve local performance.
$ rm /tmp/socket
$ nbdkit -f -U /tmp/socket --filter=readahead --filter=cache \
I actually replaced that URL with a UK-based mirror to make the process a little faster.
Now comes the undocumented virt-install command:
$ virt-install --name test --ram 2048 \
--disk device=cdrom,source_protocol=nbd,source_host_transport=unix,source_host_socket=/tmp/socket \
After a bit of grinding that should boot into Fedora 29, and you never (not explicitly at least) had to download the ISO.
To be fair qemu does also have a curl driver which virt-install could use, but nbdkit is better with the filters and plugins system giving you ultimate flexibility — check out my video about it.
The new stable release of nbdkit, our flexible Network Block Device server, is out. You can read the announcement and release notes here.
The big new features are SSH support, the linuxdisk plugin, writing plugins in Rust, and extents. Extents allows NBD clients to work out which parts of a disk are sparse or zeroes and skip reading them. It was hellishly difficult to write because of the number of obscure corner cases.
Also in this release, are a couple of interesting filters. The rate filter lets you add a bandwidth limit to connections. We will use this in virt-v2v to allow v2v instances to be rate limited (even dynamically). The readahead filter makes sequential copying and scanning of plugins more efficient by prefetching data ahead of time. It is self-configuring and in most cases simply adding the filter into your filter stack is sufficient to get a nice performance boost, assuming your client’s access patterns are mostly sequential.
Easy with virt-customize. In this example I’m adding the
nosmt option to the command line:
$ virt-customize -a rhel7.img \
s/^GRUB_CMDLINE_LINUX="/GRUB_CMDLINE_LINUX="nosmt /' \
--run-command 'grub2-mkconfig -o /boot/grub2/grub.cfg'
I’ve submitted a talk about nbdkit, our flexible pluggable NBD server, to FOSDEM next February. This is going to be about using NBD as a better way to do loop mounts in Linux.
In preparation I gave a very early version of the talk to a small Red Hat audience.
Video link: http://oirase.annexia.org/rwmj.wp.com/rjones-nbdkit-tech-talk-2018-11-19.mp4
Sorry about the slow start. You may want to skip to 2 mins to get past the intro.
Summary of what’s in the talk:
- Demo of regular, plain loop mounting.
- Demo of loop mounting an XZ-compressed disk image using NBD + nbdkit.
- Slides about how loop device compares to NBD.
- Slides about nbdkit plugins and filters.
- Using VMware VDDK to access a VMDK file.
- Creating a giant disk costing EUR 300 million(!)
- Visualizing a single filesystem.
- Visualizing RAID 5.
- Writing a plugin in shell script (live demo).
If you saw my posting from two days ago you’ll know I’m working on visualizing what happens on block devices when you perform various operations. Last time we covered basics like partitioning a disk, creating a filesystem, creating files, and fstrim.
This time I’ve tied together 5 of the nbdcanvas widgets into a bigger Tcl application that can show what’s happening on a RAID 5 disk set. As with the last posting there’s a video followed by commentary on what happens at each step.
- 00:00: I start guestfish connected to all 5 nbdkit servers. Also of note I’ve added
raid456.devices_handle_discard_safely=1 to the appliance kernel command line, which is required for discards to work through MD RAID devices (I didn’t know that before yesterday).
- 00:02: When the appliance starts up, the black flashes show the kernel probing for possible partitions or filesystems. The disks are blank so nothing is found.
- 00:16: As in the previous post I’m partitioning the disks using GPT. Each ends up with a partition table at the start and end of the disk (two red blocks of pixels).
- 00:51: Now I use
mdadm --create (via the guestfish
md-create command) to make a RAID 5 array across the first 4 disks. The 4th disk is the parity disk — you can see disks 1 through 3 being scanned and the parity information being written to the 4th disk. The 5th disk is a hot spare. Notice how the scanning continues after the
mdadm command has returned. In real arrays this can go on for hours or days.
- 01:11: I create a filesystem. The first action that
mkfs performs is discarding previous data (indicated by light purple). Notice that the parity data is also discarded, which surprised me, but does make sense.
- 01:27: The RAID array is mounted and I unpack a tarball into it.
- 01:40: I delete the files and fstrim, which discards the underlying blocks again.
- 01:48: Now I’m going to inject errors at the block layer into the 3rd disk. The Error checkbox in the Tcl widget simply creates a file. We’re using the nbdkit error filter which monitors for the named file and when it is created starts injecting errors into any read or write operation. Almost immediately the RAID array notices the damage and starts rebuilding on to the hot spare. Notice the black flashes where it reads the working disks (including old parity disk) to construct the redundant information on the spare.
- 01:55: While reconstruction is under way, the RAID array can be used normally.
- 02:14: Examining
/proc/mdstat shows that the third disk has been marked failed.
- 02:24: Now I’m going to inject errors into the 4th disk as well. This RAID array can survive this, operating in a “degraded state”, but there is no more redundancy.
- 02:46: Finally we can examine the kernel messages which show that the RAID array is continuing on 3 devices.
In case you want to reproduce the results yourself, the full command to run nbdkit (repeated 5 times) is:
$ rm /tmp/sock1 /tmp/error1
$ ./nbdkit -fv -U /tmp/sock1 \
--filter=error --filter=log --filter=delay \
memory size=$((64*1024*1024)) \
rdelay=40ms wdelay=40ms \
And the nbdraid viewing program:
$ ./nbdraid.tcl 5 $((64*1024*1024)) /tmp/log%d /tmp/error%d
Ever wondered what is really happening when you write to a disk? What blocks the filesystem writes to and so on? With our flexible, plug-in based NBD server called nbdkit and a little Tcl/Tk program I wrote you can now visualise this.
As in this video (MP4) …
… which shows me opening a blank disk, partitioning it, creating an ext4 filesystem and writing some files.
There’s a lot going on in this video, which I’ll explain below. But first to say that each pixel corresponds to a 4K block on disk — the total disk size is 64M which is 128×128 pixels, and each row is therefore half a megabyte. Red pixels are writes. Black flashing pixels show reads. Light purple is for trim requests, and white pixels are zero requests.
nbdkit was run with the following command line:
$ nbdkit -fv \
memory size=$((64*1024*1024)) \
This means that we’re using the memory plugin to create a throwaway blank disk of 64M. In front of this plugin we place two filters: The delay filter delays all reads and writes by 40ms. This makes it easier to see what’s going on. The second filter is the log filter which records all requests in a log file (
The log file is what the second command reads asynchronously to generate the graphical image:
$ ./nbdview.tcl /tmp/log $((64*1024*1024))
So to the video (MP4):
- 00:07: I start guestfish connected to the NBD server. This boots a Linux appliance, and you can see from the flashes of black how the Linux kernel probes the disk every which way to try to detect any kind of partition or filesystem signature. (Recall that I’m intentionally delaying all read requests which is why the appliance boot and probing seems to take so long. In reality these probes happen near instantaneously.) Of course the disk is all zeroes at this point, so nothing is found.
- 00:23: I partition the disk using GPT. The partitioning is done under the hood by GNU parted and as you can see there is a considerable amount of probing going on by both parted and then the kernel still looking for filesystem signatures. Eventually we end up with two blocks of red (written) data, because GPT creates both a primary and secondary partition table at the beginning and end of the disk.
- 00:36: I create an ext4 filesystem inside the partition. After even more probing by mkfs the first major operation is to trim/discard all data on the disk (shown by the disk filling up with light purple). Then mkfs writes a large block of data in the middle of the disk which I believe is the journal, followed by four dots which I believe could be backup superblocks.
- 00:48: Interestingly filesystem creation has not finished. ext4 (as well as other modern filesystems) defer a lot of work to the kernel, and this is obvious when I mount the disk. Notice that a few seconds after the mount (around 00:59) the kernel starts zeroing parts of the disk. I believe this is the inode table and block free bitmap for the first block group. For larger disks this lazy initialization could go on for a long time.
- 01:05: I unpack a tarball into the filesystem. As expected the operation finishes almost instantaneously, and nothing is actually written to disk. However issuing an explicit sync at 01:11 causes the files and directories to be written, filling first the data blocks and then the inodes and block free bitmap (is there a reason these are written last, or is it just coincidence? Also does the Linux page cache retain the order that the filesystem wrote the blocks?)
- 01:18: I delete the directory tree I just created. As you’d expect nothing is written to disk, and even after a sync nothing much changes.
- 01:26: In contrast when I fstrim the filesystem, all the now-deleted data blocks are discarded (light purple). This is the same principle which
virt-sparsify --in-place uses to make a disk image sparse.
- 01:32: Finally after unmounting the filesystem I issue a blkdiscard command which throws the whole thing away. Even after this Linux is probing the partition to see if somehow a filesystem signature could be present.
You can easily reproduce this and similar results yourself using nbdkit and nbdview, and I’ve submitted a talk to FOSDEM about this and much more fun you can have with nbdkit.
nbdkit is our flexible, plug-in based Network Block Device server.
While I was visiting the KVM Forum last week, one of the most respected members of the QEMU development team mentioned to me that he wanted to think about deprecating QEMU’s VVFAT driver. This QEMU driver is a bit of an oddity — it lets you point QEMU to a directory of files, and inside the guest it will see a virtual floppy containing those files:
$ qemu -drive file=fat:/some/directory
That’s not the odd thing. The odd thing is that it also lets you make the drive writable, and the VVFAT driver then turns those writes back into modifications to the host filesystem (remember that these are writes happening to raw FAT32 data structures, the driver has to infer from just seeing the writes what is happening at the filesystem level). Which is both amazing and crazy (and also buggy).
Anyway I have implemented the read-only part of this in nbdkit. I didn’t implement the write stuff because that’s very ambitious, although if you were going to implement that, doing it in nbdkit would be better than qemu since the only thing that can crash is nbdkit, not the whole hypervisor.
Usage is very simple:
$ nbdkit floppy /some/directory
This gives you an NBD source which you can connect straight to a qemu virtual machine:
$ qemu -drive nbd:localhost:10809
or examine with guestfish:
$ guestfish --ro --format=raw -a nbd://localhost -m /dev/sda1
Welcome to guestfish, the guest filesystem shell for
editing virtual machine filesystems and disk images.
Type: ‘help’ for help on commands
‘man’ to read the manual
‘quit’ to quit the shell
> ll /
drwxr-xr-x 14 root root 16384 Jan 1 1970 .
drwxr-xr-x 19 root root 4096 Oct 28 10:07 ..
-rwxr-xr-x 1 root root 40 Sep 17 21:23 .dir-locals.el
-rwxr-xr-x 1 root root 879 Oct 27 21:10 .gdb_history
drwxr-xr-x 8 root root 16384 Oct 28 10:05 .git
-rwxr-xr-x 1 root root 1383 Sep 17 21:23 .gitignore
-rwxr-xr-x 1 root root 1453 Sep 17 21:23 LICENSE
-rwxr-xr-x 1 root root 34182 Oct 28 10:04 Makefile
-rwxr-xr-x 1 root root 2568 Oct 27 22:17 Makefile.am
-rwxr-xr-x 1 root root 32085 Oct 27 22:18 Makefile.in
-rwxr-xr-x 1 root root 620 Sep 17 21:23 OTHER_PLUGINS
-rwxr-xr-x 1 root root 4628 Oct 16 22:36 README
-rwxr-xr-x 1 root root 4007 Sep 17 21:23 TODO
-rwxr-xr-x 1 root root 54733 Oct 27 22:18 aclocal.m4
drwxr-xr-x 2 root root 16384 Oct 27 22:18 autom4te.cache
drwxr-xr-x 2 root root 16384 Oct 28 10:04 bash
drwxr-xr-x 5 root root 16384 Oct 27 18:07 common
Previously … create ISO images on the fly in nbdkit