ZPOOLPROPS(7)

๐Ÿฆ‹ zpoolprops ๐Ÿฆ‹

okay bestie, gather round, because this is the manual page for zpoolprops โ€” properties of ZFS storage pools โ€” and it's genuinely iconic. โœจ


๐Ÿ’– NAME ๐Ÿ’–

zpoolprops โ€” properties of ZFS storage pools ๐Ÿ’…


โœจ DESCRIPTION โœจ

So every single pool has a bunch of properties attached to it, right? Some of them are read-only stats โ€” you just look at them and vibe โ€” and others are configurable</>, meaning you can actually change how the pool behaves. ๐Ÿ‘‘

Also, quick note: user properties have literally zero effect on ZFS behavior. Not one. Use them to annotate your pools in a way that makes sense for your environment, bestie. If you want the full tea on user properties, scroll to the "User Properties" section. ๐Ÿ“


๐ŸŒธ the read-only properties ๐ŸŒธ

These ones are look-but-don't-touch. ๐Ÿ’–

  • allocated โ€” how much storage is used inside the pool. See fragmentation and free for more deets.
  • bcloneratio โ€” the ratio of the total storage you'd need to store every cloned block without cloning, versus the storage you're actually using. Calculated like this, no cap:
((bclonesaved + bcloneused) * 100) / bcloneused
  • bclonesaved โ€” the extra storage you would have needed if block cloning wasn't a thing. Savings, queen. ๐Ÿ’ฐ
  • bcloneused โ€” how much storage the cloned blocks are actually eating.
  • capacity โ€” the percentage of pool space used. You can also call it by its shortened column name, cap. โœจ
  • dedupcached โ€” total size of the deduplication table that's currently loaded into the ARC. See zpool-prefetch(8).
  • dedup_table_size โ€” total on-disk size of the deduplication table.
  • expandsize โ€” the amount of uninitialized space inside the pool or device that could be used to grow the pool's total capacity. On whole-disk vdevs, this is the space past the end of the GPT โ€” which typically happens when a LUN gets dynamically expanded, or when a disk gets swapped for a bigger one. On partition vdevs, it's the space appended to the partition after it was added to the pool โ€” most likely from resizing it in-place. You can claim that space for the pool by bringing it online with autoexpand=on or by using zpool online -e. ๐Ÿซถ
  • fragmentation โ€” how fragmented the pool is. The more space gets allocated, the harder it is to find free space, which can tank your write performance compared to pools with more unfragmented free space. it's giving messy room energy ๐Ÿ˜ญ
  • free โ€” how much free space is available in the pool. Okay but real talk: this is not the same as the zfs(8) available property, which tells you how much new data can be written to ZFS filesystems/volumes. The zpool free property is generally not useful for that purpose and can be substantially more than the zfs available space. Why the discrepancy? Several reasons, bestie: raidz parity; the zfs reservation, quota, refreservation, and refquota properties; and space set aside by spa_slop_shift (peep zfs(4) for more).
  • freeing โ€” when a file system or snapshot gets destroyed, the space it was using goes back to the pool asynchronously. freeing is how much space is still waiting to be reclaimed. Over time freeing goes down while free goes up. the way that it just... slowly heals ๐Ÿงš
  • guid โ€” a unique identifier for the pool.
  • health โ€” the pool's current health. It can be one of ONLINE, DEGRADED, FAULTED, OFFLINE, REMOVED, UNAVAIL.
  • last_scrubbed_txg โ€” tells you the transaction group (TXG) up to which the most recent scrub operation checked and repaired the dataset. Basically it gives you insight into your pool's data integrity status at a specific point in time. โœจ zpool-scrub(8) can use this property to scan only the data that's changed since the last scrub finished, when you pass it the -C flag. Heads up though: this property does not get updated when you do an error scrub with the -e flag.
  • leaked โ€” space that wasn't released during freeing because of corruption, so now it's permanently leaked into the pool. ๐Ÿ’€ rip.
  • load_guid โ€” a unique identifier for the pool. But unlike the guid property, this one gets generated every time we load the pool (so it does not persist across imports/exports) and it never changes while the pool is loaded โ€” even if a reguid operation happens.
  • size โ€” total size of the storage pool. ๐Ÿ“
  • unsupported@guid โ€” info about unsupported features that are enabled on the pool. See zpool-features(7) for the details.

