ZFS Pool Setup_

Extends the server installer design with a ZFS path: F8 on the disk picker switches from one UFS disk to a marked set of disks, which then get arranged into mirrors or raidz, given options, and reviewed before anything is erased.

PRELIMINARY · WILL BE REFINED TICKET U4 · userland#201 EPIC E14 · nextbsd#468 NEEDS Z0 · kernel#230 NEEDS A6 · userland#200 NO SWAP PARTITION
Preliminary design — not final. This draft is a starting point for the ZFS install path in U4 (nextbsd-userland#201), and it will be refined before implementation begins. Treat the screens, keys and defaults as proposals, not a spec.

1Where ZFS fits

ZFS is a branch off the existing disk picker, not a new installer. UFS stays the default and its path is unchanged: one disk, whole-disk install.

Install Mode Disk Picker F8 · ZFS Pool Layout Pool Options Review Account & Hostname Install

2Disk Picker · F8 switches the filesystem

A filesystem line sits above the disk list. In UFS mode the picker behaves exactly as it does now: one disk, Enter to select.

PHASE 2 · UFS MODE (DEFAULT)
┌────────────────────────  Select Install Disk  ─────────────────────────┐
                                                                        
   The selected disk will be ERASED in full.  Pick a target:            
                                                                        
   Filesystem:  [ UFS ]   ZFS                            F8 switch      
                                                                        
     ▸ ada0   238 GB   Samsung SSD 860 EVO                              
       ├─ "BACKUP"        212 GB   ufs                                  
       └─ "EFI"           260 MB   fat32  (ESP)                         
                                                                        
       ada1   931 GB   WDC WD10EZEX-08WN4A0                             
       └─ "vault"         931 GB   zfs    (zpool: tank)                 
                                                                        
       ada2   238 GB   Samsung SSD 860 EVO                              
                                                                        
       da0     15 GB   SanDisk Ultra USB  (install media)               
                                                                        
   Enter selects · F8 switches to ZFS · da0 is locked (booted from)     
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                  < Select >      < Back >    < Rescan >                
└────────────────────────────────────────────────────────────────────────┘

F8 switches to ZFS mode. Every row gains a checkbox, Space marks or unmarks the highlighted disk, and Enter moves on to lay out the pool.

PHASE 2 · ZFS MODE (AFTER F8)
┌─────────────────────────  Select Pool Disks  ──────────────────────────┐
                                                                        
   Mark every disk for the pool.  Marked disks are ERASED.              
                                                                        
   Filesystem:   UFS   [ ZFS ]                           F8 switch      
                                                                        
   [x]  ada0   238 GB   Samsung SSD 860 EVO                             
         ├─ "BACKUP"      212 GB   ufs                                  
         └─ "EFI"         260 MB   fat32  (ESP)                         
                                                                        
     [x]  ada1   931 GB   WDC WD10EZEX-08WN4A0                          
         └─ "vault"       931 GB   zfs    (zpool: tank)                 
                                                                        
   [x]  ada2   238 GB   Samsung SSD 860 EVO                             
                                                                        
    ·   da0     15 GB   SanDisk Ultra USB  (install media)              
                                                                        
   3 disks marked · 1,407 GB raw                                        
   Space marks · Enter lays out the pool · F8 back to UFS               
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                 < Continue >      < Back >    < Rescan >               
└────────────────────────────────────────────────────────────────────────┘

3Pool Layout · arrow disks into vdevs

Two panes: the marked disks on the left and the pool's vdevs on the right. moves the highlighted disk into the highlighted vdev, and takes it back out. The usable size and failure tolerance update as you go.

PHASE 3 · LAYOUT IN PROGRESS
┌─────────────────────  ZFS Pool Layout  ·  zroot  ──────────────────────┐
                                                                        
   Move disks into vdevs with ← →.  T cycles the vdev type.             
                                                                        
  MARKED DISKS                     POOL zroot                          
                                                                       
    ada1   931 GB  WDC WD10EZEX    ▾ vdev 1   mirror      238 GB       
                                        ada0   238 GB  Samsung 860     
                                        ada2   238 GB  Samsung 860     
                                                                       
                                   + new vdev          (N)             
                                                                        
   Usable ≈ 238 GB · survives 1 disk failure in vdev 1                  
   ! ada1 is marked but not in the pool — move it in, or unmark it.     
                                                                        
   ↑↓ move · → into vdev · ← out · Tab pane · T type · N new · D delete 
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                        < Continue >    < Back >                        
└────────────────────────────────────────────────────────────────────────┘

T cycles the highlighted vdev's type. Here four disks were moved into one vdev and cycled to raidz2:

PHASE 3 · RAIDZ2, READY
┌─────────────────────  ZFS Pool Layout  ·  zroot  ──────────────────────┐
                                                                        
  MARKED DISKS                     POOL zroot                          
                                                                       
    (all disks placed)             ▾ vdev 1   raidz2      1.86 TB      
                                        ada0   931 GB  WDC WD10EZEX    
                                        ada1   931 GB  WDC WD10EZEX    
                                        ada2   931 GB  WDC WD10EZEX    
                                        ada3   931 GB  WDC WD10EZEX    
                                                                       
                                   + new vdev          (N)             
                                                                        
   Usable ≈ 1.86 TB · survives any 2 disk failures                      
   T:  single → mirror → raidz1 → raidz2 → raidz3                       
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                        < Continue >      < Back >                      
└────────────────────────────────────────────────────────────────────────┘
KeyAction
Move the cursor within a pane
TabSwitch between the disk pane and the pool pane
Move the highlighted disk into the highlighted vdev
Move a disk out of its vdev, back to the marked list
TCycle the vdev type: single → mirror → raidz1 → raidz2 → raidz3
NAdd a new vdev (for striping several mirrors or raidz groups)
DDelete the highlighted vdev; its disks return to the marked list
Enter / EscContinue when the layout is valid / back to the disk picker
Vdev typeMinimum disksSurvivesSource
single1 (exactly)no disk failureSeveral singles = a stripe; shown with a warning
mirror2all but one diskUsable = the smallest disk
raidz12 — 3 recommended1 diskvdev_children < nparity + 1 is rejected in vdev_raidz_open(), and zpool's is_grouping() sets mindev = nparity + 1
raidz23 — 4+ recommended2 disks
raidz34 — 5+ recommended3 disks

4Pool Options

PHASE 4 · POOL OPTIONS
┌──────────────────────────  ZFS Pool Options  ──────────────────────────┐
                                                                        
   Pool name          [ zroot            ]                              
                                                                        
   Sector size        ashift 12 (4 KiB)        auto from disks          
                                                                        
   Compression        ( ) off   (•) lz4   ( ) zstd                      
                                                                        
   Encrypt user data  [x] zroot/Users  — passphrase at boot             
        Passphrase    [ ••••••••••••     ]                              
        Confirm       [ ••••••••••••_    ]                              
                                                                        
   The system itself stays unencrypted: the loader reads ZFS but        
   cannot decrypt it. Swap is encrypted by the pager, and crash         
   dumps with dumpon -k.                                                
                                                                        
   ↑↓ field · Space toggles · Tab next · Enter continues                
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                        < Continue >      < Back >                      
└────────────────────────────────────────────────────────────────────────┘

5Review · nothing is written until Install

Continuing the first layout example after ada1 was unmarked: a two-disk mirror. The review names every volume that will be destroyed, disk by disk.

PHASE 5 · REVIEW
┌────────────  Review  ·  nothing is written until Install  ─────────────┐
                                                                        
   POOL      zroot · mirror (ada0, ada2) · ≈ 238 GB · 1 failure         
   EACH DISK gpt: efi 260 MB · freebsd-zfs rest · no swap               
                                                                        
   DATASETS  zroot/ROOT/default        /                                
             zroot/private             /private       canmount=off      
             zroot/private/var         /private/var   canmount=off      
             zroot/private/var/vm      swap + corefile                  
             zroot/private/var/crash   savecore output                  
             zroot/Users               /Users         encrypted         
                                                                        
   ERASES    ada0  "BACKUP" "EFI"     ada2  (no volumes)                
                                                                        
├────────────────────────────────────────────────────────────────────────┤
                        < Install >      < Back >                       
└────────────────────────────────────────────────────────────────────────┘

Roughly what the engine runs for the mirror above. It is illustrative, not the engine code:

ENGINE · ILLUSTRATIVE
# each disk: EFI system partition + ZFS, no swap
gpart create -s gpt ada0
gpart add -t efi -s 260m -l efi0 ada0
gpart add -t freebsd-zfs -l zfs0 ada0          # same for ada2 -> efi2 / zfs2

zpool create -o ashift=12 -O compression=lz4 -O atime=off \
      -O canmount=off -O mountpoint=none -R /mnt \
      zroot mirror gpt/zfs0 gpt/zfs2

zfs create -o canmount=off -o mountpoint=none zroot/ROOT
zfs create -o mountpoint=/ zroot/ROOT/default
zfs create -o canmount=off -o mountpoint=/private zroot/private
zfs create -o canmount=off zroot/private/var
zfs create -o checksum=off -o compression=off -o dedup=off -o copies=1 \
      -o recordsize=128K -o encryption=off \
      -o com.sun:auto-snapshot=false zroot/private/var/vm
zfs create -o exec=off -o setuid=off zroot/private/var/crash
zfs create -o encryption=on -o keyformat=passphrase \
      -o keylocation=prompt -o mountpoint=/Users zroot/Users
zpool set bootfs=zroot/ROOT/default zroot

6What this depends on

NeedsWhy
Z0 · kernel#230ZFS compiled into the kernel, plus zfs/zpool in the image. Today they exist only in /rescue.
A6 · userland#200Without /etc/fstab or rc.d, nothing mounts the datasets beyond zroot/ROOT/default, and nothing prompts for the zroot/Users passphrase.
U2 · userland#179This design supplies the dataset layout that U2 creates.
Z3 · Z4Swapify needs zroot/private/var/vm with exactly these properties. Z4 skips it during recursive snapshots.

7Open decisions — to settle while refining