I now have a Dell R7425 with 12 x 12TB HDD in the basement.
A raidz2 zpool would give me about 120TB – with a significant resilver time.
I have also thought about a creating 6 x mirrors and striping across them. That would give me about 72TB – that’s still a lot.
However I do it, I’m going to label the partitions with the drive slot and serial number. I’m going to write a little helper script. I’m guessing by the time I finish writing this blog post, I could have done the labelling manually. However, if I have to redo the labelling because I messed up, I think that’s where the script will pay off.
Some background
This is the zpool status from r730-03:
[16:42 r730-03 dvl ~] % zpool status pool: data01 state: ONLINE scan: scrub repaired 0B in 1 days 04:29:00 with 0 errors on Fri May 29 08:31:09 2026 config: NAME STATE READ WRITE CKSUM data01 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 gpt/SEAG_ZJV4HFPE ONLINE 0 0 0 gpt/SEAG_ZHZ16KEX ONLINE 0 0 0 mirror-1 ONLINE 0 0 0 gpt/SG_ZHZ03BAT ONLINE 0 0 0 gpt/HGST_8CJW1G4E ONLINE 0 0 0 mirror-2 ONLINE 0 0 0 gpt/SG_ZL2NJBT2 ONLINE 0 0 0 gpt/HGST_5PGGTH3D ONLINE 0 0 0 errors: No known data errors pool: zroot state: ONLINE status: Some supported and requested features are not enabled on the pool. The pool can still be used, but some features are unavailable. action: Enable all features using 'zpool upgrade'. Once this is done, the pool may no longer be accessible by software that does not support the features. See zpool-features(7) for details. scan: scrub repaired 0B in 00:01:49 with 0 errors on Thu May 28 04:04:13 2026 config: NAME STATE READ WRITE CKSUM zroot ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 ada1p3 ONLINE 0 0 0 ada0p3 ONLINE 0 0 0 errors: No known data errors
Notice how the drives in data01 are labelled with the drive brand (e.g. Seagate) and the serial number (ZJV4HFPE).
This helps to correctly identify the drive you want to remove, should one need replacing.
These are the drives in the Dell R7425 (the hostname is r7425-01).
root@r7425-01:~ # sesutil show ses0: <DP BP14G+EXP 2.52>; ID: 500056b345a433ff Desc Dev Model Ident Size/Status Drive Slot 0 da0 ATA HGST HUH721212AL 8CGSV9DG Unknown Drive Slot 1 da1 ATA HGST HUH721212AL 8CGSXG6G Unknown Drive Slot 2 da2 ATA HGST HUH721212AL 8HGAWR3H Unknown Drive Slot 3 da3 ATA HGST HUH721212AL 8CGSVS3G Unknown Drive Slot 4 da4 ATA HGST HUH721212AL 8CGSB6YG Unknown Drive Slot 5 da5 ATA HGST HUH721212AL 8CGSZ0VG Unknown Drive Slot 6 da6 ATA HGST HUH721212AL 8CGSZY5G Unknown Drive Slot 7 da7 ATA HGST HUH721212AL 8CGSV8YG Unknown Drive Slot 8 da8 ATA HGST HUH721212AL 8CGS875G Unknown Drive Slot 9 da9 ATA HGST HUH721212AL 8CGSBA2G Unknown Drive Slot 10 da10 ATA HGST HUH721212AL 8CGSX4UG Unknown Drive Slot 11 da11 ATA HGST HUH721212AL 8CGSDEHG Unknown Drive Slot 12 da12 ATA ST1000NM0018-2F2 ZFA0NVQD Unknown Drive Slot 13 - - - Not Installed Drive Slot 14 da13 ATA MTFDDAK480TDN 191821E45D17 Unknown Drive Slot 15 da14 ATA MTFDDAK480TDN 191821E45DA1 Unknown Drive Slot 16 - - - Not Installed Drive Slot 17 - - - Not Installed
Some notes:
- Slots 0-11 are in the front of the chassis. They are the main data drives and are the subjects of this blog post.
- Slot 12 is mounted in the rear of the chassis and is a 1TB drive
- slots 14-15 are 2.5″ SSDs mounted internally – they contain the zroot
From the past
I went searching my blog for zpool create and found Copying everything off a zpool, destroying it, creating a new one, and copying everything back – in there, I found this command:
sudo gpart add -a 4K -i 1 -t freebsd-zfs -s 1953520000 -l S59VNS0N809087J_S00 da0
Let’s write a script to output that.
Listing the drives
This is my starting point:
root@r7425-01:~ # sesutil show | grep 'Drive Slot' | grep -vE 'Drive Slot (12|13|14|15|16|17)' Drive Slot 0 da0 ATA HGST HUH721212AL 8CGSV9DG Unknown Drive Slot 1 da1 ATA HGST HUH721212AL 8CGSXG6G Unknown Drive Slot 2 da2 ATA HGST HUH721212AL 8HGAWR3H Unknown Drive Slot 3 da3 ATA HGST HUH721212AL 8CGSVS3G Unknown Drive Slot 4 da4 ATA HGST HUH721212AL 8CGSB6YG Unknown Drive Slot 5 da5 ATA HGST HUH721212AL 8CGSZ0VG Unknown Drive Slot 6 da6 ATA HGST HUH721212AL 8CGSZY5G Unknown Drive Slot 7 da7 ATA HGST HUH721212AL 8CGSV8YG Unknown Drive Slot 8 da8 ATA HGST HUH721212AL 8CGS875G Unknown Drive Slot 9 da9 ATA HGST HUH721212AL 8CGSBA2G Unknown Drive Slot 10 da10 ATA HGST HUH721212AL 8CGSX4UG Unknown Drive Slot 11 da11 ATA HGST HUH721212AL 8CGSDEHG Unknown root@r7425-01:~ #
Let’s save that into a file:
root@r7425-01:~ # sesutil show | grep 'Drive Slot' | grep -vE 'Drive Slot (12|13|14|15|16|17)' > data_drives root@r7425-01:~ # cat data_drives Drive Slot 0 da0 ATA HGST HUH721212AL 8CGSV9DG Unknown Drive Slot 1 da1 ATA HGST HUH721212AL 8CGSXG6G Unknown Drive Slot 2 da2 ATA HGST HUH721212AL 8HGAWR3H Unknown Drive Slot 3 da3 ATA HGST HUH721212AL 8CGSVS3G Unknown Drive Slot 4 da4 ATA HGST HUH721212AL 8CGSB6YG Unknown Drive Slot 5 da5 ATA HGST HUH721212AL 8CGSZ0VG Unknown Drive Slot 6 da6 ATA HGST HUH721212AL 8CGSZY5G Unknown Drive Slot 7 da7 ATA HGST HUH721212AL 8CGSV8YG Unknown Drive Slot 8 da8 ATA HGST HUH721212AL 8CGS875G Unknown Drive Slot 9 da9 ATA HGST HUH721212AL 8CGSBA2G Unknown Drive Slot 10 da10 ATA HGST HUH721212AL 8CGSX4UG Unknown Drive Slot 11 da11 ATA HGST HUH721212AL 8CGSDEHG Unknown root@r7425-01:~ #
gpart create
Next, let’s compose a command to create gpart partitions on each drive.
NOTE, this command creates the partitions, it’s not echoing out the commands for you to run that.
root@r7425-01:~ # cat data_drives | cut -f 4 -w | xargs -n 1 -I % gpart create -s gpt % da0 created da1 created da2 created da3 created da4 created da5 created da6 created da7 created da8 created da9 created da10 created da11 created root@r7425-01:~ #
Next, let’s create a partition, and label it with the drive slot and the serial number.
Partition size?
On FreeBSD, it has been routine procedure to partition the drive and use a partition for the vdev, not the whole raw device. I recall reading the reasoning behind that. I will continue with that routine.
For that, I need to know drive size, and let’s look at this command for that information:
root@r7425-01:~ # diskinfo -v da0 da0 512 # sectorsize 12000138625024 # mediasize in bytes (11T) 23437770752 # mediasize in sectors 4096 # stripesize 0 # stripeoffset 1458933 # Cylinders according to firmware. 255 # Heads according to firmware. 63 # Sectors according to firmware. ATA HGST HUH721212AL # Disk descr. 8CGSV9DG # Disk ident. mpr0 # Attachment id1,enc@n500056b345a433fd/type@0/slot@1/elmdesc@Drive_Slot_0 # Physical path No # TRIM/UNMAP support 7200 # Rotation rate in RPM Not_Zoned # Zone Mode root@r7425-01:~ #
We have 23,437,770,752 sectors (mediasize in sectors), each one being 512 bytes (sectorsize)
I’m going to leave 2.5M free at the end of that drive, just in case any replacement drive comes up a little bit short. 2.5M is 2,621,440 bytes. 2,621,440 bytes / 512 bytes per sector is 5,120 sectors.
The size on the gpart command will be 23,437,770,752 – 5,120 = 23,437,765,632
The partition add
The script I came up with is. This command echos the commands you want to run later.
root@r7425-01:~ # cat data_drives | awk '{ print "gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_" $3 "_" $8 " " $4 }'
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_0_8CGSV9DG da0
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_1_8CGSXG6G da1
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_2_8HGAWR3H da2
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_3_8CGSVS3G da3
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_4_8CGSB6YG da4
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_5_8CGSZ0VG da5
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_6_8CGSZY5G da6
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_7_8CGSV8YG da7
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_8_8CGS875G da8
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_9_8CGSBA2G da9
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_10_8CGSX4UG da10
gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_11_8CGSDEHG da11
Let’s try running that first command:
root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_0_8CGSV9DG da0
da0p1 added
root@r7425-01:~ # gpart show da0
=> 40 23437770672 da0 GPT (11T)
40 23437765632 1 freebsd-zfs (11T)
23437765672 5040 - free - (2.5M)
root@r7425-01:~ # gpart show -l da0
=> 40 23437770672 da0 GPT (11T)
40 23437765632 1 slot_0_8CGSV9DG (11T)
23437765672 5040 - free - (2.5M)
root@r7425-01:~ # ls -l /dev/gpt
total 0
crw-r----- 1 root operator 0xd1 May 30 16:27 efiboot0
crw-r----- 1 root operator 0xc5 May 30 16:27 efiboot1
crw-r----- 1 root operator 0xf5 May 30 17:34 slot_0_8CGSV9DG
root@r7425-01:~ #
That looks right. Let’s run the rest:
root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_1_8CGSXG6G da1 da1p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_2_8HGAWR3H da2 da2p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_3_8CGSVS3G da3 da3p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_4_8CGSB6YG da4 da4p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_5_8CGSZ0VG da5 da5p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_6_8CGSZY5G da6 da6p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_7_8CGSV8YG da7 da7p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_8_8CGS875G da8 da8p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_9_8CGSBA2G da9 da9p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_10_8CGSX4UG da10 da10p1 added root@r7425-01:~ # gpart add -a 4K -i 1 -t freebsd-zfs -s 23437765632 -l slot_11_8CGSDEHG da11 da11p1 added root@r7425-01:~ # ls -l /dev/gpt total 0 crw-r----- 1 root operator 0xd1 May 30 16:27 efiboot0 crw-r----- 1 root operator 0xc5 May 30 16:27 efiboot1 crw-r----- 1 root operator 0xf5 May 30 17:34 slot_0_8CGSV9DG crw-r----- 1 root operator 0x135 May 30 17:36 slot_10_8CGSX4UG crw-r----- 1 root operator 0x13b May 30 17:36 slot_11_8CGSDEHG crw-r----- 1 root operator 0xff May 30 17:36 slot_1_8CGSXG6G crw-r----- 1 root operator 0x105 May 30 17:36 slot_2_8HGAWR3H crw-r----- 1 root operator 0x10b May 30 17:36 slot_3_8CGSVS3G crw-r----- 1 root operator 0x111 May 30 17:36 slot_4_8CGSB6YG crw-r----- 1 root operator 0x117 May 30 17:36 slot_5_8CGSZ0VG crw-r----- 1 root operator 0x11d May 30 17:36 slot_6_8CGSZY5G crw-r----- 1 root operator 0x123 May 30 17:36 slot_7_8CGSV8YG crw-r----- 1 root operator 0x129 May 30 17:36 slot_8_8CGS875G crw-r----- 1 root operator 0x12f May 30 17:36 slot_9_8CGSBA2G
So far so good.
The zpool create
I thought about this.. how best to mirror the drives. The drives are stacked 3 high and 4 across. I thought: put mirrored drives right beside each other. Would that help with future tasks?
Then I thought: hell, no, that might take some interesting maneuvers in the zpool create command…. Let’s keep this part simple.
Next, so I did not have to copy / paste the device names, I did this:
root@r7425-01:~ # cat data_drives | awk '{ print "/dev/gpt/slot_" $3 "_" $8}'
/dev/gpt/slot_0_8CGSV9DG
/dev/gpt/slot_1_8CGSXG6G
/dev/gpt/slot_2_8HGAWR3H
/dev/gpt/slot_3_8CGSVS3G
/dev/gpt/slot_4_8CGSB6YG
/dev/gpt/slot_5_8CGSZ0VG
/dev/gpt/slot_6_8CGSZY5G
/dev/gpt/slot_7_8CGSV8YG
/dev/gpt/slot_8_8CGS875G
/dev/gpt/slot_9_8CGSBA2G
/dev/gpt/slot_10_8CGSX4UG
/dev/gpt/slot_11_8CGSDEHG
And yes, those all exist:
root@r7425-01:~ # cat data_drives | awk '{ print "/dev/gpt/slot_" $3 "_" $8}' | xargs ls -l
crw-r----- 1 root operator 0xf5 May 30 17:34 /dev/gpt/slot_0_8CGSV9DG
crw-r----- 1 root operator 0x135 May 30 17:36 /dev/gpt/slot_10_8CGSX4UG
crw-r----- 1 root operator 0x13b May 30 17:36 /dev/gpt/slot_11_8CGSDEHG
crw-r----- 1 root operator 0xff May 30 17:36 /dev/gpt/slot_1_8CGSXG6G
crw-r----- 1 root operator 0x105 May 30 17:36 /dev/gpt/slot_2_8HGAWR3H
crw-r----- 1 root operator 0x10b May 30 17:36 /dev/gpt/slot_3_8CGSVS3G
crw-r----- 1 root operator 0x111 May 30 17:36 /dev/gpt/slot_4_8CGSB6YG
crw-r----- 1 root operator 0x117 May 30 17:36 /dev/gpt/slot_5_8CGSZ0VG
crw-r----- 1 root operator 0x11d May 30 17:36 /dev/gpt/slot_6_8CGSZY5G
crw-r----- 1 root operator 0x123 May 30 17:36 /dev/gpt/slot_7_8CGSV8YG
crw-r----- 1 root operator 0x129 May 30 17:36 /dev/gpt/slot_8_8CGS875G
crw-r----- 1 root operator 0x12f May 30 17:36 /dev/gpt/slot_9_8CGSBA2G
Next, I went one step farther:
root@r7425-01:~ # cat data_drives | awk '{ print "/dev/gpt/slot_" $3 "_" $8}' | xargs -n 2 echo mirror
mirror /dev/gpt/slot_0_8CGSV9DG /dev/gpt/slot_1_8CGSXG6G
mirror /dev/gpt/slot_2_8HGAWR3H /dev/gpt/slot_3_8CGSVS3G
mirror /dev/gpt/slot_4_8CGSB6YG /dev/gpt/slot_5_8CGSZ0VG
mirror /dev/gpt/slot_6_8CGSZY5G /dev/gpt/slot_7_8CGSV8YG
mirror /dev/gpt/slot_8_8CGS875G /dev/gpt/slot_9_8CGSBA2G
mirror /dev/gpt/slot_10_8CGSX4UG /dev/gpt/slot_11_8CGSDEHG
That output now just needs a zpool create data01 in front of it. Let’s go.
Oh, that’s wrong. That failed. It created a zpool of two drives. I need trailing \ on each line.
I tried mucking about with the script. I failed. Instead, I copied the output to an editor, added the trailing \ and came up with this:
zpool create data01 \ mirror /dev/gpt/slot_0_8CGSV9DG /dev/gpt/slot_1_8CGSXG6G \ mirror /dev/gpt/slot_2_8HGAWR3H /dev/gpt/slot_3_8CGSVS3G \ mirror /dev/gpt/slot_4_8CGSB6YG /dev/gpt/slot_5_8CGSZ0VG \ mirror /dev/gpt/slot_6_8CGSZY5G /dev/gpt/slot_7_8CGSV8YG \ mirror /dev/gpt/slot_8_8CGS875G /dev/gpt/slot_9_8CGSBA2G \ mirror /dev/gpt/slot_10_8CGSX4UG /dev/gpt/slot_11_8CGSDEHG
And I ran it:
root@r7425-01:~ # zpool create data01 \ > mirror /dev/gpt/slot_0_8CGSV9DG /dev/gpt/slot_1_8CGSXG6G \ > mirror /dev/gpt/slot_2_8HGAWR3H /dev/gpt/slot_3_8CGSVS3G \ > mirror /dev/gpt/slot_4_8CGSB6YG /dev/gpt/slot_5_8CGSZ0VG \ > mirror /dev/gpt/slot_6_8CGSZY5G /dev/gpt/slot_7_8CGSV8YG \ > mirror /dev/gpt/slot_8_8CGS875G /dev/gpt/slot_9_8CGSBA2G \ > mirror /dev/gpt/slot_10_8CGSX4UG /dev/gpt/slot_11_8CGSDEHG root@r7425-01:~ #
And I have:
root@r7425-01:~ # zpool list NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT data01 65.4T 480K 65.4T - - 0% 0% 1.00x ONLINE - zroot 436G 1.14G 435G - - 0% 0% 1.00x ONLINE - root@r7425-01:~ # zpool status data01 pool: data01 state: ONLINE config: NAME STATE READ WRITE CKSUM data01 ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 gpt/slot_0_8CGSV9DG ONLINE 0 0 0 gpt/slot_1_8CGSXG6G ONLINE 0 0 0 mirror-1 ONLINE 0 0 0 gpt/slot_2_8HGAWR3H ONLINE 0 0 0 gpt/slot_3_8CGSVS3G ONLINE 0 0 0 mirror-2 ONLINE 0 0 0 gpt/slot_4_8CGSB6YG ONLINE 0 0 0 gpt/slot_5_8CGSZ0VG ONLINE 0 0 0 mirror-3 ONLINE 0 0 0 gpt/slot_6_8CGSZY5G ONLINE 0 0 0 gpt/slot_7_8CGSV8YG ONLINE 0 0 0 mirror-4 ONLINE 0 0 0 gpt/slot_8_8CGS875G ONLINE 0 0 0 gpt/slot_9_8CGSBA2G ONLINE 0 0 0 mirror-5 ONLINE 0 0 0 gpt/slot_10_8CGSX4UG ONLINE 0 0 0 gpt/slot_11_8CGSDEHG ONLINE 0 0 0 errors: No known data errors root@r7425-01:~ #











