How to mount external ZFS file system without clobbering/altering current or external filesystem

mountzfs

I am using FreeBSD 10.2 using ZFS on root as the file system (zroot01). I have an external hard disk with a ZFS file system from another FreeBSD 10.2 system (zroot02) that I want to temporarily mount, read only, so I can get some files off of it, then disconnect it afterward. I don't want the external ZFS system to clobber or replace my current file system, nor do I want the data on the external to be corrupted/altered either.

To demonstrate what I'm trying to accomplish, if I was using UFS I'd do something like this:

mount -t ufs -o ro /dev/ada0s2 /mnt/my-fun-mountpoint

…where /dev/ada0s2 is the partition on my external drive and /mnt/my-fun-mountpoint is in the /mnt directory of my existing operating system.

All of the searching and man page reading has not provided a crystal-clear method for doing so. What answers I did find ended up taking over my current file system and corrupting it beyond repair — obviously not the result I'm looking for. I attempted this a while ago so I don't remember which commands I tried, unfortunately.

Can you please provide some clear guidance on how to do this? Thank you in advance for your help.

Best Answer

Well, it really depends on how read-only you want the pool to be. And no, that's not a joke.

First, a bit of terminology: in ZFS, you import a pool, and optionally mount the (any) file systems within it. You can import a pool without mounting any file systems by passing -N to zpool import and then later on mount any desired file systems using zfs mount. (This is a perfectly valid scenario if, for example, you want to access only a single file system out of many, or if you want to do something resembling an off-line scrub of the pool.)

ZFS isn't a big fan of truly read-only access. For example, if ZFS detects an error that it is able to repair, I believe it will repair the error and write the repaired data to disk even if you imported the pool as read-only. My understanding is that, in ZFS parlace, "read-only" applies only to the user-visible state of the pool and its datasets. If, on the other hand, you make a binary copy of the disk to a file (or set of files), make those files truly read only, and try to import the pool from there, ZFS won't be able to import the pool at all no matter how hard you try. If you make the files writable, it will work fine. (I actually tried this just a few weeks ago, albeit using a zvol, and ZFS vehemently refused to import the pool. When I set the zvol to read/write instead of read-only, the pool imported fine.) Other file systems like (on Linux) ext4 and probably others handle this situation somewhat gracefully, but ZFS balks.

If you are unlucky, and don't have ECC RAM installed in the system where you are importing the pool, then ZFS' attempting to correct any errors it encounters might actually make things worse, although opinions differ on whether this is actually a real risk in practice. Personally I am of the opinion that any data I care enough about to protect with ZFS and snapshots and storage-level redundancy and backups and whatnot deserves the protection offered by ECC RAM also, but many PCs don't have ECC RAM.

So, you can import the pool in read-only mode, with a specific alternate root to keep it from stepping on anything else's toes, but you need to be aware that it isn't necessarily truly read-only in a forensic sense. (It will, however, ensure that you don't accidentally change anything in the pool.) To do a read-only import, assuming that the pool is named tank and that the device node(s) is/are available in /dev, you would use a command like:

# zpool import tank -d /dev -o readonly=on -R /mnt/someplace

This will look in /dev for anything holding a ZFS pool with the name tank, import it, temporarily setting the pool property readonly to on (which means that all user-initiated writes will be rejected) and temporarily setting its altroot property to /mnt/someplace. (These property values are "temporary" in the sense that they are not persisted to the disk(s) as current property values, so if you export and re-import the pool without them, the values will be back to normal. They might possibly be written to the pool history though, which once the pool is imported you can look at with zpool history tank if you are so inclined.) Once the pool is imported, you will see your files under /mnt/someplace and have normal, read-only access to them, including any snapshots that are already made on the datasets in the pool.

Given your example, I suspect that you would use something along the lines of:

# zpool import zroot02 -d /dev -o readonly=on -R /mnt/my-fun-mountpoint

When you are done, remember to cleanly export the pool:

# zpool export tank

or perhaps

# zpool export zroot02

That will unmount all file systems and other datasets within the pool, flush all buffers (to the extent that any need flushing in the first place), mark the pool as not imported on all constituent devices, and perform any other necessary housekeeping tasks to ensure that the pool can safely be moved to a different system and imported there later.

Related Question