You may have noticed another difference between the way we’re using disks in UML and the way they are normally used on a physical machine. We haven’t been partitioning them and putting filesystems and swap space on the partitions. This is a consequence of the ease of creating and adding new virtual disks to a virtual machine. With a physical disk, it’s much less convenient, and sometimes impossible, to add more disks to a system. Therefore, you want to make the best of what you have, and that means being able to slice a physical disk into partitions that can be treated separately.
When UML was first released, there was no partition support for exactly this reason. I figured there was no need for partitions, given that if you want more disk space in your UML, you just create a new host file for it, and away you go.
This was a mistake. I underestimated the desire of my users to treat their UMLs exactly like their physical machines. In part, this meant they wanted to be able to partition their virtual disks. So, parti- tion support for UML block devices ultimately appeared, and everyone was happy.
However, my original mistake resulted in some naming conven- tions that can be extremely confusing to a UML newcomer. Initially, UML block devices were referred to by number, for example, ubd0, ubd1, and so on. At first, these numbers corresponded to their minor device numbers, so when you made a device node for ubd1, the com- mand was:
50 Chapter 3 Exploring UML
When partition support appeared, this style of device naming was wrong in a couple of respects. First, you want to refer to the partition by number, as with /dev/hda1 or /dev/sdb2. But does ubd10 refer to block device 10 or partition 0 on device 1? Second, there is support for 16 partitions per device, so each block device gets a chunk of 16 device minor numbers to refer to them. For example, block device 0 has minor numbers 0 through 15, device 1 has minors 16 though 31, and so on. This breaks the previous convention that device numbers correspond to minor numbers, leading people to specify ubd1 on the UML command line and not realize that it has minor device number 16 inside UML.
These two problems led to a naming convention that should have been present from the start. We name ubd devices in the same way as hd or sd devices—the disk number is specified with a letter (a, b, c, and so on), and the partition is a number. So, partition 1 on virtual disk 1 is ubdb1. When you add a second disk on the UML command line or via mconsole, it is ubdb, not ubd1. This eliminates the ambiguity of multidigit device numbers and the naming confusion. In this book, I will adhere to this convention, although my fingers still use ubd0, ubd1, and so on when I boot UML. In addition, the filesystems I’m using have references to ubd0, so commands such as mount and df will refer to names such as ubd0 rather than ubda.
So, let’s partition a ubd device just to see that it’s the same as on a physical machine. First, let’s make another host file to hold the device and plug it into the UML:
host% dd if=/dev/zero of=partitioned bs=1024 \ seek=$[ 1024 * 1024 ] count=1
1+0 records in 1+0 records out
host% uml_mconsole debian config ubdc=partitioned OK
Now, inside the UML, let’s use fdisk to chop this into partitions. Figure 3.2 shows my dialog with fdisk to create two equal-size parti- tions on this disk.
Now, I don’t happen to have device nodes for these partitions, so I’ll create them:
UML# mknod /dev/ubdc1 b 98 33 UML# mknod /dev/ubdc2 b 98 34
Partitioned Disks 51
usermode:~# fdisk /dev/ubdc
Device contains neither a valid DOS partition table, nor Sun, SGI, or OSF disklabel
Building a new DOS disklabel. Changes will remain in memory only, until you decide to write them. After that, of course, the previous content won’t be recoverable.
Command (m for help): p
Disk /dev/ubdc: 128 heads, 32 sectors, 512 cylinders Units = cylinders of 4096 * 512 bytes
Device Boot Start End Blocks Id System Command (m for help): n
Command action e extended
p primary partition (1-4) p
Partition number (1-4): 1
First cylinder (1-512, default 1): Using default value 1
Last cylinder or +size or +sizeM or +sizeK (1-512, default 512): 256 Command (m for help): n
Command action e extended
p primary partition (1-4) p
Partition number (1-4): 2
First cylinder (257-512, default 257): Using default value 257
Last cylinder or +size or +sizeM or +sizeK (257-512, default 512): Using default value 512
Command (m for help): w
The partition table has been altered! Calling ioctl() to re-read partition table.
WARNING: If you have created or modified any DOS 6.x
partitions, please see the fdisk manual page for additional information.
Syncing disks. usermode:~#
52 Chapter 3 Exploring UML
For some variety, let’s make one a swap partition and the other a filesystem:
UML# mkswap /dev/ubdc1
Setting up swapspace version 1, size = 536850432 bytes UML# mke2fs /dev/ubdc2
mke2fs 1.18, 11-Nov-1999 for EXT2 FS 0.5b, 95/08/09 Filesystem label=
OS type: Linux
Block size=4096 (log=2) Fragment size=4096 (log=2) 131072 inodes, 262144 blocks
13107 blocks (5.00%) reserved for the super user First data block=0
8 block groups
32768 blocks per group, 32768 fragments per group 16384 inodes per group
Superblock backups stored on blocks: 32768, 98304, 163840, 229376
Writing inode tables: done
And let’s put them into action to see that they work as advertised:
UML# swapon /dev/ubdc1 UML# free
total used free shared buffers \ cached
Mem: 125128 69344 55784 0 448 \ 49872
-/+ buffers/cache: 19024 106104 Swap: 1572832 0 1572832 UML# mount /dev/ubdc2 /mnt
UML# df
Filesystem 1k-blocks Used Available Use% Mounted on /dev/ubd0 1032056 259444 720132 26% /
none 62564 0 62564 0% /tmp /dev/ubdc2 507748 13 481521 0% /mnt
So, we do, in fact, have another 512MB of swap space and a brand- new empty 512MB filesystem.
Rather than calling swapon by hand whenever we want to add some swap space to our UML, we can also just add the device to the UML’s /etc/fstab. In our case, the relevant lines would be:
/dev/ubdb swap swap defaults 0 0 /dev/ubdc1 swap swap defaults 0 0
However, if you do this, you must remember to configure the devices on the UML command line since they must be present early in boot when the filesystems are mounted.
UML Disks as Raw Data 53
UML DISKS
AS RAW DATA
Normally, when you add a new block device to a UML, it will be used as either a filesystem or a swap device. However, some other possibilities are also useful with a UML. These work equally well on a physical machine but aren’t used because of the lower flexibility of physical disks.
For example, you can copy files into a UML by creating a tar file on the host that contains them, plug that tar file into the UML as a virtual disk, and, inside the UML, untar the files directly from that device. So, on the host, let’s create a tar file with some useful files in it:
host% tar cf etc.tar /etc
tar: Removing leading `/' from member names
When I did this on my machine, I got a bunch of errors about files that I, as a normal user, couldn’t read. Since this is just a demo, that’s OK, but if you were really trying to copy your host’s /etc into a UML, you’d want to become root in order to get everything.
host% ls -l etc.tar
-rw-rw-rw- 1 jdike jdike 24535040 Feb 19 13:54 etc.tar
I did get about 25MB worth of files, so let’s plug this tar file into the UML as device number 4, or ubdd:
host% uml_mconsole debian config ubdd=etc.tar
Now we can untar directly from the device:
UML# tar xf /dev/ubdd
This technique can also be used to copy a single file into a UML. Simply configure that file as a UML block device and use dd to copy it from the device to a normal file inside the UML filesystem. The draw- back of this approach is that the block device will be an even multiple of the device block size, which is 512 bytes. So, a file whose size is not an even multiple of 512 bytes will have some padding added to it. If this matters, that excess will have to be trimmed in order to make the UML file the same size as the host file.
UML block devices can be attached to anything on the host that can be accessed as a file. Formally, the underlying host file must be seekable. This rules out UNIX sockets, character devices, and named pipes but includes block devices. Devices such as physical disks, parti- tions, CD-ROMs, DVDs, and floppies can be passed to UML as block devices and accessed from inside as ubd devices. If there is a filesystem
54 Chapter 3 Exploring UML
on the host block device, it can be mounted inside UML in exactly the same way as on the host, except for the different device name.
The UML must have the appropriate filesystem, either built-in or available as a module. For example, in order to mount a host CD-ROM inside a UML, it must have ISO-96602 filesystem support.
The properties of the host file show through to the UML device to a great extent. We have already seen that the host file’s size deter- mines the size of the UML block device. Permissions also control what can be done inside UML. If the UML user doesn’t have write access to the host file, the resulting device will be only mounted read-only.