Introduction
Using ZFS on an external drive
flash drive

Using ZFS on an external drive

This tutorial will teach you how to put ZFS on your external SSD/HDD/flash drive. Note that all the steps below were tested on FreeBSD 13.2-RELEASE. I will briefly introduce ZFS and describe each step in a bit of detail. If you are impatient, you can skip to the summary at the end of this post.

What is ZFS?

ZFS, or the Zettabyte File System, as it was previously known, is a combined file system and logical volume manager. Traditionally, file systems have a 1:1 mapping to disk partitions. For example, if you have a disk with three parititons, then each of those paritions needs its own, separate file system.

A logical volume manager can abstract different disks and/or parititions and present them as logical storage units on which you can put your file system. In other words, a file system can span multiple partitions or disks. ZFS is an all-in-one solution that does both of these functions for you: logical volume management and the actual file system.

Basic ZFS terminology and concepts

This is not meant to be comprehensive (or even accurate), but there are a few things you should know about how ZFS is different from traditional file systems:

  • In ZFS terminology, a file system is called a dataset.
  • You combine one or more disks to form a zpool. A zpool is a logical container for all of your storage space. You can then create one or more datasets from that zpool.
  • zpool management is done with the zpool command, while dataset management is done with the zfs command.
  • Unlike traditional partitions, you do not have to set a predefined size for your datasets. A dataset can use as much storage space as is available in your zpool.

Creating the zpool

For this demo, I'm going to use a 128GB USB flash drive. Insert your drive into an available USB port on your machine and check its device name with dmesg:

# dmesg
...
ugen1.5: <SanDisk Ultra> at usbus1
umass0 on uhub1
umass0: <SanDisk Ultra, class 0/0, rev 3.00/1.00, addr 5> on usbus1
umass0:  SCSI over Bulk-Only; quirks = 0xc100
umass0:0:0: Attached to scbus0
da0 at umass-sim0 bus 0 scbus0 target 0 lun 0
da0: <SanDisk Ultra 1.00> Removable Direct Access SPC-4 SCSI device
da0: Serial Number 4C530000110623109545
da0: 400.000MB/s transfers
da0: 117312MB (240254976 512 byte sectors)
da0: quirks=0x2<NO_6_BYTE>

Here, da0 is our flash drive. Remember, before we can create a dataset (file system), we must have a zpool to allocate the storage from. We want to use the entire space on /dev/da0 (as opposed to a partition/slice like /dev/da0s1) as part of our zpool, so let's create the zpool and add da0 to it (this will destroy data on the drive, so make sure you back it up first):

# zpool create myexternalpool /dev/da0

I named the zpool myexternalpool, but you can use any other identifier you want. You can confirm the creation of the pool with the list and status sub-commands:

# zpool list
NAME             SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
myexternalpool   114G   384K   114G        -         -     0%     0%  1.00x    ONLINE  -
zroot            472G   115G   357G        -         -     6%    24%  1.00x    ONLINE  -
# zpool status myexternalpool
  pool: myexternalpool
 state: ONLINE
config:

	NAME            STATE     READ WRITE CKSUM
	myexternalpool  ONLINE       0     0     0
	  da0           ONLINE       0     0     0

errors: No known data errors

zroot in this case is the name of my machine's main zpool (composed of a single SSD).

Creating a dataset

Now that we have a pool to allocate storage from, let's create a file system (dataset) to store our files on:

# zfs create myexternalpool/myexternaldataset

By default, your new file system will be mounted at /<pool_name>/<dataset_name>/. In our case, that would be /myexternalpool/myexternaldataset/. This can also be confirmed in the output of the zfs list command (MOUNTPOINT column) or the zfs get mountpoint command:

# zfs list
NAME                                           USED  AVAIL     REFER  MOUNTPOINT
myexternalpool                                 704K   110G      104K  /myexternalpool
myexternalpool/myexternaldataset                96K   110G       96K  /myexternalpool/myexternaldataset
zroot                                          115G   343G       96K  /zroot
zroot/ROOT                                    29.9G   343G       96K  none
...
# zfs get mountpoint myexternalpool/myexternaldataset
NAME                              PROPERTY    VALUE                              SOURCE
myexternalpool/myexternaldataset  mountpoint  /myexternalpool/myexternaldataset  default

You can create multiple datasets if you want, but for the purposes of this demo, one will suffice. Go ahead and create some files on your shiny new file system:

# touch /myexternalpool/myexternaldataset/woofwoof.txt
# touch /myexternalpool/myexternaldataset/meow.txt
# ls /myexternalpool/myexternaldataset/
meow.txt	woofwoof.txt

zpool export and import

Before you unplug your external drive, it is important, or even crucial, that you export the zpool first. To simplify things, you can think of exporting a pool as making it "ready to be migrated to another machine". Likewise, in order to access your data the next time you plug your drive in, you must import the pool first.

Since we just created a couple of empty text files on our dataset, let's do a zpool export:

# zpool export myexternalpool
# zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
zroot   472G   115G   357G        -         -     6%    24%  1.00x    ONLINE  -

Unplug your drive and plug it back in. Check dmesg to see your device name again (for the purposes of this demo, I first plugged in another USB flash drive so that our external ZFS drive gets a different device name than da0):

# dmesg
...
ugen1.6: <SanDisk Ultra> at usbus1
umass1 on uhub1
umass1: <SanDisk Ultra, class 0/0, rev 3.00/1.00, addr 8> on usbus1
umass1:  SCSI over Bulk-Only; quirks = 0xc100
umass1:1:1: Attached to scbus1
da1 at umass-sim1 bus 1 scbus1 target 0 lun 0
da1: <SanDisk Ultra 1.00> Removable Direct Access SPC-4 SCSI device
da1: Serial Number 4C530000110623109545
da1: 400.000MB/s transfers
da1: 117312MB (240254976 512 byte sectors)
da1: quirks=0x2<NO_6_BYTE>

Now import the pool:

# zpool import -d /dev/da1 myexternalpool
# zpool list
NAME             SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
myexternalpool   114G  1.01M   114G        -         -     0%     0%  1.00x    ONLINE  -
zroot            472G   115G   357G        -         -     6%    24%  1.00x    ONLINE  -
# zfs list
NAME                                           USED  AVAIL     REFER  MOUNTPOINT
myexternalpool                                1.01M   110G      104K  /myexternalpool
myexternalpool/myexternaldataset               104K   110G      104K  /myexternalpool/myexternaldataset
zroot                                          115G   343G       96K  /zroot
zroot/ROOT                                    29.9G   343G       96K  none
...
# ls -l /myexternalpool/myexternaldataset/
total 2
-rw-r--r--  1 root  wheel  0 Oct 29 06:58 meow.txt
-rw-r--r--  1 root  wheel  0 Oct 29 06:58 woofwoof.txt

And voila!

Summary

# echo "Create a zpool from the external drive"
# zpool create <poolname> /dev/<devicename>
# echo "Create a dataset on our pool"
# zfs create <poolname>/<datasetname>
# echo "Your dataset is now mounted at /<poolname>/<datasetname>/"
# echo "Write data to your dataset"
# echo "test" > /<poolname>/<datasetname>/sample.txt
# echo "Read data from your dataset"
# cat /<poolname>/<datasetname>/sample.txt
# echo "Before unplugging your drive, export the pool first"
# zpool export <poolname>
# echo "Next time you plug it in, import it first"
# zpool import -d /dev/<devicename> <poolname>
Author

binshdev

View Comments
Next Post

DNS queries with drill

Subscribe to binsh.dev

Subscribe to our newsletter and receive access to exclusive posts and content updates. We don't spam and your email won't be shared with third-parties.

Thanks for subscribing!

Check your inbox to confirm your subscription.

Please enter a valid email address!