Now, the space usage properties report the actual physical space available to the storage pool. That physical space can be different from the total amount of space any contained datasets can actually use. In a raidz configuration, how much space gets used depends on the characteristics of the data being written. On top of that, ZFS reserves some space for internal accounting that the zfs(8) command takes into account โ€” but the zpoolprops command does not. For non-full pools of a reasonable size, these effects should be invisible, bestie. But for small pools, or pools that are about to be completely full? These discrepancies may become way more noticeable. ๐Ÿ™ˆ


๐ŸŽ€ the property you can set at creation time and import time ๐ŸŽ€

  • altroot โ€” alternate root directory. If you set it, this directory gets prepended to any mount points inside the pool. Super handy when you're examining an unknown pool where the mount points can't be trusted, or in an alternate boot environment where the usual paths aren't valid. altroot is not a persistent property โ€” it's only valid while the system is up. Setting altroot defaults to using cachefile=none, though you can override that with an explicit setting. ๐Ÿ’…

๐Ÿ”ฅ the property you can set only at import time ๐Ÿ”ฅ

  • readonly=on|off โ€” if you set it to on, the pool gets imported in read-only mode. You can also call this one by its shortened column name, rdonly.

๐Ÿ‘‘ the properties you can set at creation time and import time โ€” and change later with zpool set ๐Ÿ‘‘

  • ashift=ashift โ€” the pool sector size exponent, to the power of 2 (internally referred to as ashift). Valid values are 9 to 16, inclusive; also, the value 0 (which is the default) means auto-detect using the kernel's block layer and a ZFS internal exception list. I/O operations get aligned to the specified size boundaries. On top of that, the minimum (disk) write size gets set to the specified size, so this is a whole space/performance trade-off situation. For optimal performance, your pool sector size should be greater than or equal to the sector size of the underlying disks. The typical case for setting this property is when performance matters and the underlying disks use 4KiB sectors but report 512B sectors to the OS (for compatibility reasons) โ€” in that case, set ashift=12 (which is 1<<12 = 4096). Once set, this property is used as the default hint value in subsequent vdev operations (add, attach and replace). Changing this value will not modify any existing vdev, not even on disk replacement. But it can be used, for instance, to replace a dying 512B-sectors disk with a newer 4KiB-sectors device โ€” which will probably result in bad performance, but at the same time could prevent loss of data. so... trade-offs, bestie ๐Ÿ’€
  • autoexpand=on|off โ€” controls automatic pool expansion when the underlying LUN grows. If set to on, the pool gets resized according to the size of the expanded device. If the device is part of a mirror or raidz, then all devices within that mirror/raidz group must be expanded before the new space becomes available to the pool. The default behavior is off. You can also call this one by its shortened column name, expand.
  • autoreplace=on|off โ€” controls automatic device replacement. If set to off, device replacement has to be initiated by the administrator using the zpool replace command. If set to on, any new device found in the same physical location as a device that previously belonged to the pool gets automatically formatted and replaced. The default behavior is off. You can also call this one by its shortened column name, replace. Autoreplace also works with virtual disks (like device mapper), as long as you use the /dev/disk/by-vdev paths set up by vdev_id.conf. See the vdev_id(8) manual page for more details. Oh and โ€” Autoreplace and autoonline require the ZFS Event Daemon to be configured and running. See the zed(8) manual page for more details. ๐Ÿซถ
  • autotrim=on|off โ€” when set to on, space that was recently freed and is no longer allocated by the pool gets periodically trimmed. This lets block device vdevs that support BLKDISCARD (like SSDs) โ€” or file vdevs on which the underlying file system supports hole-punching โ€” reclaim unused blocks. The default value for this property is off.

