0

I have two Linux (NixOS) machines that I would like to share an encrypted ZFS-formatted portable USB hard drive. I've gotten this to work fine for a single machine, but I may have destroyed the ZFS filesystem on the drive when I tried mounting it on my 2nd machine.

Before moving the USB drive from one machine to the other, I exported the zpool to unmount it. I was hoping I could import the zpool from the drive on the second machine, but I may have misunderstood ZFS's concept of a zpool. I was unable to get my 2nd machine to see the ZFS drive at all with various combinations of zpool list, zpool import -a, zpool import -D, etc. The drive was definitely showing up as /dev/sdb, but ZFS's auto-detection on this 2nd machine was simply ignoring it for mysterious reasons.

Eventually I did a simple sudo zpool create z /dev/sdb, thinking the zpool was entirely a virtual thing that I needed to mirror on this machine, but I think this command overwrote the original ZFS filesystems on this drive with no warning. The drive is now an empty unencrypted filesystem and I'm unsure if it's even possible to recover my data from it. I fortunately did have backups, so it's not a total loss.

Two questions:

  1. Does creating a new zpool atop an existing vdev irreversibly destroy any previous ZFS filesystems on that device?

  2. How can one import an existing encrypted ZFS drive zpool from one machine to another, importing all the original zpool configuration options such as compression, encryption, datasets, etc? If it's not zpool import, what is it?

1 Answer 1

0

I presume you've answered your first question by way of your experiment: yes, doing a zpool create clobbers any existing pool on the affected vdevs.

Given that you're working on ensuring compatibility between the systems you want to share this pool, I'd suggest you forego the encryption until you are certain that you have the mechanics of the zpool structure correct and that there are no underlying blockages that could keep your tests from succeeding.

With that said, one of the necessary conditions for ZFS pools to be portable across systems is that the block devices that comprise the pool (and which are encoded in the pool metadata) must be unambiguous across any systems where the pool is to be imported. This makes it unwise to use bare physical devices like /dev/sdb, etc. Better is to create a partition on each drive to be used, and to assign a unique label to each partition that is used. The drive's serial number is often a convenient string to use, since it will be electronically visible not only in the pool metadata, but also in the blkid output, and humanly visible upon inspection of the physical drive chassis.

So if the hard drive's serial number is 6SL0CTD, you should create a partition on that drive and label it zfs-data-6SL0CTD. Then create the pool referencing that logical device (instead of the possibly variable physical device):

# zpool create tank /dev/disk/by-partlabel/zfs-data-6SL0CTCD

Also, read the man page for zpool import, and note that there are a lot of non-destructive tools you can use when you're not sure what you're importing (or why it won't import):

With no parameters:

# zpool import

shows you any pool(s) that may be available to import. I don't have a test case at hand, but I believe it will also show pools which cannot be imported, typically because of missing or failed devices. One cause of a "missing" device can be because the pool metadata says that /dev/sdb is to be used, but the host already has a /dev/sdb, and that device does not contain metadata matching the pool. Again, this is why assigning partition labels and creating pools based solely on partition labels is important. If that partition label is present, the pool will be found, and it won't matter what physical device that partition appears on.

# zpool import -N tank

Imports the pool tank but does not mount any filesystems from it. This can be used as a second-level check of the pool. Although nothing is mounted, the pool's statistics can be inspected, the pool can be scrubbed, etc.

Once you've got your pool created correctly so that it uses unambiguous device names, you can see in hindsight why this may be important.

zpool status -P will show the full, logical path of all devices in the pool:

# zpool status -P
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 21h34m with 0 errors on Sun Oct 10 21:58:23 2021
config:

    NAME                                            STATE     READ WRITE CKSUM
    tank                                          ONLINE       0     0     0
      /dev/disk/by-partlabel/zfs-data-6SL0CTCD    ONLINE       0     0     0

errors: No known data errors

Conversely, zpool status -L will show the physical device name of all devices in the pool:

# zpool status -L
  pool: tank
 state: ONLINE
  scan: scrub repaired 0B in 21h34m with 0 errors on Sun Oct 10 21:58:23 2021
config:

    NAME                                            STATE     READ WRITE CKSUM
    tank                       ONLINE       0     0     0
      sdb1                     ONLINE       0     0     0

errors: No known data errors

The end result of using partition labels instead of physical device nodes, is that the output of zpool status -P will be identical on all machines that import the pool, whereas the output zpool status -L may well differ. Which in turn is why the zpool create command needs to be written in terms of non-variant logical devices which are guaranteed to be unambiguous across all machines that might need to import the pool.

Once you've got the pool structured in terms of unambiguous device names, applying encryption to the zpool should be straightforward, assuming that you have reasonably similar ZFS stacks on the hosts that need to be able to import the pool.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.