Adding a New Disk

WARNING: BE CAREFUL! Some commands in this tutorial can cause permanent data loss. We recommend you backup your files before attempting to run these commands. You should also double check every command to make sure you have made no typos or mistakes. A single typo could destroy your data forever!

NOTE: This guide is no substitute for reading the OpenBSD FAQ. In particular, you should read the section on Disk Setup.

NOTE: Before performing the upgrades, you will want to announce the changes to your users and teammates.

On OpenBSD, there are two disk drivers: wd and sd. wd is an IDE-like disk, and sd is a SCSI-like disk (including USB disks). To list all your available disks:

$ dmesg | grep -E '(sd[0-9]|wd[0-9])'
sd0 at scsibus2 targ 0 lun 0: <BUYVM, SLAB, 2.5+> serial.BUYVM_SLAB_VOLUME-4047
sd0: 524288MB, 512 bytes/sector, 1073741824 sectors, thin
sd1 at scsibus3 targ 0 lun 0: <VirtIO, Block Device, >
sd1: 40960MB, 512 bytes/sector, 83886080 sectors

In this example, our server has two SCSI-like disks (a BuyVM slab and a VirtIO block device). In this case, the VirtIO block device is the hard disk the operating system is installed on, and the slab is extra storage we purchased. The disks are numbered by the order in which they are detected at boot time. The first SCSI-like disk will be sd0, the second sd1, and so forth.

The first disk sd0 can store around 500GB of data, the second disk sd1 can store around 40GB.

We will now add the new space from sd0 by creating a new partition for the disk, formatting it, and then mounting it to the filesystem.

WARNING: Double check your commands and make certain you are editing the correct disk. You must substitute the disk in the example for the one you actually want to format. Typing the wrong disk by accident could destroy all your data forever.

Creating a New Partition

The first task is to use fdisk to create fdisk partitions (Master Boot Record partitions). Now, the easy way is to run this one command:

$ doas fdisk -iy sd0

This automatically creates an fdisk partition that spans the entire disk. That said, you can (and should!) learn how to edit this interactively, to fine tune your options.

$ doas fdisk -e sd0
Enter 'help' for information

Type help to get help, manual to read the fdisk man page, and print to view the partitions:

sd0: 1> help
        help            Command help list
        manual          Show entire OpenBSD man page for fdisk
        reinit          Re-initialize loaded MBR (to defaults)
        setpid          Set the identifier of a given table entry
        disk            Edit current drive stats
        edit            Edit given table entry
        flag            Flag given table entry as bootable
        update          Update machine code in loaded MBR
        select          Select extended partition table entry MBR
        swap            Swap two partition entries
        print           Print loaded MBR partition table
        write           Write loaded MBR to disk
        exit            Exit edit of current MBR, without saving changes
        quit            Quit edit of current MBR, saving current changes
        abort           Abort program without saving current changes
sd0: 1> print
Disk: sd0       geometry: 66837/255/63 [1073741824 Sectors]
Offset: 0       Signature: 0x0
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 3: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      

This disk sd0 is completely blank, so it is probably safe to edit the fdisk partitions and format the disk.

WARNING: If the disk already has existing partitions, double check to make sure you are not wiping out data!

First, let's reinit. This should automatically create an fdisk partition on the last partition, partition 3, for OpenBSD and use all available space. It will also initialize this as the boot block.