Automatic TRIM does not immediately reclaim blocks after a free. Instead, it optimistically delays so smaller ranges can be aggregated into a few larger ones, which can then be issued more efficiently to the storage. TRIM on L2ARC devices is enabled by setting l2arc_trim_ahead > 0.

โš ๏ธ be aware, bestie: automatic trimming of recently freed data blocks can put significant stress on the underlying storage devices. How much varies depending on how well the specific device handles these commands. For lower-end devices, it's often possible to get most of the benefits of automatic trimming by running an on-demand (manual) TRIM periodically using the zpool trim command. ๐Ÿ™ˆ
  • bootfs=(unset)|pool[/dataset] โ€” this one tells the system which dataset on the root pool is the default bootable one ๐Ÿฅพ๐Ÿ’–. Honestly? It's meant to be set by the installation and upgrade programs, not by you at 2am. And heads up bestie: not every Linux distribution's boot process even uses the bootfs property, so don't come for me if it does nothing on your box.
  • cachefile=path|none โ€” controls where the pool configuration gets cached ๐Ÿ“ฆโœจ. Here's the tea: finding all your pools at system startup needs a cached copy of the config data, and that copy lives on the root file system. Every pool in that cache gets auto-imported when the system boots. Some environments โ€” install setups, clustering, that whole vibe โ€” need to stash that info somewhere else so pools don't auto-import. Setting this property caches the pool config in a different location that you can later import with zpool import -c. Set it to none and you get a temporary pool that is never cached, and the "" (empty string) uses the default location.

Multiple pools can share the same cache file. And because the kernel destroys and recreates this file whenever pools are added and removed, be careful when you try to access it ๐Ÿ‘€. When the last pool using a cachefile is exported or destroyed, the file will be empty. It's giving ghost town ๐Ÿ’€.

  • comment=text โ€” a text string of printable ASCII characters that gets stored so it's still there even if the pool becomes faulted ๐ŸŽ€. Basically a little love note from the administrator with extra info about the pool. Cute, useful, iconic.
  • compatibility=off|legacy|file[,file]โ€ฆ โ€” tells the pool to stay compatible with specific feature sets ๐ŸŒˆ. Set it to off (or leave it unset) and compatibility is disabled, meaning all features may be enabled. Set it to legacy and no features may be enabled, periodt. Set it to a comma-separated list of filenames โ€” and each filename can be either an absolute path, or relative to /etc/zfs/compatibility.d or /usr/share/zfs/compatibility.d โ€” and the lists of requested features get read from those files, separated by whitespace and/or commas. Only features present in all the files may be enabled, no exceptions bestie.

See zpool-features(7), zpool-create(8) and zpool-upgrade(8) for more info on how compatibility feature sets actually operate ๐Ÿ”ฅ.

  • dedup_table_quota=number|none|auto โ€” this sets a limit on the on-disk size of the pool's dedup table ๐Ÿงฎ. Once that size is reached, entries will not be added to the dedup table anymore. And if a dedup table already exists and is larger than this size? Those entries will not be removed just because you set this property. Existing entries will still have their reference counts updated though, so they're still doing their little job ๐Ÿ’….

The actual size limit of the table may land above or below the quota, depending on the actual on-disk size of the entries (which may be approximated for purposes of calculating the quota). Like, setting a quota size of 1M may result in the max size being slightly below, or slightly above, that value. Set it to none to disable. In automatic mode โ€” which is the default โ€” the size of a dedicated dedup vdev is used as the quota limit.

