After using parted
disk1.raw
has a partition table, but does
that mean we can create partitions on it now? Let's run
fdisk on disk1.raw
.
$ fdisk disk1.raw You must set cylinders. You can do this from the extra functions menu. Command (m for help):
TODO: Maybe this next paragraph should be rejiggered. It's not so much that it's too difficult to calculate, but rather, it's because the virtual disk has no actual physical properties.
Or, just explain that it's impractical and unnecessary. Provide as a reference in the appendix.
A much simpler way to create partitions (still using fdisk) is by accessing the file as if it were an actual device. Doing this requires creating loop devices.
Instead of using fdisk on
disk1.raw
directly, we'll create a loop
device and associate disk1.raw
with it. From
here on we'll be accessing our virtual drives through loop
devices.
Why are we doing this? And what is a loop device?
Unfortunately for disk1.raw
, it will never be
anything more than just a file. The operating system just doesn't
have interfaces for block operations against files. As the kernel
creates the block special device /dev/sda
to represent my hard drive,
we need to create a block special device to represent our virtual
disk. This is called a loop device. You can think of a loop
device, e.g., /dev/loop1
, like a translator.
With a loop device inserted between programs and our disk image we can view and operate on the disk image as if it were a regular drive. When accessed through a loop device fdisk can properly determine the number of cylinders, heads, and everything else required to create partitions.
Note | |
---|---|
Since we'll be working with the kernel to create a device you'll need to have super user permissions to continue. |
To create a loop device run the losetup command
with the -f
option. The first available loop
device will be selected automatically and associated with
disk1.raw
[28]
.
Example 3.6. Creating a loop device with losetup
$ sudo losetup -f disk1.raw $ sudo losetup -a /dev/loop1: [0805]:151552 (/home/tim/images/disk1.raw)
You can run file, stat, and
fdisk on disk1.raw
to
verify that nothing has changed since we put a partition table on
it with parted.
Example 3.7. Examining the Loop Device
$ file /dev/loop0 /dev/loop0: block special $ stat /dev/loop0 File: `/dev/loop0' Size: 0 Blocks: 0 IO Block: 4096 block special file Device: 5h/5d Inode: 5102 Links: 1 Device type: 7,0 Access: (0660/brw-rw----) Uid: ( 0/ root) Gid: ( 6/ disk) Access: 2010-09-15 01:22:09.909721760 -0400 Modify: 2010-09-12 11:03:19.351004598 -0400 Change: 2010-09-12 11:03:24.694640781 -0400 $ sudo fdisk -l /dev/loop0 Disk /dev/loop0: 1073 MB, 1073741824 bytes 255 heads, 63 sectors/track, 130 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x000e44e8 Device Boot Start End Blocks Id System
Look back at Example 3.1, “Regular Disk Drive”
where I ran these commands against my actual disk drive
(/dev/sda
) and
you'll see the results are quite similar.
Table 3.3. Examining the Loop Device
Command | sda | disk1.raw | disk1.raw (via parted) | /dev/loop0 |
---|---|---|---|---|
file | block special | data | x86 boot sector | block special |
stat | block special | regular file | regular file | block special |
fdisk | has partition table | no partition table | valid partition table. unknown cylinder count | valid partition table. known cylinder count |
file detects loop0
as a block special
device.
stat does too.
fdisk no longer says we need to set the cylinders.
Our virtual disk is starting to look like a real hard drive now! To conclude this section we'll:
create a partition
format it with an ext3 filesystem
mount it for reading and writing
Open /dev/loop0
(or
whatever loop device your disk was associated with) in
fdisk to create a partition.
Example 3.8. Creating a partition with fdisk
$ sudo fdisk /dev/loop0 Command (m for help): n Command action e extended p primary partition (1-4) p Partition number (1-4): 1 First cylinder (1-130, default 1): Using default value 1 Last cylinder, +cylinders or +size{K,M,G} (1-130, default 130): Using default value 130 Command (m for help): t Selected partition 1 Hex code (type L to list codes): 83 Command (m for help): w The partition table has been altered! Calling ioctl() to re-read partition table. WARNING: Re-reading the partition table failed with error 22: Invalid argument. The kernel still uses the old table. The new table will be used at the next reboot or after you run partprobe(8) or kpartx(8) Syncing disks. $ sudo fdisk -l /dev/loop0 Disk /dev/loop0: 1073 MB, 1073741824 bytes 255 heads, 63 sectors/track, 130 cylinders Units = cylinders of 16065 * 512 = 8225280 bytes Disk identifier: 0x000e44e8 Device Boot Start End Blocks Id System /dev/loop0p1 1 130 1044193+ 83 Linux
TODO: That example would benefit a LOT from some well placed callouts
TODO: Speak about the kpartx and partprobe commands
Unlike /dev/sda
we can't
just create a partition on the loop0
device by addressing it as
/dev/loop0
. This is
because the kernel has no device created to represent it. Instead
we'll have to create another device associated with a specific
offset in our device/file.
TODO: Rephrase the above paragraph ^ wrt: device representation
Q: |
What is an |
A: |
An
The first partition is not located at the beginning of the
device. That is where the Master Boot Record
(MBR) is stored
( |
Q: | How do we calculate the offset to specify? |
A: |
To calculate the offset we need to know what sector the
partition ( |
Q: | Why doesn't the first partition begin after the MBR? Specifically, why is there empty space between the first sector (where the MBR is stored) and the first partition? |
A: | It's complicated but worth learning about. See Appendix B, Appendix: Disk Drive History for a complete explanation. Here's the short answer: In current PC MBRs there may be up to 446B of executable code and a partition table containing up to 64B of data. When you add in another 2B to record a Boot Signature you have 512B, which up until recently happened to be the typical size of one sector. Partitioning tools historically left the space between the MBR and the second cylinder empty. Modern boot loaders (NTLDR[29], GRUB[30], etc) use this space to store additional code and data necessary to boot the system [31] [32]. Some software, such as licensing managers and virus scanners, also use this space to store files [33] . |
Print the partition table using fdisk with the
-u
option to switch the printing format to
sectors instead of cylinders for units.
$ sudo fdisk -u -l /dev/loop0 Disk /dev/loop0: 1073 MB, 1073741824 bytes 255 heads, 63 sectors/track, 130 cylinders, total 2097152 sectors Units = sectors of 1 * 512 = 512 bytes Disk identifier: 0x000e44e8 Device Boot Start End Blocks Id System /dev/loop0p1 63 2088449 1044193+ 83 Linux
/dev/loop0p1
is
our first partition and from the table above we know that it
starts on sector 63. Since we have to specify offsets in
bytes we multiply 63 by 512 (the default block size) to
obtain an offset of 32256 bytes.
$ sudo losetup -o 32256 -f /dev/loop0 $ sudo losetup -a /dev/loop0: [0805]:151552 (/home/tim/images/disk1.raw) /dev/loop1: [0005]:5102 (/dev/loop0), offset 32256
Now that we have /dev/loop1
representing the first
partition of our virtual disk we can create a filesystem on it and
finally mount it.
Example 3.9. Formatting and mounting the partition
$ sudo mkfs -t ext3 /dev/loop1 mke2fs 1.41.9 (22-Aug-2009) Filesystem label= OS type: Linux Block size=4096 (log=2) Fragment size=4096 (log=2) 65536 inodes, 262136 blocks 13106 blocks (5.00%) reserved for the super user First data block=0 Maximum filesystem blocks=268435456 8 block groups 32768 blocks per group, 32768 fragments per group 8192 inodes per group Superblock backups stored on blocks: 32768, 98304, 163840, 229376 Writing inode tables: done Creating journal (4096 blocks): done Writing superblocks and filesystem accounting information: done This filesystem will be automatically checked every 25 mounts or 180 days, whichever comes first. Use tune2fs -c or -i to override. $ sudo losetup -d /dev/loop1 $ sudo losetup -d /dev/loop0 $ mkdir partition1 $ sudo mount -t ext3 -o loop,offset=32256 disk1.raw partition1/ $ mount | grep partition1 /dev/loop0 on /home/tim/images/partition1 type ext3 (rw,offset=32256) $ df -h partition1/ Filesystem Size Used Avail Use% Mounted on /dev/loop0 1008M 18M 940M 2% /home/tim/images/partition1
Note | |
---|---|
The same procedure applies to any arbitrary partition: obtain the starting sector, multiply by block size. |
You can detach the loop device (while leaving your file
intact) by giving the -d
option to
losetup.
[28] FUSE (Filesystem in Userspace)
has a module called Mountlo
that allows non-root users
to make make loop devices.
[29] NT Loader (NTLDR): http://en.wikipedia.org/wiki/NTLDR
[30] The Grand Unified Bootloader (GRUB): http://www.gnu.org/software/grub/
[31] GRUB: BIOS Installation: http://www.gnu.org/software/grub/manual/grub.html#BIOS-installation
[32] Simon Kitching: Booting Linux on x86 using Grub2: http://moi.vonos.net/linux/Booting_Linux_on_x86_with_Grub2/#installing-grub
[33] Ubuntu Forums - Sector 32 FlexNet Problem -- Grub: http://ubuntuforums.org/showthread.php?t=1661254