sd0: 1> reinit
Disk: sd0       geometry: 66837/255/63 [1073741824 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 1: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
 2: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
*3: A6      0   1   2 -  66836 254  63 [          64:  1073736341 ] OpenBSD     
Use 'write' to update disk.

Notice that the Signature changes from 0x0 to 0xAA55, and partition #3 is now set to id A6 (the OpenBSD partition type).

This can also be done manually by using the edit command on partition 3:

sd0: 1> edit 3
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 3: 00      0   0   0 -      0   0   0 [           0:           0 ] unused      
Partition id ('0' to disable) [01 - FF]: [0] (? for help) A6
Do you wish to edit in CHS mode? [n] y
BIOS Starting cylinder [0 - 66836]: [0] 
BIOS Starting head [0 - 254]: [1] 
BIOS Starting sector [1 - 63]: [2] 
BIOS Ending cylinder [0 - 66836]: [0] 66836
BIOS Ending head [0 - 254]: [0] 254
BIOS Ending sector [1 - 63]: [1] 63

We need to edit in Cylinder-Head-Sector (CHS) mode. To use the full space of the disk, you will want to choose the lowest numbers in the range for the starting cylinder, head, and sector; and the highest possible numbers for the ending cylinder, head, and sector.

We now write to disk:

sd0*: 1> write
Writing MBR at offset 0.

We'll print G to see everything in gigabytes:

sd0: 1> print G
Disk: sd0       geometry: 66837/255/63 [1073741824 Sectors]
Offset: 0       Signature: 0xAA55
            Starting         Ending         LBA Info:
 #: id      C   H   S -      C   H   S [       start:        size ]
-------------------------------------------------------------------------------
 0: 00      0   0   0 -      0   0   0 [           0:           0G] unused      
 1: 00      0   0   0 -      0   0   0 [           0:           0G] unused      
 2: 00      0   0   0 -      0   0   0 [           0:           0G] unused      
*3: A6      0   1   2 -  66836 254  63 [          64:         512G] OpenBSD     

If everything looks good,

sd0: 1> quit

Disklabel

Next, we need to use disklabel to manage OpenBSD filesystem partitions (these disklabel partitions exist inside of an fdisk partition).

We should leave the first logical track unused, so the first partition should start at block 64.

Each fdisk partition can be sliced into OpenBSD disklabel partitions with letters as labels. The a partition is your root partition, b is your swap, and c is the entire disk.

If you already have the operating system installed on another disk (like we do here), you just need 1 single partition: the a partition with the same size as the disk.

$ doas disklabel -E sd0
Label editor (enter '?' for help at any prompt)
sd0> ?
Available commands:
 ? | h    - show help                 n [part] - set mount point
 A        - auto partition all space  p [unit] - print partitions
 a [part] - add partition             q        - quit & save changes
 b        - set OpenBSD boundaries    R [part] - resize auto allocated partition
 c [part] - change partition size     r        - display free space
 D        - reset label to default    s [path] - save label to file
 d [part] - delete partition          U        - undo all changes
 e        - edit drive parameters     u        - undo last change
 g [d|u]  - [d]isk or [u]ser geometry w        - write label to disk
 i        - modify disklabel UID      X        - toggle expert mode
 l [unit] - print disk label header   x        - exit & lose changes
 M        - disklabel(8) man page     z        - delete all partitions
 m [part] - modify partition

Suffixes can be used to indicate units other than sectors:
 'b' (bytes), 'k' (kilobytes), 'm' (megabytes), 'g' (gigabytes) 't' (terabytes)
 'c' (cylinders), '%' (% of total disk), '&' (% of free space).
Values in non-sector units are truncated to the nearest cylinder boundary.

To print the partitions in gigabytes:

sd0> p G
OpenBSD area: 64-1073736405; size: 512.0G; free: 512.0G
#                size           offset  fstype [fsize bsize   cpg]
  c:           512.0G                0  unused                    

We want to add the a partition. We'll use defaults for offset, size, and FS type:

sd0> a a
offset: [64] 
size: [1073736341] 
FS type: [4.2BSD] 
sd0*> p G
OpenBSD area: 64-1073736405; size: 512.0G; free: 0.0G
#                size           offset  fstype [fsize bsize   cpg]
  a:           512.0G               64  4.2BSD   4096 32768     1 
  c:           512.0G                0  unused                    

Then write the changes to disk and quit:

sd0*> w
sd0> q
No label changes.

Next, you'll want to format the disk:

$ doas newfs sd0a
/dev/rsd0a: 524285.3MB in 1073736320 sectors of 512 bytes                    
644 cylinder groups of 814.44MB, 26062 blocks, 52224 inodes each             
super-block backups (for fsck -b #) at:                                                 
...

We now have sd0a formatted, but we need to mount it. Let's look at where our system's partitions are currently mounted:

$ mount                 
/dev/sd1a on / type ffs (local)
/dev/sd1k on /home type ffs (local, nodev, nosuid)
/dev/sd1d on /tmp type ffs (local, nodev, nosuid)
/dev/sd1f on /usr type ffs (local, nodev)
/dev/sd1g on /usr/X11R6 type ffs (local, nodev)
/dev/sd1h on /usr/local type ffs (local, nodev, wxallowed)
/dev/sd1j on /usr/obj type ffs (local, nodev, nosuid)
/dev/sd1i on /usr/src type ffs (local, nodev, nosuid)
/dev/sd1e on /var type ffs (local, nodev, nosuid)

We can also see the size of these partitions:

$ df -h                                                                      
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/sd1a      615M    232M    352M    40%    /
/dev/sd1k      3.7G    2.1G    1.4G    59%    /home
/dev/sd1d      863M   28.0K    820M     0%    /tmp
/dev/sd1f      2.3G    1.6G    600M    74%    /usr
/dev/sd1g      648M    238M    378M    39%    /usr/X11R6
/dev/sd1h      2.3G    2.2G   50.2M    98%    /usr/local
/dev/sd1j      5.2G    2.0K    4.9G     0%    /usr/obj
/dev/sd1i      1.4G    2.0K    1.3G     0%    /usr/src
/dev/sd1e      1.3G    318M    913M    26%    /var

For this example, /home is too small for our server, so we're going to copy all the data from sd1k to sd0, then mount sd0a as the new /home.

$ doas su
# mount /dev/sd0a /mnt
# cd /mnt

Then we dump and restore to clone the partition:

# dump -0 -a -f - /home | restore -rf -

You will want to replace /home with whatever partition you want to back up on the new disk.

Alternatively, you can copy the files manually by running:

# cp -R /home/* /home/.* /mnt/

Inspect the files in the partition to make sure they copied successfully:

# ls -a /mnt/

Then unmount the partition:

# umount /mnt/
# ^D

(Type ctrl+d or ^D to exit)

The next steps will take the system offline, so before performing any more steps, you will want to announce to your users and teammates that they should save all files and prepare for downtime.

Now we need to automatically mount this partition at bootup. Let's take a look at the current /etc/fstab:

37deb3c1c30cbfbf.b none swap sw
37deb3c1c30cbfbf.a / ffs rw 1 1
37deb3c1c30cbfbf.k /home ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.d /tmp ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.f /usr ffs rw,nodev 1 2
37deb3c1c30cbfbf.g /usr/X11R6 ffs rw,nodev 1 2
37deb3c1c30cbfbf.h /usr/local ffs rw,wxallowed,nodev 1 2
37deb3c1c30cbfbf.j /usr/obj ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.i /usr/src ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.e /var ffs rw,nodev,nosuid 1 2

The string 37deb3c1c30cbfbf is called the disklabel unique identifier (DUID). Each disk partition has its own unique DUID. Let's find the DUID of our new disk partition:

$ sysctl hw.disknames 
hw.disknames=cd0:,sd0:f433d9e11879420f,sd1:37deb3c1c30cbfbf,fd0:

The DUID for sd0 is f433d9e11879420f. So, we need to replace /home's partition 37deb3c1c30cbfbf.k with f433d9e11879420f.a (since we are trying to mount sd0a):

37deb3c1c30cbfbf.b none swap sw
37deb3c1c30cbfbf.a / ffs rw 1 1
f433d9e11879420f.a /home ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.d /tmp ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.f /usr ffs rw,nodev 1 2
37deb3c1c30cbfbf.g /usr/X11R6 ffs rw,nodev 1 2
37deb3c1c30cbfbf.h /usr/local ffs rw,wxallowed,nodev 1 2
37deb3c1c30cbfbf.j /usr/obj ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.i /usr/src ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.e /var ffs rw,nodev,nosuid 1 2

Then, reboot:

$ doas shutdown -r now

If everything was done correctly, the system should automatically mount sd0a as /home upon bootup. The old partition, /dev/sd1k, can still be mounted if you need it:

$ doas mount /dev/sd1k /mnt/

Double check to make sure the files on /home exactly match those on /mnt from sd1k. If they do not, you will need to clone the disk again using dump/restore or cp.

Once you are certain the files have been copied properly, you can use unmount the partition:

$ doas umount /mnt

Then you can clear out the free space to grow an existing partition? or you can create a new partition with it and mount it elsewhere.

Troubleshooting:

Uh oh, my system won't reboot!

This can happen if you foul up /etc/fstab. For example, suppose I had made this error in /etc/fstab:

37deb3c1c30cbfbf.b none swap sw
37deb3c1c30cbfbf.a / ffs rw 1 1
f433d9e11879420f.b /home ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.d /tmp ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.f /usr ffs rw,nodev 1 2
37deb3c1c30cbfbf.g /usr/X11R6 ffs rw,nodev 1 2
37deb3c1c30cbfbf.h /usr/local ffs rw,wxallowed,nodev 1 2
37deb3c1c30cbfbf.j /usr/obj ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.i /usr/src ffs rw,nodev,nosuid 1 2
37deb3c1c30cbfbf.e /var ffs rw,nodev,nosuid 1 2

For the third line, instead of putting .a, I put .b by accident. When I reboot the system by running doas shutdown -r now, I can no longer ssh into the system. When I log in via serial console (cu for vmm or VNC for BuyVM)

root on sd0a (a0e97b069eed0743.a) swap on sd0b dump on sd0b
Automatic boot in progress: starting file system checks.
/dev/sd0a (a0e97b069eed0743.a): file system is clean; not checking
Can't open d40a0cfcd4551ac7.b: No such file or directory
CAN'T CHECK FILE SYSTEM.
d40a0cfcd4551ac7.b: UNEXPECTED INCONSISTENCY; RUN fsck_ffs MANUALLY.
/dev/sd0k (a0e97b069eed0743.k): file system is clean; not checking
/dev/sd0d (a0e97b069eed0743.d): file system is clean; not checking
/dev/sd0f (a0e97b069eed0743.f): file system is clean; not checking
/dev/sd0g (a0e97b069eed0743.g): file system is clean; not checking
/dev/sd0h (a0e97b069eed0743.h): file system is clean; not checking
/dev/sd0j (a0e97b069eed0743.j): file system is clean; not checking
/dev/sd0i (a0e97b069eed0743.i): file system is clean; not checking
/dev/sd0e (a0e97b069eed0743.e): file system is clean; not checking
THE FOLLOWING FILE SYSTEM HAD AN UNEXPECTED INCONSISTENCY:
        ffs: d40a0cfcd4551ac7.b (/home)
Automatic file system check failed; help!
Enter pathname of shell or RETURN for sh: 

In order to boot up, you'll need to fix fstab. So, press the enter key to enter into the shell. Then, to view your /etc/fstab, type:

# cat /etc/fstab

Check how your partitions are mounted:

# mount
root_device on / type ffs (local, read-only)

You'll notice that only / is mounted (so you can't use programs from /usr or view files in /home). This means you'll lack basic utilities like less and text editors like vi and mg. You'll also be unable to edit and save /etc/fstab, since / is mounted read-only. So first, let's fix that.

# mount -rw /
# mount -rw /dev/sd0f /usr

Our fstab says a0e97b069eed0743.f is used for /usr so we mount /dev/sd0f to /usr. Also, TERM=vt220 will allow us to use text editors like vi to edit (you could, of course, use ed).

# export TERM=vt220
# vi /etc/fstab

Replace f433d9e11879420f.b with f433d9e11879420f.a, save and quit, then reboot the system:

# shutdown -r now