The dedup_table_quota property works for both legacy and fast dedup tables โœจ.

  • dedupditto=number โ€” this property is deprecated and no longer has any effect. That's it. That's the whole entry. RIP bozo ๐Ÿชฆ.
  • delegation=on|off โ€” controls whether a non-privileged user gets access based on the dataset permissions defined on the dataset ๐Ÿ”. See zfs(8) for more info on ZFS delegated administration.
  • failmode=wait|continue|panic โ€” controls what the system does when there's a catastrophic pool failure ๐Ÿ˜ญ. That condition is typically caused by losing connectivity to the underlying storage device(s), or by all the devices in the pool failing. Here's how each option plays out:
    • wait โ€” blocks all I/O access until device connectivity is recovered and the errors are cleared with zpool clear. This is the default behavior. Just vibes and patience.
    • continue โ€” returns EIO to any new write I/O requests but allows reads to any of the remaining healthy devices. Any write requests that have yet to be committed to disk would be blocked.
    • panic โ€” prints out a message to the console and generates a system crash dump ๐Ÿ’€๐Ÿ”ฅ.
  • feature@feature_name=enabled โ€” the value of this property is the current state of feature_name. The only valid value when setting this property is enabled, which moves feature_name to the enabled state. See zpool-features(7) for details on feature states, bestie ๐Ÿฆ‹.
  • listsnapshots=on|off โ€” controls whether info about snapshots associated with this pool gets output when zfs list is run without the -t option ๐Ÿ‘‘. The default value is off. This property can also be referred to by its shortened name, listsnaps. Nickname privileges, we love to see it.
  • multihost=on|off โ€” controls whether a pool activity check should be performed during zpool import ๐Ÿ”. When a pool is determined to be active it cannot be imported, even with the -f option. This property is intended for failover configurations where multiple hosts have access to a pool on shared storage.

Multihost provides protection on import only. It does not protect against an individual device being used in multiple pools, regardless of the type of vdev. See the discussion under zpool create.

When this property is on, periodic writes to storage occur to show the pool is in use. See zfs_multihost_interval in the zfs(4) manual page. In order to enable this property each host must set a unique hostid. See genhostid(1), zgenhostid(8), spl(4) for additional details. The default value is off.

  • version=version โ€” the current on-disk version of the pool ๐Ÿ“Œ. This can be increased, but never decreased โ€” no take-backs, no cap. The preferred method of updating pools is with the zpool upgrade command, though this property can be used when you need a specific version for backwards compatibility. Once feature flags are enabled on a pool this property will no longer have a value. It's giving retirement arc ๐Ÿงš.

๐Ÿซถ User Properties ๐Ÿซถ

In addition to the standard native properties, ZFS supports arbitrary user properties โœจ. User properties have no effect on ZFS behavior, but applications or administrators can use them to annotate pools. Fancy little sticky notes, basically.

User property names must contain a colon (":") character to distinguish them from native properties ๐Ÿ‘€. They may contain lowercase letters, numbers, and the following punctuation characters: colon (":"), dash ("-"), period ("."), and underscore ("_"). The expected convention is that the property name is divided into two portions, like module:property, but this namespace is not enforced by ZFS. User property names can be at most 255 characters, and cannot begin with a dash ("-").

When making programmatic use of user properties, it is strongly suggested to use a reversed DNS domain name for the module component of property names, to reduce the chance that two independently-developed packages use the same property name for different purposes ๐Ÿ™ˆ. Do it. Future you will thank you.

The values of user properties are arbitrary strings and are never validated. All of the commands that operate on properties (zpool list, zpool get, zpool set, and so forth) can be used to manipulate both native properties and user properties. Use zpool set name= to clear a user property. Property values are limited to 8192 bytes ๐Ÿ“.


okay that's the whole thing bestie, you're officially a zpool properties scholar ๐Ÿ’…๐Ÿ‘‘ this was written by the fine folks at OpenZFS, dated December 4, 2024, and it lives at section ZPOOLPROPS(7) โ€” go forth and annotate your pools, mwah ๐ŸŽ€๐Ÿ’–โœจ

๐Ÿ“ฆ where this page comes from