mirror of
				https://git.proxmox.com/git/mirror_zfs.git
				synced 2025-10-26 18:05:04 +03:00 
			
		
		
		
	Add "compatibility" property for zpool feature sets
Property to allow sets of features to be specified; for compatibility with specific versions / releases / external systems. Influences the behavior of 'zpool upgrade' and 'zpool create'. Initial man page changes and test cases included. Brief synopsis: zpool create -o compatibility=off|legacy|file[,file...] pool vdev... compatibility = off : disable compatibility mode (enable all features) compatibility = legacy : request that no features be enabled compatibility = file[,file...] : read features from specified files. Only features present in *all* files will be enabled on the resulting pool. Filenames may be absolute, or relative to /etc/zfs/compatibility.d or /usr/share/zfs/compatibility.d (/etc checked first). Only affects zpool create, zpool upgrade and zpool status. ABI changes in libzfs: * New function "zpool_load_compat" to load and parse compat sets. * Add "zpool_compat_status_t" typedef for compatibility parse status. * Add ZPOOL_PROP_COMPATIBILITY to the pool properties enum * Add ZPOOL_STATUS_COMPATIBILITY_ERR to the pool status enum An initial set of base compatibility sets are included in cmd/zpool/compatibility.d, and the Makefile for cmd/zpool is modified to install these in $pkgdatadir/compatibility.d and to create symbolic links to a reasonable set of aliases. Reviewed-by: ericloewe Reviewed-by: Matthew Ahrens <mahrens@delphix.com> Reviewed-by: Richard Laager <rlaager@wiktel.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Colm Buckley <colm@tuatha.org> Closes #11468
This commit is contained in:
		
							parent
							
								
									35ec51796f
								
							
						
					
					
						commit
						658fb8020f
					
				| @ -39,7 +39,7 @@ include $(top_srcdir)/config/CppCheck.am | |||||||
| zpoolconfdir = $(sysconfdir)/zfs/zpool.d | zpoolconfdir = $(sysconfdir)/zfs/zpool.d | ||||||
| zpoolexecdir = $(zfsexecdir)/zpool.d | zpoolexecdir = $(zfsexecdir)/zpool.d | ||||||
| 
 | 
 | ||||||
| EXTRA_DIST = zpool.d/README | EXTRA_DIST = zpool.d/README compatibility.d | ||||||
| 
 | 
 | ||||||
| dist_zpoolexec_SCRIPTS = \
 | dist_zpoolexec_SCRIPTS = \
 | ||||||
| 	zpool.d/dm-deps \
 | 	zpool.d/dm-deps \
 | ||||||
| @ -129,6 +129,48 @@ zpoolconfdefaults = \ | |||||||
| 	test_progress \
 | 	test_progress \
 | ||||||
| 	test_ended | 	test_ended | ||||||
| 
 | 
 | ||||||
|  | zpoolcompatdir = $(pkgdatadir)/compatibility.d | ||||||
|  | 
 | ||||||
|  | dist_zpoolcompat_DATA = \
 | ||||||
|  | 	compatibility.d/compat-2018 \
 | ||||||
|  | 	compatibility.d/compat-2019 \
 | ||||||
|  | 	compatibility.d/compat-2020 \
 | ||||||
|  | 	compatibility.d/compat-2021 \
 | ||||||
|  | 	compatibility.d/freebsd-11.0 \
 | ||||||
|  | 	compatibility.d/freebsd-11.2 \
 | ||||||
|  | 	compatibility.d/freebsd-11.3 \
 | ||||||
|  | 	compatibility.d/freenas-9.10.2 \
 | ||||||
|  | 	compatibility.d/grub2 \
 | ||||||
|  | 	compatibility.d/openzfsonosx-1.7.0 \
 | ||||||
|  | 	compatibility.d/openzfsonosx-1.8.1 \
 | ||||||
|  | 	compatibility.d/openzfsonosx-1.9.3 \
 | ||||||
|  | 	compatibility.d/openzfs-2.0-freebsd \
 | ||||||
|  | 	compatibility.d/openzfs-2.0-linux \
 | ||||||
|  | 	compatibility.d/zol-0.6.5 \
 | ||||||
|  | 	compatibility.d/zol-0.7 \
 | ||||||
|  | 	compatibility.d/zol-0.8 | ||||||
|  | 
 | ||||||
|  | # canonical <- alias symbolic link pairs
 | ||||||
|  | # eg: "2018" is a link to "compat-2018"
 | ||||||
|  | zpoolcompatlinks = \
 | ||||||
|  | 	"compat-2018		2018" \
 | ||||||
|  | 	"compat-2019		2019" \
 | ||||||
|  | 	"compat-2020		2020" \
 | ||||||
|  | 	"compat-2021		2021" \
 | ||||||
|  | 	"freebsd-11.0		freebsd-11.1" \
 | ||||||
|  | 	"freebsd-11.0		freenas-11.0" \
 | ||||||
|  | 	"freebsd-11.2		freenas-11.2" \
 | ||||||
|  | 	"freebsd-11.3		freebsd-11.4" \
 | ||||||
|  | 	"freebsd-11.3		freebsd-12.0" \
 | ||||||
|  | 	"freebsd-11.3		freebsd-12.1" \
 | ||||||
|  | 	"freebsd-11.3		freebsd-12.2" \
 | ||||||
|  | 	"freebsd-11.3		freenas-11.3" \
 | ||||||
|  | 	"freenas-11.0		freenas-11.1" \
 | ||||||
|  | 	"openzfsonosx-1.9.3	openzfsonosx-1.9.4" \
 | ||||||
|  | 	"openzfs-2.0-freebsd	truenas-12.0" \
 | ||||||
|  | 	"zol-0.7		ubuntu-18.04" \
 | ||||||
|  | 	"zol-0.8		ubuntu-20.04" | ||||||
|  | 
 | ||||||
| install-data-hook: | install-data-hook: | ||||||
| 	$(MKDIR_P) "$(DESTDIR)$(zpoolconfdir)" | 	$(MKDIR_P) "$(DESTDIR)$(zpoolconfdir)" | ||||||
| 	for f in $(zpoolconfdefaults); do \
 | 	for f in $(zpoolconfdefaults); do \
 | ||||||
| @ -136,3 +178,6 @@ install-data-hook: | |||||||
| 	       -L "$(DESTDIR)$(zpoolconfdir)/$${f}" || \
 | 	       -L "$(DESTDIR)$(zpoolconfdir)/$${f}" || \
 | ||||||
| 	    ln -s "$(zpoolexecdir)/$${f}" "$(DESTDIR)$(zpoolconfdir)"; \
 | 	    ln -s "$(zpoolexecdir)/$${f}" "$(DESTDIR)$(zpoolconfdir)"; \
 | ||||||
| 	done | 	done | ||||||
|  | 	for l in $(zpoolcompatlinks); do \
 | ||||||
|  | 		(cd "$(DESTDIR)$(zpoolcompatdir)"; ln -s $${l} ); \
 | ||||||
|  | 	done | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								cmd/zpool/compatibility.d/compat-2018
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/zpool/compatibility.d/compat-2018
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | # Features supported by all Tier 1 platforms as of 2018 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										15
									
								
								cmd/zpool/compatibility.d/compat-2019
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cmd/zpool/compatibility.d/compat-2019
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # Features supported by all Tier 1 platforms as of 2019 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										15
									
								
								cmd/zpool/compatibility.d/compat-2020
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cmd/zpool/compatibility.d/compat-2020
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # Features supported by all Tier 1 platforms as of 2020 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										19
									
								
								cmd/zpool/compatibility.d/compat-2021
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								cmd/zpool/compatibility.d/compat-2021
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | # Features supported by all Tier 1 platforms as of 2021 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | zpool_checkpoint | ||||||
							
								
								
									
										15
									
								
								cmd/zpool/compatibility.d/freebsd-11.0
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								cmd/zpool/compatibility.d/freebsd-11.0
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | # Features supported by FreeBSD 11.0 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										18
									
								
								cmd/zpool/compatibility.d/freebsd-11.2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								cmd/zpool/compatibility.d/freebsd-11.2
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | # Features supported by FreeBSD 11.2 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | zpool_checkpoint | ||||||
							
								
								
									
										19
									
								
								cmd/zpool/compatibility.d/freebsd-11.3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								cmd/zpool/compatibility.d/freebsd-11.3
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | |||||||
|  | # Features supported by FreeBSD 11.3 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | zpool_checkpoint | ||||||
							
								
								
									
										13
									
								
								cmd/zpool/compatibility.d/freenas-9.10.2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										13
									
								
								cmd/zpool/compatibility.d/freenas-9.10.2
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,13 @@ | |||||||
|  | # Features supported by FreeNAS 9.10.2 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										12
									
								
								cmd/zpool/compatibility.d/grub2
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/zpool/compatibility.d/grub2
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | # Features which are supported by GRUB2 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										33
									
								
								cmd/zpool/compatibility.d/openzfs-2.0-freebsd
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								cmd/zpool/compatibility.d/openzfs-2.0-freebsd
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,33 @@ | |||||||
|  | # Features supported by OpenZFS 2.0 on FreeBSD | ||||||
|  | allocation_classes | ||||||
|  | async_destroy | ||||||
|  | bookmark_v2 | ||||||
|  | bookmark_written | ||||||
|  | bookmarks | ||||||
|  | device_rebuild | ||||||
|  | device_removal | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | encryption | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | large_dnode | ||||||
|  | livelist | ||||||
|  | log_spacemap | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | project_quota | ||||||
|  | redacted_datasets | ||||||
|  | redaction_bookmarks | ||||||
|  | resilver_defer | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | userobj_accounting | ||||||
|  | zpool_checkpoint | ||||||
|  | zstd_compress | ||||||
							
								
								
									
										34
									
								
								cmd/zpool/compatibility.d/openzfs-2.0-linux
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								cmd/zpool/compatibility.d/openzfs-2.0-linux
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,34 @@ | |||||||
|  | # Features supported by OpenZFS 2.0 on Linux | ||||||
|  | allocation_classes | ||||||
|  | async_destroy | ||||||
|  | bookmark_v2 | ||||||
|  | bookmark_written | ||||||
|  | bookmarks | ||||||
|  | device_rebuild | ||||||
|  | device_removal | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | encryption | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | large_dnode | ||||||
|  | livelist | ||||||
|  | log_spacemap | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | project_quota | ||||||
|  | redacted_datasets | ||||||
|  | redaction_bookmarks | ||||||
|  | resilver_defer | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | userobj_accounting | ||||||
|  | zpool_checkpoint | ||||||
|  | zstd_compress | ||||||
							
								
								
									
										16
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.7.0
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.7.0
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,16 @@ | |||||||
|  | # Features supported by OpenZFSonOSX 1.7.0 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										21
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.8.1
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.8.1
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,21 @@ | |||||||
|  | # Features supported by OpenZFSonOSX 1.8.1 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | encryption | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | zpool_checkpoint | ||||||
							
								
								
									
										27
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.9.3
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								cmd/zpool/compatibility.d/openzfsonosx-1.9.3
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | # Features supported by OpenZFSonOSX 1.9.3 | ||||||
|  | allocation_classes | ||||||
|  | async_destroy | ||||||
|  | bookmark_v2 | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | encryption | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | large_dnode | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | project_quota | ||||||
|  | resilver_defer | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | userobj_accounting | ||||||
|  | zpool_checkpoint | ||||||
							
								
								
									
										12
									
								
								cmd/zpool/compatibility.d/zol-0.6.5
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								cmd/zpool/compatibility.d/zol-0.6.5
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,12 @@ | |||||||
|  | # Features supported by ZFSonLinux v0.6.5 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | spacemap_histogram | ||||||
							
								
								
									
										18
									
								
								cmd/zpool/compatibility.d/zol-0.7
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								cmd/zpool/compatibility.d/zol-0.7
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | |||||||
|  | # Features supported by ZFSonLinux v0.7 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | large_dnode | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | userobj_accounting | ||||||
							
								
								
									
										27
									
								
								cmd/zpool/compatibility.d/zol-0.8
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								cmd/zpool/compatibility.d/zol-0.8
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,27 @@ | |||||||
|  | # Features supported by ZFSonLinux v0.8 | ||||||
|  | allocation_classes | ||||||
|  | async_destroy | ||||||
|  | bookmark_v2 | ||||||
|  | bookmarks | ||||||
|  | device_removal | ||||||
|  | edonr | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | encryption | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | large_dnode | ||||||
|  | lz4_compress | ||||||
|  | multi_vdev_crash_dump | ||||||
|  | obsolete_counts | ||||||
|  | project_quota | ||||||
|  | resilver_defer | ||||||
|  | sha512 | ||||||
|  | skein | ||||||
|  | spacemap_histogram | ||||||
|  | spacemap_v2 | ||||||
|  | userobj_accounting | ||||||
|  | zpool_checkpoint | ||||||
| @ -31,6 +31,7 @@ | |||||||
|  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. |  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  * Copyright (c) 2017, Intel Corporation. |  * Copyright (c) 2017, Intel Corporation. | ||||||
|  * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com> |  * Copyright (c) 2019, loli10K <ezomori.nozomu@gmail.com> | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <assert.h> | #include <assert.h> | ||||||
| @ -124,6 +125,9 @@ static int zpool_do_version(int, char **); | |||||||
| 
 | 
 | ||||||
| static int zpool_do_wait(int, char **); | static int zpool_do_wait(int, char **); | ||||||
| 
 | 
 | ||||||
|  | static zpool_compat_status_t zpool_do_load_compat( | ||||||
|  |     const char *, boolean_t *); | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * These libumem hooks provide a reasonable set of defaults for the allocator's |  * These libumem hooks provide a reasonable set of defaults for the allocator's | ||||||
|  * debugging facilities. |  * debugging facilities. | ||||||
| @ -782,6 +786,8 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props, | |||||||
| 
 | 
 | ||||||
| 	if (poolprop) { | 	if (poolprop) { | ||||||
| 		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); | 		const char *vname = zpool_prop_to_name(ZPOOL_PROP_VERSION); | ||||||
|  | 		const char *fname = | ||||||
|  | 		    zpool_prop_to_name(ZPOOL_PROP_COMPATIBILITY); | ||||||
| 
 | 
 | ||||||
| 		if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL && | 		if ((prop = zpool_name_to_prop(propname)) == ZPOOL_PROP_INVAL && | ||||||
| 		    !zpool_prop_feature(propname)) { | 		    !zpool_prop_feature(propname)) { | ||||||
| @ -804,6 +810,19 @@ add_prop_list(const char *propname, char *propval, nvlist_t **props, | |||||||
| 			return (2); | 			return (2); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * compatibility property and version should not be specified | ||||||
|  | 		 * at the same time. | ||||||
|  | 		 */ | ||||||
|  | 		if ((prop == ZPOOL_PROP_COMPATIBILITY && | ||||||
|  | 		    nvlist_exists(proplist, vname)) || | ||||||
|  | 		    (prop == ZPOOL_PROP_VERSION && | ||||||
|  | 		    nvlist_exists(proplist, fname))) { | ||||||
|  | 			(void) fprintf(stderr, gettext("'compatibility' and " | ||||||
|  | 			    "'version' properties cannot be specified " | ||||||
|  | 			    "together\n")); | ||||||
|  | 			return (2); | ||||||
|  | 		} | ||||||
| 
 | 
 | ||||||
| 		if (zpool_prop_feature(propname)) | 		if (zpool_prop_feature(propname)) | ||||||
| 			normnm = propname; | 			normnm = propname; | ||||||
| @ -1374,13 +1393,15 @@ zpool_do_create(int argc, char **argv) | |||||||
| { | { | ||||||
| 	boolean_t force = B_FALSE; | 	boolean_t force = B_FALSE; | ||||||
| 	boolean_t dryrun = B_FALSE; | 	boolean_t dryrun = B_FALSE; | ||||||
| 	boolean_t enable_all_pool_feat = B_TRUE; | 	boolean_t enable_pool_features = B_TRUE; | ||||||
|  | 
 | ||||||
| 	int c; | 	int c; | ||||||
| 	nvlist_t *nvroot = NULL; | 	nvlist_t *nvroot = NULL; | ||||||
| 	char *poolname; | 	char *poolname; | ||||||
| 	char *tname = NULL; | 	char *tname = NULL; | ||||||
| 	int ret = 1; | 	int ret = 1; | ||||||
| 	char *altroot = NULL; | 	char *altroot = NULL; | ||||||
|  | 	char *compat = NULL; | ||||||
| 	char *mountpoint = NULL; | 	char *mountpoint = NULL; | ||||||
| 	nvlist_t *fsprops = NULL; | 	nvlist_t *fsprops = NULL; | ||||||
| 	nvlist_t *props = NULL; | 	nvlist_t *props = NULL; | ||||||
| @ -1396,7 +1417,7 @@ zpool_do_create(int argc, char **argv) | |||||||
| 			dryrun = B_TRUE; | 			dryrun = B_TRUE; | ||||||
| 			break; | 			break; | ||||||
| 		case 'd': | 		case 'd': | ||||||
| 			enable_all_pool_feat = B_FALSE; | 			enable_pool_features = B_FALSE; | ||||||
| 			break; | 			break; | ||||||
| 		case 'R': | 		case 'R': | ||||||
| 			altroot = optarg; | 			altroot = optarg; | ||||||
| @ -1434,11 +1455,14 @@ zpool_do_create(int argc, char **argv) | |||||||
| 				ver = strtoull(propval, &end, 10); | 				ver = strtoull(propval, &end, 10); | ||||||
| 				if (*end == '\0' && | 				if (*end == '\0' && | ||||||
| 				    ver < SPA_VERSION_FEATURES) { | 				    ver < SPA_VERSION_FEATURES) { | ||||||
| 					enable_all_pool_feat = B_FALSE; | 					enable_pool_features = B_FALSE; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) | 			if (zpool_name_to_prop(optarg) == ZPOOL_PROP_ALTROOT) | ||||||
| 				altroot = propval; | 				altroot = propval; | ||||||
|  | 			if (zpool_name_to_prop(optarg) == | ||||||
|  | 			    ZPOOL_PROP_COMPATIBILITY) | ||||||
|  | 				compat = propval; | ||||||
| 			break; | 			break; | ||||||
| 		case 'O': | 		case 'O': | ||||||
| 			if ((propval = strchr(optarg, '=')) == NULL) { | 			if ((propval = strchr(optarg, '=')) == NULL) { | ||||||
| @ -1632,10 +1656,26 @@ zpool_do_create(int argc, char **argv) | |||||||
| 		ret = 0; | 		ret = 0; | ||||||
| 	} else { | 	} else { | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * Hand off to libzfs. | 		 * Load in feature set. | ||||||
|  | 		 * Note: if compatibility property not given, we'll have | ||||||
|  | 		 * NULL, which means 'all features'. | ||||||
| 		 */ | 		 */ | ||||||
| 		spa_feature_t i; | 		boolean_t requested_features[SPA_FEATURES]; | ||||||
| 		for (i = 0; i < SPA_FEATURES; i++) { | 		if (zpool_do_load_compat(compat, requested_features) != | ||||||
|  | 		    ZPOOL_COMPATIBILITY_OK) | ||||||
|  | 			goto errout; | ||||||
|  | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * props contains list of features to enable. | ||||||
|  | 		 * For each feature: | ||||||
|  | 		 *  - remove it if feature@name=disabled | ||||||
|  | 		 *  - leave it there if feature@name=enabled | ||||||
|  | 		 *  - add it if: | ||||||
|  | 		 *    - enable_pool_features (ie: no '-d' or '-o version') | ||||||
|  | 		 *    - it's supported by the kernel module | ||||||
|  | 		 *    - it's in the requested feature set | ||||||
|  | 		 */ | ||||||
|  | 		for (spa_feature_t i = 0; i < SPA_FEATURES; i++) { | ||||||
| 			char propname[MAXPATHLEN]; | 			char propname[MAXPATHLEN]; | ||||||
| 			char *propval; | 			char *propval; | ||||||
| 			zfeature_info_t *feat = &spa_feature_table[i]; | 			zfeature_info_t *feat = &spa_feature_table[i]; | ||||||
| @ -1643,18 +1683,14 @@ zpool_do_create(int argc, char **argv) | |||||||
| 			(void) snprintf(propname, sizeof (propname), | 			(void) snprintf(propname, sizeof (propname), | ||||||
| 			    "feature@%s", feat->fi_uname); | 			    "feature@%s", feat->fi_uname); | ||||||
| 
 | 
 | ||||||
| 			/*
 |  | ||||||
| 			 * Only features contained in props will be enabled: |  | ||||||
| 			 * remove from the nvlist every ZFS_FEATURE_DISABLED |  | ||||||
| 			 * value and add every missing ZFS_FEATURE_ENABLED if |  | ||||||
| 			 * enable_all_pool_feat is set. |  | ||||||
| 			 */ |  | ||||||
| 			if (!nvlist_lookup_string(props, propname, &propval)) { | 			if (!nvlist_lookup_string(props, propname, &propval)) { | ||||||
| 				if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0) | 				if (strcmp(propval, ZFS_FEATURE_DISABLED) == 0) | ||||||
| 					(void) nvlist_remove_all(props, | 					(void) nvlist_remove_all(props, | ||||||
| 					    propname); | 					    propname); | ||||||
| 			} else if (enable_all_pool_feat && | 			} else if ( | ||||||
| 			    feat->fi_zfs_mod_supported) { | 			    enable_pool_features && | ||||||
|  | 			    feat->fi_zfs_mod_supported && | ||||||
|  | 			    requested_features[i]) { | ||||||
| 				ret = add_prop_list(propname, | 				ret = add_prop_list(propname, | ||||||
| 				    ZFS_FEATURE_ENABLED, &props, B_TRUE); | 				    ZFS_FEATURE_ENABLED, &props, B_TRUE); | ||||||
| 				if (ret != 0) | 				if (ret != 0) | ||||||
| @ -2674,8 +2710,15 @@ show_import(nvlist_t *config) | |||||||
| 
 | 
 | ||||||
| 	case ZPOOL_STATUS_FEAT_DISABLED: | 	case ZPOOL_STATUS_FEAT_DISABLED: | ||||||
| 		printf_color(ANSI_BOLD, gettext("status: ")); | 		printf_color(ANSI_BOLD, gettext("status: ")); | ||||||
| 		printf_color(ANSI_YELLOW, gettext("Some supported features are " | 		printf_color(ANSI_YELLOW, gettext("Some supported and " | ||||||
| 		    "not enabled on the pool.\n")); | 		    "requested features are not enabled on the pool.\n")); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
|  | 	case ZPOOL_STATUS_COMPATIBILITY_ERR: | ||||||
|  | 		printf_color(ANSI_BOLD, gettext("status: ")); | ||||||
|  | 		printf_color(ANSI_YELLOW, gettext("Error reading or parsing " | ||||||
|  | 		    "the file(s) indicated by the 'compatibility'\n" | ||||||
|  | 		    "property.\n")); | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
| 	case ZPOOL_STATUS_UNSUP_FEAT_READ: | 	case ZPOOL_STATUS_UNSUP_FEAT_READ: | ||||||
| @ -2767,6 +2810,12 @@ show_import(nvlist_t *config) | |||||||
| 			    "imported using its name or numeric identifier, " | 			    "imported using its name or numeric identifier, " | ||||||
| 			    "though\n\tsome features will not be available " | 			    "though\n\tsome features will not be available " | ||||||
| 			    "without an explicit 'zpool upgrade'.\n")); | 			    "without an explicit 'zpool upgrade'.\n")); | ||||||
|  | 		} else if (reason == ZPOOL_STATUS_COMPATIBILITY_ERR) { | ||||||
|  | 			(void) printf(gettext(" action: The pool can be " | ||||||
|  | 			    "imported using its name or numeric\n\tidentifier, " | ||||||
|  | 			    "though the file(s) indicated by its " | ||||||
|  | 			    "'compatibility'\n\tproperty cannot be parsed at " | ||||||
|  | 			    "this time.\n")); | ||||||
| 		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { | 		} else if (reason == ZPOOL_STATUS_HOSTID_MISMATCH) { | ||||||
| 			(void) printf(gettext(" action: The pool can be " | 			(void) printf(gettext(" action: The pool can be " | ||||||
| 			    "imported using its name or numeric " | 			    "imported using its name or numeric " | ||||||
| @ -7942,7 +7991,8 @@ status_callback(zpool_handle_t *zhp, void *data) | |||||||
| 	if (cbp->cb_explain && | 	if (cbp->cb_explain && | ||||||
| 	    (reason == ZPOOL_STATUS_OK || | 	    (reason == ZPOOL_STATUS_OK || | ||||||
| 	    reason == ZPOOL_STATUS_VERSION_OLDER || | 	    reason == ZPOOL_STATUS_VERSION_OLDER || | ||||||
| 	    reason == ZPOOL_STATUS_FEAT_DISABLED)) { | 	    reason == ZPOOL_STATUS_FEAT_DISABLED || | ||||||
|  | 	    reason == ZPOOL_STATUS_COMPATIBILITY_ERR)) { | ||||||
| 		if (!cbp->cb_allpools) { | 		if (!cbp->cb_allpools) { | ||||||
| 			(void) printf(gettext("pool '%s' is healthy\n"), | 			(void) printf(gettext("pool '%s' is healthy\n"), | ||||||
| 			    zpool_get_name(zhp)); | 			    zpool_get_name(zhp)); | ||||||
| @ -8117,9 +8167,10 @@ status_callback(zpool_handle_t *zhp, void *data) | |||||||
| 
 | 
 | ||||||
| 	case ZPOOL_STATUS_FEAT_DISABLED: | 	case ZPOOL_STATUS_FEAT_DISABLED: | ||||||
| 		printf_color(ANSI_BOLD, gettext("status: ")); | 		printf_color(ANSI_BOLD, gettext("status: ")); | ||||||
| 		printf_color(ANSI_YELLOW, gettext("Some supported features are " | 		printf_color(ANSI_YELLOW, gettext("Some supported and " | ||||||
| 		    "not enabled on the pool. The pool can\n\tstill be used, " | 		    "requested features are not enabled on the pool.\n\t" | ||||||
| 		    "but some features are unavailable.\n")); | 		    "The pool can still be used, but some features are " | ||||||
|  | 		    "unavailable.\n")); | ||||||
| 		printf_color(ANSI_BOLD, gettext("action: ")); | 		printf_color(ANSI_BOLD, gettext("action: ")); | ||||||
| 		printf_color(ANSI_YELLOW, gettext("Enable all features using " | 		printf_color(ANSI_YELLOW, gettext("Enable all features using " | ||||||
| 		    "'zpool upgrade'. Once this is done,\n\tthe pool may no " | 		    "'zpool upgrade'. Once this is done,\n\tthe pool may no " | ||||||
| @ -8127,6 +8178,19 @@ status_callback(zpool_handle_t *zhp, void *data) | |||||||
| 		    "the features. See zpool-features(5) for details.\n")); | 		    "the features. See zpool-features(5) for details.\n")); | ||||||
| 		break; | 		break; | ||||||
| 
 | 
 | ||||||
|  | 	case ZPOOL_STATUS_COMPATIBILITY_ERR: | ||||||
|  | 		printf_color(ANSI_BOLD, gettext("status: ")); | ||||||
|  | 		printf_color(ANSI_YELLOW, gettext("This pool has a " | ||||||
|  | 		    "compatibility list specified, but it could not be\n\t" | ||||||
|  | 		    "read/parsed at this time. The pool can still be used, " | ||||||
|  | 		    "but this\n\tshould be investigated.\n")); | ||||||
|  | 		printf_color(ANSI_BOLD, gettext("action: ")); | ||||||
|  | 		printf_color(ANSI_YELLOW, gettext("Check the value of the " | ||||||
|  | 		    "'compatibility' property against the\n\t" | ||||||
|  | 		    "appropriate file in " ZPOOL_SYSCONF_COMPAT_D " or " | ||||||
|  | 		    ZPOOL_DATA_COMPAT_D ".\n")); | ||||||
|  | 		break; | ||||||
|  | 
 | ||||||
| 	case ZPOOL_STATUS_UNSUP_FEAT_READ: | 	case ZPOOL_STATUS_UNSUP_FEAT_READ: | ||||||
| 		printf_color(ANSI_BOLD, gettext("status: ")); | 		printf_color(ANSI_BOLD, gettext("status: ")); | ||||||
| 		printf_color(ANSI_YELLOW, gettext("The pool cannot be accessed " | 		printf_color(ANSI_YELLOW, gettext("The pool cannot be accessed " | ||||||
| @ -8625,6 +8689,16 @@ upgrade_enable_all(zpool_handle_t *zhp, int *countp) | |||||||
| 	boolean_t firstff = B_TRUE; | 	boolean_t firstff = B_TRUE; | ||||||
| 	nvlist_t *enabled = zpool_get_features(zhp); | 	nvlist_t *enabled = zpool_get_features(zhp); | ||||||
| 
 | 
 | ||||||
|  | 	char compat[ZFS_MAXPROPLEN]; | ||||||
|  | 	if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compat, | ||||||
|  | 	    ZFS_MAXPROPLEN, NULL, B_FALSE) != 0) | ||||||
|  | 		compat[0] = '\0'; | ||||||
|  | 
 | ||||||
|  | 	boolean_t requested_features[SPA_FEATURES]; | ||||||
|  | 	if (zpool_do_load_compat(compat, requested_features) != | ||||||
|  | 	    ZPOOL_COMPATIBILITY_OK) | ||||||
|  | 		return (-1); | ||||||
|  | 
 | ||||||
| 	count = 0; | 	count = 0; | ||||||
| 	for (i = 0; i < SPA_FEATURES; i++) { | 	for (i = 0; i < SPA_FEATURES; i++) { | ||||||
| 		const char *fname = spa_feature_table[i].fi_uname; | 		const char *fname = spa_feature_table[i].fi_uname; | ||||||
| @ -8633,7 +8707,7 @@ upgrade_enable_all(zpool_handle_t *zhp, int *countp) | |||||||
| 		if (!spa_feature_table[i].fi_zfs_mod_supported) | 		if (!spa_feature_table[i].fi_zfs_mod_supported) | ||||||
| 			continue; | 			continue; | ||||||
| 
 | 
 | ||||||
| 		if (!nvlist_exists(enabled, fguid)) { | 		if (!nvlist_exists(enabled, fguid) && requested_features[i]) { | ||||||
| 			char *propname; | 			char *propname; | ||||||
| 			verify(-1 != asprintf(&propname, "feature@%s", fname)); | 			verify(-1 != asprintf(&propname, "feature@%s", fname)); | ||||||
| 			ret = zpool_set_prop(zhp, propname, | 			ret = zpool_set_prop(zhp, propname, | ||||||
| @ -8855,7 +8929,7 @@ upgrade_one(zpool_handle_t *zhp, void *data) | |||||||
| 			printnl = B_TRUE; | 			printnl = B_TRUE; | ||||||
| 		} else if (cur_version == SPA_VERSION) { | 		} else if (cur_version == SPA_VERSION) { | ||||||
| 			(void) printf(gettext("Pool '%s' already has all " | 			(void) printf(gettext("Pool '%s' already has all " | ||||||
| 			    "supported features enabled.\n"), | 			    "supported and requested features enabled.\n"), | ||||||
| 			    zpool_get_name(zhp)); | 			    zpool_get_name(zhp)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -9016,8 +9090,8 @@ zpool_do_upgrade(int argc, char **argv) | |||||||
| 				(void) printf(gettext("All pools are already " | 				(void) printf(gettext("All pools are already " | ||||||
| 				    "formatted using feature flags.\n\n")); | 				    "formatted using feature flags.\n\n")); | ||||||
| 				(void) printf(gettext("Every feature flags " | 				(void) printf(gettext("Every feature flags " | ||||||
| 				    "pool already has all supported features " | 				    "pool already has all supported and " | ||||||
| 				    "enabled.\n")); | 				    "requested features enabled.\n")); | ||||||
| 			} else { | 			} else { | ||||||
| 				(void) printf(gettext("All pools are already " | 				(void) printf(gettext("All pools are already " | ||||||
| 				    "formatted with version %llu or higher.\n"), | 				    "formatted with version %llu or higher.\n"), | ||||||
| @ -9043,7 +9117,7 @@ zpool_do_upgrade(int argc, char **argv) | |||||||
| 
 | 
 | ||||||
| 		if (cb.cb_first) { | 		if (cb.cb_first) { | ||||||
| 			(void) printf(gettext("Every feature flags pool has " | 			(void) printf(gettext("Every feature flags pool has " | ||||||
| 			    "all supported features enabled.\n")); | 			    "all supported and requested features enabled.\n")); | ||||||
| 		} else { | 		} else { | ||||||
| 			(void) printf(gettext("\n")); | 			(void) printf(gettext("\n")); | ||||||
| 		} | 		} | ||||||
| @ -10347,6 +10421,39 @@ zpool_do_version(int argc, char **argv) | |||||||
| 	return (0); | 	return (0); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Do zpool_load_compat() and print error message on failure | ||||||
|  |  */ | ||||||
|  | static zpool_compat_status_t | ||||||
|  | zpool_do_load_compat(const char *compat, boolean_t *list) | ||||||
|  | { | ||||||
|  | 	char badword[ZFS_MAXPROPLEN]; | ||||||
|  | 	char badfile[MAXPATHLEN]; | ||||||
|  | 	zpool_compat_status_t ret; | ||||||
|  | 
 | ||||||
|  | 	switch (ret = zpool_load_compat(compat, list, badword, badfile)) { | ||||||
|  | 	case ZPOOL_COMPATIBILITY_OK: | ||||||
|  | 		break; | ||||||
|  | 	case ZPOOL_COMPATIBILITY_READERR: | ||||||
|  | 		(void) fprintf(stderr, gettext("error reading compatibility " | ||||||
|  | 		    "file '%s'\n"), badfile); | ||||||
|  | 		break; | ||||||
|  | 	case ZPOOL_COMPATIBILITY_BADFILE: | ||||||
|  | 		(void) fprintf(stderr, gettext("compatibility file '%s' " | ||||||
|  | 		    "too large or not newline-terminated\n"), badfile); | ||||||
|  | 		break; | ||||||
|  | 	case ZPOOL_COMPATIBILITY_BADWORD: | ||||||
|  | 		(void) fprintf(stderr, gettext("unknown feature '%s' in " | ||||||
|  | 		    "compatibility file '%s'\n"), badword, badfile); | ||||||
|  | 		break; | ||||||
|  | 	case ZPOOL_COMPATIBILITY_NOFILES: | ||||||
|  | 		(void) fprintf(stderr, gettext("no compatibility files " | ||||||
|  | 		    "specified\n")); | ||||||
|  | 		break; | ||||||
|  | 	} | ||||||
|  | 	return (ret); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| int | int | ||||||
| main(int argc, char **argv) | main(int argc, char **argv) | ||||||
| { | { | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ AM_CPPFLAGS += -DLIBEXECDIR=\"$(libexecdir)\" | |||||||
| AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\" | AM_CPPFLAGS += -DRUNSTATEDIR=\"$(runstatedir)\" | ||||||
| AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\" | AM_CPPFLAGS += -DSBINDIR=\"$(sbindir)\" | ||||||
| AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\" | AM_CPPFLAGS += -DSYSCONFDIR=\"$(sysconfdir)\" | ||||||
|  | AM_CPPFLAGS += -DPKGDATADIR=\"$(pkgdatadir)\" | ||||||
| AM_CPPFLAGS += $(DEBUG_CPPFLAGS) | AM_CPPFLAGS += $(DEBUG_CPPFLAGS) | ||||||
| AM_CPPFLAGS += $(CODE_COVERAGE_CPPFLAGS) | AM_CPPFLAGS += $(CODE_COVERAGE_CPPFLAGS) | ||||||
| if BUILD_LINUX | if BUILD_LINUX | ||||||
|  | |||||||
| @ -28,6 +28,7 @@ | |||||||
|  * Copyright 2016 Nexenta Systems, Inc. |  * Copyright 2016 Nexenta Systems, Inc. | ||||||
|  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. |  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  * Copyright (c) 2019 Datto Inc. |  * Copyright (c) 2019 Datto Inc. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #ifndef	_LIBZFS_H | #ifndef	_LIBZFS_H | ||||||
| @ -391,6 +392,7 @@ typedef enum { | |||||||
| 	ZPOOL_STATUS_REBUILDING,	/* device being rebuilt */ | 	ZPOOL_STATUS_REBUILDING,	/* device being rebuilt */ | ||||||
| 	ZPOOL_STATUS_REBUILD_SCRUB,	/* recommend scrubbing the pool */ | 	ZPOOL_STATUS_REBUILD_SCRUB,	/* recommend scrubbing the pool */ | ||||||
| 	ZPOOL_STATUS_NON_NATIVE_ASHIFT,	/* (e.g. 512e dev with ashift of 9) */ | 	ZPOOL_STATUS_NON_NATIVE_ASHIFT,	/* (e.g. 512e dev with ashift of 9) */ | ||||||
|  | 	ZPOOL_STATUS_COMPATIBILITY_ERR,	/* bad 'compatibility' property */ | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Finally, the following indicates a healthy pool. | 	 * Finally, the following indicates a healthy pool. | ||||||
| @ -912,6 +914,20 @@ int zfs_smb_acl_rename(libzfs_handle_t *, char *, char *, char *, char *); | |||||||
| extern int zpool_enable_datasets(zpool_handle_t *, const char *, int); | extern int zpool_enable_datasets(zpool_handle_t *, const char *, int); | ||||||
| extern int zpool_disable_datasets(zpool_handle_t *, boolean_t); | extern int zpool_disable_datasets(zpool_handle_t *, boolean_t); | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Parse a features file for -o compatibility | ||||||
|  |  */ | ||||||
|  | typedef enum { | ||||||
|  | 	ZPOOL_COMPATIBILITY_OK, | ||||||
|  | 	ZPOOL_COMPATIBILITY_READERR, | ||||||
|  | 	ZPOOL_COMPATIBILITY_BADFILE, | ||||||
|  | 	ZPOOL_COMPATIBILITY_BADWORD, | ||||||
|  | 	ZPOOL_COMPATIBILITY_NOFILES | ||||||
|  | } zpool_compat_status_t; | ||||||
|  | 
 | ||||||
|  | extern zpool_compat_status_t zpool_load_compat(const char *, | ||||||
|  |     boolean_t *, char *, char *); | ||||||
|  | 
 | ||||||
| #ifdef __FreeBSD__ | #ifdef __FreeBSD__ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  | |||||||
| @ -27,10 +27,10 @@ | |||||||
|  * Copyright (c) 2014 Integros [integros.com] |  * Copyright (c) 2014 Integros [integros.com] | ||||||
|  * Copyright (c) 2017, Intel Corporation. |  * Copyright (c) 2017, Intel Corporation. | ||||||
|  * Copyright (c) 2019 Datto Inc. |  * Copyright (c) 2019 Datto Inc. | ||||||
|  |  * Portions Copyright 2010 Robert Milkowski | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /* Portions Copyright 2010 Robert Milkowski */ |  | ||||||
| 
 |  | ||||||
| #ifndef	_SYS_FS_ZFS_H | #ifndef	_SYS_FS_ZFS_H | ||||||
| #define	_SYS_FS_ZFS_H | #define	_SYS_FS_ZFS_H | ||||||
| 
 | 
 | ||||||
| @ -246,6 +246,7 @@ typedef enum { | |||||||
| 	ZPOOL_PROP_CHECKPOINT, | 	ZPOOL_PROP_CHECKPOINT, | ||||||
| 	ZPOOL_PROP_LOAD_GUID, | 	ZPOOL_PROP_LOAD_GUID, | ||||||
| 	ZPOOL_PROP_AUTOTRIM, | 	ZPOOL_PROP_AUTOTRIM, | ||||||
|  | 	ZPOOL_PROP_COMPATIBILITY, | ||||||
| 	ZPOOL_NUM_PROPS | 	ZPOOL_NUM_PROPS | ||||||
| } zpool_prop_t; | } zpool_prop_t; | ||||||
| 
 | 
 | ||||||
| @ -733,6 +734,7 @@ typedef struct zpool_load_policy { | |||||||
| #define	ZPOOL_CONFIG_ALLOCATION_BIAS	"alloc_bias"	/* not stored on disk */ | #define	ZPOOL_CONFIG_ALLOCATION_BIAS	"alloc_bias"	/* not stored on disk */ | ||||||
| #define	ZPOOL_CONFIG_EXPANSION_TIME	"expansion_time"	/* not stored */ | #define	ZPOOL_CONFIG_EXPANSION_TIME	"expansion_time"	/* not stored */ | ||||||
| #define	ZPOOL_CONFIG_REBUILD_STATS	"org.openzfs:rebuild_stats" | #define	ZPOOL_CONFIG_REBUILD_STATS	"org.openzfs:rebuild_stats" | ||||||
|  | #define	ZPOOL_CONFIG_COMPATIBILITY	"compatibility" | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
|  * The persistent vdev state is stored as separate values rather than a single |  * The persistent vdev state is stored as separate values rather than a single | ||||||
| @ -845,6 +847,19 @@ typedef struct zpool_load_policy { | |||||||
|  */ |  */ | ||||||
| #define	ZPOOL_CACHE_BOOT	"/boot/zfs/zpool.cache" | #define	ZPOOL_CACHE_BOOT	"/boot/zfs/zpool.cache" | ||||||
| #define	ZPOOL_CACHE		"/etc/zfs/zpool.cache" | #define	ZPOOL_CACHE		"/etc/zfs/zpool.cache" | ||||||
|  | /*
 | ||||||
|  |  * Settings for zpool compatibility features files | ||||||
|  |  */ | ||||||
|  | #define	ZPOOL_SYSCONF_COMPAT_D	SYSCONFDIR "/zfs/compatibility.d" | ||||||
|  | #define	ZPOOL_DATA_COMPAT_D	PKGDATADIR "/compatibility.d" | ||||||
|  | #define	ZPOOL_COMPAT_MAXSIZE	16384 | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Hard-wired compatibility settings | ||||||
|  |  */ | ||||||
|  | #define	ZPOOL_COMPAT_LEGACY	"legacy" | ||||||
|  | #define	ZPOOL_COMPAT_OFF	"off" | ||||||
|  | 
 | ||||||
| /*
 | /*
 | ||||||
|  * vdev states are ordered from least to most healthy. |  * vdev states are ordered from least to most healthy. | ||||||
|  * A vdev that's CANT_OPEN or below is considered unusable. |  * A vdev that's CANT_OPEN or below is considered unusable. | ||||||
|  | |||||||
| @ -424,6 +424,8 @@ struct spa { | |||||||
| 	int		spa_waiters;		/* number of waiting threads */ | 	int		spa_waiters;		/* number of waiting threads */ | ||||||
| 	boolean_t	spa_waiters_cancel;	/* waiters should return */ | 	boolean_t	spa_waiters_cancel;	/* waiters should return */ | ||||||
| 
 | 
 | ||||||
|  | 	char		*spa_compatibility;	/* compatibility file(s) */ | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * spa_refcount & spa_config_lock must be the last elements | 	 * spa_refcount & spa_config_lock must be the last elements | ||||||
| 	 * because zfs_refcount_t changes size based on compilation options. | 	 * because zfs_refcount_t changes size based on compilation options. | ||||||
|  | |||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @ -28,6 +28,7 @@ | |||||||
|  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. |  * Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  * Copyright (c) 2017, Intel Corporation. |  * Copyright (c) 2017, Intel Corporation. | ||||||
|  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com> |  * Copyright (c) 2018, loli10K <ezomori.nozomu@gmail.com> | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <errno.h> | #include <errno.h> | ||||||
| @ -44,8 +45,12 @@ | |||||||
| #include <sys/zfs_ioctl.h> | #include <sys/zfs_ioctl.h> | ||||||
| #include <sys/zfs_sysfs.h> | #include <sys/zfs_sysfs.h> | ||||||
| #include <sys/vdev_disk.h> | #include <sys/vdev_disk.h> | ||||||
|  | #include <sys/types.h> | ||||||
| #include <dlfcn.h> | #include <dlfcn.h> | ||||||
| #include <libzutil.h> | #include <libzutil.h> | ||||||
|  | #include <fcntl.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | 
 | ||||||
| #include "zfs_namecheck.h" | #include "zfs_namecheck.h" | ||||||
| #include "zfs_prop.h" | #include "zfs_prop.h" | ||||||
| #include "libzfs_impl.h" | #include "libzfs_impl.h" | ||||||
| @ -302,6 +307,7 @@ zpool_get_prop(zpool_handle_t *zhp, zpool_prop_t prop, char *buf, | |||||||
| 		case ZPOOL_PROP_ALTROOT: | 		case ZPOOL_PROP_ALTROOT: | ||||||
| 		case ZPOOL_PROP_CACHEFILE: | 		case ZPOOL_PROP_CACHEFILE: | ||||||
| 		case ZPOOL_PROP_COMMENT: | 		case ZPOOL_PROP_COMMENT: | ||||||
|  | 		case ZPOOL_PROP_COMPATIBILITY: | ||||||
| 			if (zhp->zpool_props != NULL || | 			if (zhp->zpool_props != NULL || | ||||||
| 			    zpool_get_all_props(zhp) == 0) { | 			    zpool_get_all_props(zhp) == 0) { | ||||||
| 				(void) strlcpy(buf, | 				(void) strlcpy(buf, | ||||||
| @ -462,6 +468,8 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, | |||||||
| 	char *slash, *check; | 	char *slash, *check; | ||||||
| 	struct stat64 statbuf; | 	struct stat64 statbuf; | ||||||
| 	zpool_handle_t *zhp; | 	zpool_handle_t *zhp; | ||||||
|  | 	char badword[ZFS_MAXPROPLEN]; | ||||||
|  | 	char badfile[MAXPATHLEN]; | ||||||
| 
 | 
 | ||||||
| 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { | 	if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { | ||||||
| 		(void) no_memory(hdl); | 		(void) no_memory(hdl); | ||||||
| @ -671,6 +679,39 @@ zpool_valid_proplist(libzfs_handle_t *hdl, const char *poolname, | |||||||
| 			*slash = '/'; | 			*slash = '/'; | ||||||
| 			break; | 			break; | ||||||
| 
 | 
 | ||||||
|  | 		case ZPOOL_PROP_COMPATIBILITY: | ||||||
|  | 			switch (zpool_load_compat(strval, NULL, | ||||||
|  | 			    badword, badfile)) { | ||||||
|  | 			case ZPOOL_COMPATIBILITY_OK: | ||||||
|  | 				break; | ||||||
|  | 			case ZPOOL_COMPATIBILITY_READERR: | ||||||
|  | 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | ||||||
|  | 				    "error reading feature file '%s'"), | ||||||
|  | 				    badfile); | ||||||
|  | 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf); | ||||||
|  | 				goto error; | ||||||
|  | 			case ZPOOL_COMPATIBILITY_BADFILE: | ||||||
|  | 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | ||||||
|  | 				    "feature file '%s' too large or not " | ||||||
|  | 				    "newline-terminated"), | ||||||
|  | 				    badfile); | ||||||
|  | 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf); | ||||||
|  | 				goto error; | ||||||
|  | 			case ZPOOL_COMPATIBILITY_BADWORD: | ||||||
|  | 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | ||||||
|  | 				    "unknown feature '%s' in feature " | ||||||
|  | 				    "file '%s'"), | ||||||
|  | 				    badword, badfile); | ||||||
|  | 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf); | ||||||
|  | 				goto error; | ||||||
|  | 			case ZPOOL_COMPATIBILITY_NOFILES: | ||||||
|  | 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, | ||||||
|  | 				    "no feature files specified")); | ||||||
|  | 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf); | ||||||
|  | 				goto error; | ||||||
|  | 			} | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
| 		case ZPOOL_PROP_COMMENT: | 		case ZPOOL_PROP_COMMENT: | ||||||
| 			for (check = strval; *check != '\0'; check++) { | 			for (check = strval; *check != '\0'; check++) { | ||||||
| 				if (!isprint(*check)) { | 				if (!isprint(*check)) { | ||||||
| @ -4663,3 +4704,190 @@ zpool_get_bootenv(zpool_handle_t *zhp, nvlist_t **nvlp) | |||||||
| 
 | 
 | ||||||
| 	return (error); | 	return (error); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | /*
 | ||||||
|  |  * Attempt to read and parse feature file(s) (from "compatibility" property). | ||||||
|  |  * Files contain zpool feature names, comma or whitespace-separated. | ||||||
|  |  * Comments (# character to next newline) are discarded. | ||||||
|  |  * | ||||||
|  |  * Arguments: | ||||||
|  |  *  compatibility : string containing feature filenames | ||||||
|  |  *  features : either NULL or pointer to array of boolean | ||||||
|  |  *  badtoken : either NULL or pointer to char[ZFS_MAXPROPLEN] | ||||||
|  |  *  badfile : either NULL or pointer to char[MAXPATHLEN] | ||||||
|  |  * | ||||||
|  |  * compatibility is NULL (unset), "", "off", "legacy", or list of | ||||||
|  |  * comma-separated filenames. filenames should either be absolute, | ||||||
|  |  * or relative to: | ||||||
|  |  *   1) ZPOOL_SYSCONF_COMPAT_D (eg: /etc/zfs/compatibility.d) or | ||||||
|  |  *   2) ZPOOL_DATA_COMPAT_D (eg: /usr/share/zfs/compatibility.d). | ||||||
|  |  * (Unset), "" or "off" => enable all features | ||||||
|  |  * "legacy" => disable all features | ||||||
|  |  * Any feature names read from files which match unames in spa_feature_table | ||||||
|  |  * will have the corresponding boolean set in the features array (if non-NULL). | ||||||
|  |  * If more than one feature set specified, only features present in *all* of | ||||||
|  |  * them will be set. | ||||||
|  |  * | ||||||
|  |  * An unreadable filename will be strlcpy'd to badfile (if non-NULL). | ||||||
|  |  * An unrecognized feature will be strlcpy'd to badtoken (if non-NULL). | ||||||
|  |  * | ||||||
|  |  * Return values: | ||||||
|  |  *   ZPOOL_COMPATIBILITY_OK : files read and parsed ok | ||||||
|  |  *   ZPOOL_COMPATIBILITY_READERR : file could not be opened / mmap'd | ||||||
|  |  *   ZPOOL_COMPATIBILITY_BADFILE : file too big or not a text file | ||||||
|  |  *   ZPOOL_COMPATIBILITY_BADWORD : file contains invalid feature name | ||||||
|  |  *   ZPOOL_COMPATIBILITY_NOFILES  : no file names found | ||||||
|  |  */ | ||||||
|  | zpool_compat_status_t | ||||||
|  | zpool_load_compat(const char *compatibility, | ||||||
|  |     boolean_t *features, char *badtoken, char *badfile) | ||||||
|  | { | ||||||
|  | 	int sdirfd, ddirfd, featfd; | ||||||
|  | 	int i; | ||||||
|  | 	struct stat fs; | ||||||
|  | 	char *fc;			/* mmap of file */ | ||||||
|  | 	char *ps, *ls, *ws;		/* strtok state */ | ||||||
|  | 	char *file, *line, *word; | ||||||
|  | 	char filenames[ZFS_MAXPROPLEN]; | ||||||
|  | 	int filecount = 0; | ||||||
|  | 
 | ||||||
|  | 	/* special cases (unset), "" and "off" => enable all features */ | ||||||
|  | 	if (compatibility == NULL || compatibility[0] == '\0' || | ||||||
|  | 	    strcmp(compatibility, ZPOOL_COMPAT_OFF) == 0) { | ||||||
|  | 		if (features != NULL) | ||||||
|  | 			for (i = 0; i < SPA_FEATURES; i++) | ||||||
|  | 				features[i] = B_TRUE; | ||||||
|  | 		return (ZPOOL_COMPATIBILITY_OK); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/* Final special case "legacy" => disable all features */ | ||||||
|  | 	if (strcmp(compatibility, ZPOOL_COMPAT_LEGACY) == 0) { | ||||||
|  | 		if (features != NULL) | ||||||
|  | 			for (i = 0; i < SPA_FEATURES; i++) | ||||||
|  | 				features[i] = B_FALSE; | ||||||
|  | 		return (ZPOOL_COMPATIBILITY_OK); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * Start with all true; will be ANDed with results from each file | ||||||
|  | 	 */ | ||||||
|  | 	if (features != NULL) | ||||||
|  | 		for (i = 0; i < SPA_FEATURES; i++) | ||||||
|  | 			features[i] = B_TRUE; | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * We ignore errors from the directory open() | ||||||
|  | 	 * as they're only needed if the filename is relative | ||||||
|  | 	 * which will be checked during the openat(). | ||||||
|  | 	 */ | ||||||
|  | #ifdef O_PATH | ||||||
|  | 	sdirfd = open(ZPOOL_SYSCONF_COMPAT_D, O_DIRECTORY | O_PATH); | ||||||
|  | 	ddirfd = open(ZPOOL_DATA_COMPAT_D, O_DIRECTORY | O_PATH); | ||||||
|  | #else | ||||||
|  | 	sdirfd = open(ZPOOL_SYSCONF_COMPAT_D, O_DIRECTORY | O_RDONLY); | ||||||
|  | 	ddirfd = open(ZPOOL_DATA_COMPAT_D, O_DIRECTORY | O_RDONLY); | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
|  | 	(void) strlcpy(filenames, compatibility, ZFS_MAXPROPLEN); | ||||||
|  | 	file = strtok_r(filenames, ",", &ps); | ||||||
|  | 	while (file != NULL) { | ||||||
|  | 		boolean_t features_local[SPA_FEATURES]; | ||||||
|  | 
 | ||||||
|  | 		/* try sysconfdir first, then datadir */ | ||||||
|  | 		if ((featfd = openat(sdirfd, file, 0, O_RDONLY)) < 0) | ||||||
|  | 			featfd = openat(ddirfd, file, 0, O_RDONLY); | ||||||
|  | 
 | ||||||
|  | 		if (featfd < 0 || fstat(featfd, &fs) < 0) { | ||||||
|  | 			(void) close(featfd); | ||||||
|  | 			(void) close(sdirfd); | ||||||
|  | 			(void) close(ddirfd); | ||||||
|  | 			if (badfile != NULL) | ||||||
|  | 				(void) strlcpy(badfile, file, MAXPATHLEN); | ||||||
|  | 			return (ZPOOL_COMPATIBILITY_READERR); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Too big or too small */ | ||||||
|  | 		if (fs.st_size < 1 || fs.st_size > ZPOOL_COMPAT_MAXSIZE) { | ||||||
|  | 			(void) close(featfd); | ||||||
|  | 			(void) close(sdirfd); | ||||||
|  | 			(void) close(ddirfd); | ||||||
|  | 			if (badfile != NULL) | ||||||
|  | 				(void) strlcpy(badfile, file, MAXPATHLEN); | ||||||
|  | 			return (ZPOOL_COMPATIBILITY_BADFILE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* private mmap() so we can strtok safely */ | ||||||
|  | 		fc = (char *)mmap(NULL, fs.st_size, | ||||||
|  | 		    PROT_READ|PROT_WRITE, MAP_PRIVATE, featfd, 0); | ||||||
|  | 		(void) close(featfd); | ||||||
|  | 
 | ||||||
|  | 		if (fc < 0) { | ||||||
|  | 			(void) close(sdirfd); | ||||||
|  | 			(void) close(ddirfd); | ||||||
|  | 			if (badfile != NULL) | ||||||
|  | 				(void) strlcpy(badfile, file, MAXPATHLEN); | ||||||
|  | 			return (ZPOOL_COMPATIBILITY_READERR); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* Text file sanity check - last char should be newline */ | ||||||
|  | 		if (fc[fs.st_size - 1] != '\n') { | ||||||
|  | 			(void) munmap((void *) fc, fs.st_size); | ||||||
|  | 			(void) close(sdirfd); | ||||||
|  | 			(void) close(ddirfd); | ||||||
|  | 			if (badfile != NULL) | ||||||
|  | 				(void) strlcpy(badfile, file, MAXPATHLEN); | ||||||
|  | 			return (ZPOOL_COMPATIBILITY_BADFILE); | ||||||
|  | 		} | ||||||
|  | 
 | ||||||
|  | 		/* replace with NUL to ensure we have a delimiter */ | ||||||
|  | 		fc[fs.st_size - 1] = '\0'; | ||||||
|  | 
 | ||||||
|  | 		for (i = 0; i < SPA_FEATURES; i++) | ||||||
|  | 			features_local[i] = B_FALSE; | ||||||
|  | 
 | ||||||
|  | 		line = strtok_r(fc, "\n", &ls); | ||||||
|  | 		while (line != NULL) { | ||||||
|  | 			/* discard comments */ | ||||||
|  | 			*(strchrnul(line, '#')) = '\0'; | ||||||
|  | 
 | ||||||
|  | 			word = strtok_r(line, ", \t", &ws); | ||||||
|  | 			while (word != NULL) { | ||||||
|  | 				/* Find matching feature name */ | ||||||
|  | 				for (i = 0; i < SPA_FEATURES; i++) { | ||||||
|  | 					zfeature_info_t *fi = | ||||||
|  | 					    &spa_feature_table[i]; | ||||||
|  | 					if (strcmp(word, fi->fi_uname) == 0) { | ||||||
|  | 						features_local[i] = B_TRUE; | ||||||
|  | 						break; | ||||||
|  | 					} | ||||||
|  | 				} | ||||||
|  | 				if (i == SPA_FEATURES) { | ||||||
|  | 					if (badtoken != NULL) | ||||||
|  | 						(void) strlcpy(badtoken, word, | ||||||
|  | 						    ZFS_MAXPROPLEN); | ||||||
|  | 					if (badfile != NULL) | ||||||
|  | 						(void) strlcpy(badfile, file, | ||||||
|  | 						    MAXPATHLEN); | ||||||
|  | 					(void) munmap((void *) fc, fs.st_size); | ||||||
|  | 					(void) close(sdirfd); | ||||||
|  | 					(void) close(ddirfd); | ||||||
|  | 					return (ZPOOL_COMPATIBILITY_BADWORD); | ||||||
|  | 				} | ||||||
|  | 				word = strtok_r(NULL, ", \t", &ws); | ||||||
|  | 			} | ||||||
|  | 			line = strtok_r(NULL, "\n", &ls); | ||||||
|  | 		} | ||||||
|  | 		(void) munmap((void *) fc, fs.st_size); | ||||||
|  | 		if (features != NULL) { | ||||||
|  | 			for (i = 0; i < SPA_FEATURES; i++) | ||||||
|  | 				features[i] &= features_local[i]; | ||||||
|  | 		} | ||||||
|  | 		filecount++; | ||||||
|  | 		file = strtok_r(NULL, ",", &ps); | ||||||
|  | 	} | ||||||
|  | 	(void) close(sdirfd); | ||||||
|  | 	(void) close(ddirfd); | ||||||
|  | 	if (filecount == 0) | ||||||
|  | 		return (ZPOOL_COMPATIBILITY_NOFILES); | ||||||
|  | 	return (ZPOOL_COMPATIBILITY_OK); | ||||||
|  | } | ||||||
|  | |||||||
| @ -23,6 +23,7 @@ | |||||||
|  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. |  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. | ||||||
|  * Copyright (c) 2012 by Delphix. All rights reserved. |  * Copyright (c) 2012 by Delphix. All rights reserved. | ||||||
|  * Copyright (c) 2013 Steven Hartland. All rights reserved. |  * Copyright (c) 2013 Steven Hartland. All rights reserved. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -87,6 +88,7 @@ static char *zfs_msgid_table[] = { | |||||||
| 	 *	ZPOOL_STATUS_REMOVED_DEV | 	 *	ZPOOL_STATUS_REMOVED_DEV | ||||||
| 	 *	ZPOOL_STATUS_REBUILDING | 	 *	ZPOOL_STATUS_REBUILDING | ||||||
| 	 *	ZPOOL_STATUS_REBUILD_SCRUB | 	 *	ZPOOL_STATUS_REBUILD_SCRUB | ||||||
|  | 	 *	ZPOOL_STATUS_COMPATIBILITY_ERR | ||||||
| 	 *	ZPOOL_STATUS_OK | 	 *	ZPOOL_STATUS_OK | ||||||
| 	 */ | 	 */ | ||||||
| }; | }; | ||||||
| @ -218,7 +220,8 @@ find_vdev_problem(nvlist_t *vdev, int (*func)(vdev_stat_t *, uint_t), | |||||||
|  * only picks the most damaging of all the current errors to report. |  * only picks the most damaging of all the current errors to report. | ||||||
|  */ |  */ | ||||||
| static zpool_status_t | static zpool_status_t | ||||||
| check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) | check_status(nvlist_t *config, boolean_t isimport, | ||||||
|  |     zpool_errata_t *erratap, const char *compat) | ||||||
| { | { | ||||||
| 	nvlist_t *nvroot; | 	nvlist_t *nvroot; | ||||||
| 	vdev_stat_t *vs; | 	vdev_stat_t *vs; | ||||||
| @ -471,9 +474,16 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) | |||||||
| 			    ZPOOL_CONFIG_FEATURE_STATS); | 			    ZPOOL_CONFIG_FEATURE_STATS); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
|  | 		/* check against all features, or limited set? */ | ||||||
|  | 		boolean_t pool_features[SPA_FEATURES]; | ||||||
|  | 
 | ||||||
|  | 		if (zpool_load_compat(compat, pool_features, NULL, NULL) != | ||||||
|  | 		    ZPOOL_COMPATIBILITY_OK) | ||||||
|  | 			return (ZPOOL_STATUS_COMPATIBILITY_ERR); | ||||||
| 		for (i = 0; i < SPA_FEATURES; i++) { | 		for (i = 0; i < SPA_FEATURES; i++) { | ||||||
| 			zfeature_info_t *fi = &spa_feature_table[i]; | 			zfeature_info_t *fi = &spa_feature_table[i]; | ||||||
| 			if (!nvlist_exists(feat, fi->fi_guid)) | 			if (pool_features[i] && | ||||||
|  | 			    !nvlist_exists(feat, fi->fi_guid)) | ||||||
| 				return (ZPOOL_STATUS_FEAT_DISABLED); | 				return (ZPOOL_STATUS_FEAT_DISABLED); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| @ -484,7 +494,18 @@ check_status(nvlist_t *config, boolean_t isimport, zpool_errata_t *erratap) | |||||||
| zpool_status_t | zpool_status_t | ||||||
| zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata) | zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata) | ||||||
| { | { | ||||||
| 	zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata); | 	/*
 | ||||||
|  | 	 * pass in the desired feature set, as | ||||||
|  | 	 * it affects check for disabled features | ||||||
|  | 	 */ | ||||||
|  | 	char compatibility[ZFS_MAXPROPLEN]; | ||||||
|  | 	if (zpool_get_prop(zhp, ZPOOL_PROP_COMPATIBILITY, compatibility, | ||||||
|  | 	    ZFS_MAXPROPLEN, NULL, B_FALSE) != 0) | ||||||
|  | 		compatibility[0] = '\0'; | ||||||
|  | 
 | ||||||
|  | 	zpool_status_t ret = check_status(zhp->zpool_config, B_FALSE, errata, | ||||||
|  | 	    compatibility); | ||||||
|  | 
 | ||||||
| 	if (msgid != NULL) { | 	if (msgid != NULL) { | ||||||
| 		if (ret >= NMSGID) | 		if (ret >= NMSGID) | ||||||
| 			*msgid = NULL; | 			*msgid = NULL; | ||||||
| @ -497,7 +518,7 @@ zpool_get_status(zpool_handle_t *zhp, char **msgid, zpool_errata_t *errata) | |||||||
| zpool_status_t | zpool_status_t | ||||||
| zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata) | zpool_import_status(nvlist_t *config, char **msgid, zpool_errata_t *errata) | ||||||
| { | { | ||||||
| 	zpool_status_t ret = check_status(config, B_TRUE, errata); | 	zpool_status_t ret = check_status(config, B_TRUE, errata, NULL); | ||||||
| 
 | 
 | ||||||
| 	if (ret >= NMSGID) | 	if (ret >= NMSGID) | ||||||
| 		*msgid = NULL; | 		*msgid = NULL; | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
|  * Copyright (c) 2012, 2018 by Delphix. All rights reserved. |  * Copyright (c) 2012, 2018 by Delphix. All rights reserved. | ||||||
|  * Copyright 2015 RackTop Systems. |  * Copyright 2015 RackTop Systems. | ||||||
|  * Copyright (c) 2016, Intel Corporation. |  * Copyright (c) 2016, Intel Corporation. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -552,12 +553,14 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, | |||||||
| 				 *	pool guid | 				 *	pool guid | ||||||
| 				 *	name | 				 *	name | ||||||
| 				 *	comment (if available) | 				 *	comment (if available) | ||||||
|  | 				 *	compatibility features (if available) | ||||||
| 				 *	pool state | 				 *	pool state | ||||||
| 				 *	hostid (if available) | 				 *	hostid (if available) | ||||||
| 				 *	hostname (if available) | 				 *	hostname (if available) | ||||||
| 				 */ | 				 */ | ||||||
| 				uint64_t state, version; | 				uint64_t state, version; | ||||||
| 				char *comment = NULL; | 				char *comment = NULL; | ||||||
|  | 				char *compatibility = NULL; | ||||||
| 
 | 
 | ||||||
| 				version = fnvlist_lookup_uint64(tmp, | 				version = fnvlist_lookup_uint64(tmp, | ||||||
| 				    ZPOOL_CONFIG_VERSION); | 				    ZPOOL_CONFIG_VERSION); | ||||||
| @ -577,6 +580,13 @@ get_configs(libpc_handle_t *hdl, pool_list_t *pl, boolean_t active_ok, | |||||||
| 					fnvlist_add_string(config, | 					fnvlist_add_string(config, | ||||||
| 					    ZPOOL_CONFIG_COMMENT, comment); | 					    ZPOOL_CONFIG_COMMENT, comment); | ||||||
| 
 | 
 | ||||||
|  | 				if (nvlist_lookup_string(tmp, | ||||||
|  | 				    ZPOOL_CONFIG_COMPATIBILITY, | ||||||
|  | 				    &compatibility) == 0) | ||||||
|  | 					fnvlist_add_string(config, | ||||||
|  | 					    ZPOOL_CONFIG_COMPATIBILITY, | ||||||
|  | 					    compatibility); | ||||||
|  | 
 | ||||||
| 				state = fnvlist_lookup_uint64(tmp, | 				state = fnvlist_lookup_uint64(tmp, | ||||||
| 				    ZPOOL_CONFIG_POOL_STATE); | 				    ZPOOL_CONFIG_POOL_STATE); | ||||||
| 				fnvlist_add_uint64(config, | 				fnvlist_add_uint64(config, | ||||||
|  | |||||||
| @ -16,6 +16,7 @@ | |||||||
| .\" Portions Copyright [yyyy] [name of copyright owner] | .\" Portions Copyright [yyyy] [name of copyright owner] | ||||||
| .\" Copyright (c) 2019, Klara Inc. | .\" Copyright (c) 2019, Klara Inc. | ||||||
| .\" Copyright (c) 2019, Allan Jude | .\" Copyright (c) 2019, Allan Jude | ||||||
|  | .\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
| .TH ZPOOL-FEATURES 5 "Aug 24, 2020" OpenZFS | .TH ZPOOL-FEATURES 5 "Aug 24, 2020" OpenZFS | ||||||
| .SH NAME | .SH NAME | ||||||
| zpool\-features \- ZFS pool feature descriptions | zpool\-features \- ZFS pool feature descriptions | ||||||
| @ -26,7 +27,8 @@ ZFS pool on\-disk format versions are specified via "features" which replace | |||||||
| the old on\-disk format numbers (the last supported on\-disk format number is | the old on\-disk format numbers (the last supported on\-disk format number is | ||||||
| 28). To enable a feature on a pool use the \fBupgrade\fR subcommand of the | 28). To enable a feature on a pool use the \fBupgrade\fR subcommand of the | ||||||
| zpool(8) command, or set the \fBfeature@\fR\fIfeature_name\fR property | zpool(8) command, or set the \fBfeature@\fR\fIfeature_name\fR property | ||||||
| to \fBenabled\fR. | to \fBenabled\fR. Please also see the \fB"Compatibility feature sets"\fR | ||||||
|  | section for information on how sets of features may be enabled together. | ||||||
| .sp | .sp | ||||||
| .LP | .LP | ||||||
| The pool format does not affect file system version compatibility or the ability | The pool format does not affect file system version compatibility or the ability | ||||||
| @ -140,6 +142,61 @@ read\-only mode. | |||||||
| Some features depend on other features being enabled in order to function | Some features depend on other features being enabled in order to function | ||||||
| properly. Enabling a feature will automatically enable any features it | properly. Enabling a feature will automatically enable any features it | ||||||
| depends on. | depends on. | ||||||
|  | 
 | ||||||
|  | .SS "Compatibility feature sets" | ||||||
|  | .sp | ||||||
|  | .LP | ||||||
|  | It is sometimes necessary for a pool to maintain compatibility with a | ||||||
|  | specific on\-disk format, by enabling and disabling particular features. The | ||||||
|  | \fBcompatibility\fR feature facilitates this by allowing feature sets to | ||||||
|  | be read from text files. When set to \fBoff\fR (the default); compatibility | ||||||
|  | feature sets are disabled (ie: all features are enabled); when set to | ||||||
|  | \fBlegacy\fR; no features are enabled. When set to a comma\-separated list | ||||||
|  | of filenames (each filename may either be an absolute path, or relative to | ||||||
|  | \fB/etc/zfs/compatibility.d\fR or \fB/usr/share/zfs/compatibility.d\fR) | ||||||
|  | the lists of requested features are read from those files, separated by | ||||||
|  | whitespace and/or commas. Only features present in all files are enabled. | ||||||
|  | .LP | ||||||
|  | Simple sanity checks are applied to the files; they must be between 1 and | ||||||
|  | 16,384 bytes in size, and must end with a newline character. | ||||||
|  | .LP | ||||||
|  | The requested features are applied when a pool is created using | ||||||
|  | \fBzpool create \-o compatibility=...\fR and controls which features are | ||||||
|  | enabled when using \fBzpool upgrade\fR. \fBzpool status\fR | ||||||
|  | will not show a warning about disabled features which are not part | ||||||
|  | of the requested feature set. | ||||||
|  | .LP | ||||||
|  | By convention, compatibility files in \fB/usr/share/zfs/compatibility.d\fR | ||||||
|  | are provided by the distribution package, and include feature sets | ||||||
|  | supported by important versions of popular distribtions, and feature | ||||||
|  | sets commonly supported at the start of each year.  Compatibility files | ||||||
|  | in \fB/etc/zfs/compatibility.d\fR, if present, will take precedence over | ||||||
|  | files with the same name in \fB/usr/share/zfs/compatibility.d\fR. | ||||||
|  | .LP | ||||||
|  | Compatibility files may include comments; any text from \fB#\fR to the end | ||||||
|  | of the line is ignored. | ||||||
|  | .LP | ||||||
|  | \fBExample:\fR | ||||||
|  | .EX | ||||||
|  | # \fBcat /usr/share/zfs/compatibility.d/grub2\fR | ||||||
|  | # Features which are supported by GRUB2 | ||||||
|  | async_destroy | ||||||
|  | bookmarks | ||||||
|  | embedded_data | ||||||
|  | empty_bpobj | ||||||
|  | enabled_txg | ||||||
|  | extensible_dataset | ||||||
|  | filesystem_limits | ||||||
|  | hole_birth | ||||||
|  | large_blocks | ||||||
|  | lz4_compress | ||||||
|  | spacemap_histogram | ||||||
|  | 
 | ||||||
|  | # \fBzpool create \-o compatibility=grub2 bootpool vdev\fR | ||||||
|  | .EE | ||||||
|  | .LP | ||||||
|  | See \fBzpool\-create(8)\fR and \fBzpool\-upgrade(8)\fR for more information | ||||||
|  | on how these commands are affected by feature sets. | ||||||
| .SH FEATURES | .SH FEATURES | ||||||
| .sp | .sp | ||||||
| .LP | .LP | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ | |||||||
| .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | ||||||
| .\" Copyright 2017 Nexenta Systems, Inc. | .\" Copyright 2017 Nexenta Systems, Inc. | ||||||
| .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  | .\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
| .\" | .\" | ||||||
| .Dd August 9, 2019 | .Dd August 9, 2019 | ||||||
| .Dt ZPOOL-CREATE 8 | .Dt ZPOOL-CREATE 8 | ||||||
| @ -40,6 +41,7 @@ | |||||||
| .Op Fl m Ar mountpoint | .Op Fl m Ar mountpoint | ||||||
| .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... | .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... | ||||||
| .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc | .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc | ||||||
|  | .Op Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... | ||||||
| .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... | .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... | ||||||
| .Op Fl R Ar root | .Op Fl R Ar root | ||||||
| .Ar pool vdev Ns ... | .Ar pool vdev Ns ... | ||||||
| @ -52,6 +54,7 @@ | |||||||
| .Op Fl m Ar mountpoint | .Op Fl m Ar mountpoint | ||||||
| .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... | .Oo Fl o Ar property Ns = Ns Ar value Oc Ns ... | ||||||
| .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc Ns ... | .Oo Fl o Ar feature@feature Ns = Ns Ar value Oc Ns ... | ||||||
|  | .Op Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... | ||||||
| .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... | .Oo Fl O Ar file-system-property Ns = Ns Ar value Oc Ns ... | ||||||
| .Op Fl R Ar root | .Op Fl R Ar root | ||||||
| .Op Fl t Ar tname | .Op Fl t Ar tname | ||||||
| @ -135,9 +138,14 @@ This can be overridden with the | |||||||
| .Fl m | .Fl m | ||||||
| option. | option. | ||||||
| .Pp | .Pp | ||||||
| By default all supported features are enabled on the new pool unless the | By default all supported features are enabled on the new pool. The | ||||||
| .Fl d | .Fl d | ||||||
| option is specified. | option or the | ||||||
|  | .Fl o Ar compatibility | ||||||
|  | property (eg: | ||||||
|  | .Fl o Ar compatibility=2020 | ||||||
|  | ) can be used to restrict the features that are enabled, so that the | ||||||
|  | pool can be imported on other releases of the ZFS software. | ||||||
| .Bl -tag -width Ds | .Bl -tag -width Ds | ||||||
| .It Fl d | .It Fl d | ||||||
| Do not enable any features on the new pool. | Do not enable any features on the new pool. | ||||||
| @ -179,6 +187,10 @@ Sets the given pool properties. | |||||||
| See the | See the | ||||||
| .Xr zpoolprops | .Xr zpoolprops | ||||||
| manual page for a list of valid properties that can be set. | manual page for a list of valid properties that can be set. | ||||||
|  | .It Fl o Ar compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... | ||||||
|  | Specifies compatibility feature sets. See | ||||||
|  | .Xr zpool-features 5 | ||||||
|  | for more information about compatibility feature sets. | ||||||
| .It Fl o Ar feature@feature Ns = Ns Ar value | .It Fl o Ar feature@feature Ns = Ns Ar value | ||||||
| Sets the given pool feature. See the | Sets the given pool feature. See the | ||||||
| .Xr zpool-features 5 | .Xr zpool-features 5 | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ | |||||||
| .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | ||||||
| .\" Copyright 2017 Nexenta Systems, Inc. | .\" Copyright 2017 Nexenta Systems, Inc. | ||||||
| .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  | .\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
| .\" | .\" | ||||||
| .Dd August 9, 2019 | .Dd August 9, 2019 | ||||||
| .Dt ZPOOL-UPGRADE 8 | .Dt ZPOOL-UPGRADE 8 | ||||||
| @ -54,7 +55,11 @@ formatted using a legacy ZFS version number. | |||||||
| These pools can continue to be used, but some features may not be available. | These pools can continue to be used, but some features may not be available. | ||||||
| Use | Use | ||||||
| .Nm zpool Cm upgrade Fl a | .Nm zpool Cm upgrade Fl a | ||||||
| to enable all features on all pools. | to enable all features on all pools. (If a pool has specified compatibility | ||||||
|  | feature sets using the | ||||||
|  | .Fl o Ar compatibility | ||||||
|  | property, only the features present in all requested compatibility sets will | ||||||
|  | be enabled on that pool.) | ||||||
| .It Xo | .It Xo | ||||||
| .Nm zpool | .Nm zpool | ||||||
| .Cm upgrade | .Cm upgrade | ||||||
| @ -70,7 +75,11 @@ for a description of feature flags features supported by the current software. | |||||||
| .Op Fl V Ar version | .Op Fl V Ar version | ||||||
| .Fl a Ns | Ns Ar pool Ns ... | .Fl a Ns | Ns Ar pool Ns ... | ||||||
| .Xc | .Xc | ||||||
| Enables all supported features on the given pool. | Enables all supported features on the given pool. (If the pool has specified | ||||||
|  | compatibility feature sets using the | ||||||
|  | .Fl o Ar compatibility | ||||||
|  | property, only the features present in all requested compatibility sets will be | ||||||
|  | enabled.) | ||||||
| Once this is done, the pool will no longer be accessible on systems that do not | Once this is done, the pool will no longer be accessible on systems that do not | ||||||
| support feature flags. | support feature flags. | ||||||
| See | See | ||||||
| @ -79,7 +88,8 @@ for details on compatibility with systems that support feature flags, but do not | |||||||
| support all features enabled on the pool. | support all features enabled on the pool. | ||||||
| .Bl -tag -width Ds | .Bl -tag -width Ds | ||||||
| .It Fl a | .It Fl a | ||||||
| Enables all supported features on all pools. | Enables all supported features (from specified compatibility sets, if any) on all | ||||||
|  | pools. | ||||||
| .It Fl V Ar version | .It Fl V Ar version | ||||||
| Upgrade to the specified legacy version. | Upgrade to the specified legacy version. | ||||||
| If the | If the | ||||||
|  | |||||||
| @ -26,6 +26,7 @@ | |||||||
| .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | .\" Copyright (c) 2018 George Melikov. All Rights Reserved. | ||||||
| .\" Copyright 2017 Nexenta Systems, Inc. | .\" Copyright 2017 Nexenta Systems, Inc. | ||||||
| .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | .\" Copyright (c) 2017 Open-E, Inc. All Rights Reserved. | ||||||
|  | .\" Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
| .\" | .\" | ||||||
| .Dd August 9, 2019 | .Dd August 9, 2019 | ||||||
| .Dt ZPOOLPROPS 8 | .Dt ZPOOLPROPS 8 | ||||||
| @ -285,6 +286,24 @@ A text string consisting of printable ASCII characters that will be stored | |||||||
| such that it is available even if the pool becomes faulted. | such that it is available even if the pool becomes faulted. | ||||||
| An administrator can provide additional information about a pool using this | An administrator can provide additional information about a pool using this | ||||||
| property. | property. | ||||||
|  | .It Sy compatibility Ns = Ns Ar off | legacy | file Bq , Ns Ar file Ns ... | ||||||
|  | Specifies that the pool maintain compatibility with specific feature sets. | ||||||
|  | When set to | ||||||
|  | .Sy off | ||||||
|  | (or unset); compatibility is disabled (all features are enabled); when set to | ||||||
|  | .Sy legacy Ns ; | ||||||
|  | no features are enabled. When set to a comma-separated list of | ||||||
|  | filenames (each filename may either be an absolute path, or relative to | ||||||
|  | .Pa /etc/zfs/compatibility.d or Pa /usr/share/zfs/compatibility.d Ns ) | ||||||
|  | the lists of requested features are read from those files, separated by | ||||||
|  | whitespace and/or commas. Only features present in all files are enabled. | ||||||
|  | 
 | ||||||
|  | See | ||||||
|  | .Xr zpool-features 5 Ns , | ||||||
|  | .Xr zpool-create 8 | ||||||
|  | and | ||||||
|  | .Xr zpool-upgrade 8 | ||||||
|  | for more information on the operation of compatibility feature sets. | ||||||
| .It Sy dedupditto Ns = Ns Ar number | .It Sy dedupditto Ns = Ns Ar number | ||||||
| This property is deprecated and no longer has any effect. | This property is deprecated and no longer has any effect. | ||||||
| .It Sy delegation Ns = Ns Sy on Ns | Ns Sy off | .It Sy delegation Ns = Ns Sy on Ns | Ns Sy off | ||||||
|  | |||||||
| @ -22,6 +22,7 @@ | |||||||
|  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. |  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. | ||||||
|  * Copyright 2011 Nexenta Systems, Inc. All rights reserved. |  * Copyright 2011 Nexenta Systems, Inc. All rights reserved. | ||||||
|  * Copyright (c) 2012, 2018 by Delphix. All rights reserved. |  * Copyright (c) 2012, 2018 by Delphix. All rights reserved. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <sys/zio.h> | #include <sys/zio.h> | ||||||
| @ -71,6 +72,9 @@ zpool_prop_init(void) | |||||||
| 	    PROP_DEFAULT, ZFS_TYPE_POOL, "<file> | none", "CACHEFILE"); | 	    PROP_DEFAULT, ZFS_TYPE_POOL, "<file> | none", "CACHEFILE"); | ||||||
| 	zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL, | 	zprop_register_string(ZPOOL_PROP_COMMENT, "comment", NULL, | ||||||
| 	    PROP_DEFAULT, ZFS_TYPE_POOL, "<comment-string>", "COMMENT"); | 	    PROP_DEFAULT, ZFS_TYPE_POOL, "<comment-string>", "COMMENT"); | ||||||
|  | 	zprop_register_string(ZPOOL_PROP_COMPATIBILITY, "compatibility", | ||||||
|  | 	    "off", PROP_DEFAULT, ZFS_TYPE_POOL, | ||||||
|  | 	    "<file[,file...]> | off | legacy", "COMPATIBILITY"); | ||||||
| 
 | 
 | ||||||
| 	/* readonly number properties */ | 	/* readonly number properties */ | ||||||
| 	zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY, | 	zprop_register_number(ZPOOL_PROP_SIZE, "size", 0, PROP_READONLY, | ||||||
|  | |||||||
| @ -32,6 +32,7 @@ | |||||||
|  * Copyright (c) 2017, 2019, Datto Inc. All rights reserved. |  * Copyright (c) 2017, 2019, Datto Inc. All rights reserved. | ||||||
|  * Copyright 2017 Joyent, Inc. |  * Copyright 2017 Joyent, Inc. | ||||||
|  * Copyright (c) 2017, Intel Corporation. |  * Copyright (c) 2017, Intel Corporation. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| /*
 | /*
 | ||||||
| @ -377,6 +378,11 @@ spa_prop_get_config(spa_t *spa, nvlist_t **nvp) | |||||||
| 		    0, ZPROP_SRC_LOCAL); | 		    0, ZPROP_SRC_LOCAL); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	if (spa->spa_compatibility != NULL) { | ||||||
|  | 		spa_prop_add_list(*nvp, ZPOOL_PROP_COMPATIBILITY, | ||||||
|  | 		    spa->spa_compatibility, 0, ZPROP_SRC_LOCAL); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	if (spa->spa_root != NULL) | 	if (spa->spa_root != NULL) | ||||||
| 		spa_prop_add_list(*nvp, ZPOOL_PROP_ALTROOT, spa->spa_root, | 		spa_prop_add_list(*nvp, ZPOOL_PROP_ALTROOT, spa->spa_root, | ||||||
| 		    0, ZPROP_SRC_LOCAL); | 		    0, ZPROP_SRC_LOCAL); | ||||||
| @ -1669,6 +1675,10 @@ spa_unload(spa_t *spa) | |||||||
| 		spa_strfree(spa->spa_comment); | 		spa_strfree(spa->spa_comment); | ||||||
| 		spa->spa_comment = NULL; | 		spa->spa_comment = NULL; | ||||||
| 	} | 	} | ||||||
|  | 	if (spa->spa_compatibility != NULL) { | ||||||
|  | 		spa_strfree(spa->spa_compatibility); | ||||||
|  | 		spa->spa_compatibility = NULL; | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
| 	spa_config_exit(spa, SCL_ALL, spa); | 	spa_config_exit(spa, SCL_ALL, spa); | ||||||
| } | } | ||||||
| @ -3249,6 +3259,7 @@ spa_ld_parse_config(spa_t *spa, spa_import_type_t type) | |||||||
| 	vdev_t *rvd; | 	vdev_t *rvd; | ||||||
| 	uint64_t pool_guid; | 	uint64_t pool_guid; | ||||||
| 	char *comment; | 	char *comment; | ||||||
|  | 	char *compatibility; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Versioning wasn't explicitly added to the label until later, so if | 	 * Versioning wasn't explicitly added to the label until later, so if | ||||||
| @ -3297,6 +3308,11 @@ spa_ld_parse_config(spa_t *spa, spa_import_type_t type) | |||||||
| 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) | 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMMENT, &comment) == 0) | ||||||
| 		spa->spa_comment = spa_strdup(comment); | 		spa->spa_comment = spa_strdup(comment); | ||||||
| 
 | 
 | ||||||
|  | 	ASSERT(spa->spa_compatibility == NULL); | ||||||
|  | 	if (nvlist_lookup_string(config, ZPOOL_CONFIG_COMPATIBILITY, | ||||||
|  | 	    &compatibility) == 0) | ||||||
|  | 		spa->spa_compatibility = spa_strdup(compatibility); | ||||||
|  | 
 | ||||||
| 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, | 	(void) nvlist_lookup_uint64(config, ZPOOL_CONFIG_POOL_TXG, | ||||||
| 	    &spa->spa_config_txg); | 	    &spa->spa_config_txg); | ||||||
| 
 | 
 | ||||||
| @ -8668,6 +8684,20 @@ spa_sync_props(void *arg, dmu_tx_t *tx) | |||||||
| 			spa_history_log_internal(spa, "set", tx, | 			spa_history_log_internal(spa, "set", tx, | ||||||
| 			    "%s=%s", nvpair_name(elem), strval); | 			    "%s=%s", nvpair_name(elem), strval); | ||||||
| 			break; | 			break; | ||||||
|  | 		case ZPOOL_PROP_COMPATIBILITY: | ||||||
|  | 			strval = fnvpair_value_string(elem); | ||||||
|  | 			if (spa->spa_compatibility != NULL) | ||||||
|  | 				spa_strfree(spa->spa_compatibility); | ||||||
|  | 			spa->spa_compatibility = spa_strdup(strval); | ||||||
|  | 			/*
 | ||||||
|  | 			 * Dirty the configuration on vdevs as above. | ||||||
|  | 			 */ | ||||||
|  | 			if (tx->tx_txg != TXG_INITIAL) | ||||||
|  | 				vdev_config_dirty(spa->spa_root_vdev); | ||||||
|  | 			spa_history_log_internal(spa, "set", tx, | ||||||
|  | 			    "%s=%s", nvpair_name(elem), strval); | ||||||
|  | 			break; | ||||||
|  | 
 | ||||||
| 		default: | 		default: | ||||||
| 			/*
 | 			/*
 | ||||||
| 			 * Set pool property values in the poolprops mos object. | 			 * Set pool property values in the poolprops mos object. | ||||||
|  | |||||||
| @ -24,6 +24,7 @@ | |||||||
|  * Copyright 2011 Nexenta Systems, Inc. All rights reserved. |  * Copyright 2011 Nexenta Systems, Inc. All rights reserved. | ||||||
|  * Copyright (c) 2011, 2020 by Delphix. All rights reserved. |  * Copyright (c) 2011, 2020 by Delphix. All rights reserved. | ||||||
|  * Copyright 2017 Joyent, Inc. |  * Copyright 2017 Joyent, Inc. | ||||||
|  |  * Copyright (c) 2021, Colm Buckley <colm@tuatha.org> | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <sys/spa.h> | #include <sys/spa.h> | ||||||
| @ -446,6 +447,9 @@ spa_config_generate(spa_t *spa, vdev_t *vd, uint64_t txg, int getstats) | |||||||
| 	if (spa->spa_comment != NULL) | 	if (spa->spa_comment != NULL) | ||||||
| 		fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT, | 		fnvlist_add_string(config, ZPOOL_CONFIG_COMMENT, | ||||||
| 		    spa->spa_comment); | 		    spa->spa_comment); | ||||||
|  | 	if (spa->spa_compatibility != NULL) | ||||||
|  | 		fnvlist_add_string(config, ZPOOL_CONFIG_COMPATIBILITY, | ||||||
|  | 		    spa->spa_compatibility); | ||||||
| 
 | 
 | ||||||
| 	hostid = spa_get_hostid(spa); | 	hostid = spa_get_hostid(spa); | ||||||
| 	if (hostid != 0) | 	if (hostid != 0) | ||||||
|  | |||||||
| @ -457,6 +457,7 @@ systemctl --system daemon-reload >/dev/null || true | |||||||
| %{_udevdir}/vdev_id | %{_udevdir}/vdev_id | ||||||
| %{_udevdir}/zvol_id | %{_udevdir}/zvol_id | ||||||
| %{_udevdir}/rules.d/* | %{_udevdir}/rules.d/* | ||||||
|  | %{_datadir}/%{name}/compatibility.d | ||||||
| %if ! 0%{?_systemd} || 0%{?_initramfs} | %if ! 0%{?_systemd} || 0%{?_initramfs} | ||||||
| # Files needed for sysvinit and initramfs-tools | # Files needed for sysvinit and initramfs-tools | ||||||
| %{_sysconfdir}/%{name}/zfs-functions | %{_sysconfdir}/%{name}/zfs-functions | ||||||
| @ -503,7 +504,10 @@ systemctl --system daemon-reload >/dev/null || true | |||||||
| %doc AUTHORS COPYRIGHT LICENSE NOTICE README.md | %doc AUTHORS COPYRIGHT LICENSE NOTICE README.md | ||||||
| 
 | 
 | ||||||
| %files test | %files test | ||||||
| %{_datadir}/%{name} | %{_datadir}/%{name}/zfs-tests | ||||||
|  | %{_datadir}/%{name}/test-runner | ||||||
|  | %{_datadir}/%{name}/runfiles | ||||||
|  | %{_datadir}/%{name}/*.sh | ||||||
| 
 | 
 | ||||||
| %files dracut | %files dracut | ||||||
| %doc contrib/dracut/README.dracut.markdown | %doc contrib/dracut/README.dracut.markdown | ||||||
|  | |||||||
| @ -34,6 +34,7 @@ export ZEDLET_ETC_DIR=$$CMD_DIR/zed/zed.d | |||||||
| export ZEDLET_LIBEXEC_DIR=$$CMD_DIR/zed/zed.d | export ZEDLET_LIBEXEC_DIR=$$CMD_DIR/zed/zed.d | ||||||
| export ZPOOL_SCRIPT_DIR=$$CMD_DIR/zpool/zpool.d | export ZPOOL_SCRIPT_DIR=$$CMD_DIR/zpool/zpool.d | ||||||
| export ZPOOL_SCRIPTS_PATH=$$CMD_DIR/zpool/zpool.d | export ZPOOL_SCRIPTS_PATH=$$CMD_DIR/zpool/zpool.d | ||||||
|  | export ZPOOL_COMPAT_DIR=$$CMD_DIR/zpool/compatibility.d | ||||||
| export CONTRIB_DIR=@abs_top_builddir@/contrib | export CONTRIB_DIR=@abs_top_builddir@/contrib | ||||||
| export LIB_DIR=@abs_top_builddir@/lib | export LIB_DIR=@abs_top_builddir@/lib | ||||||
| export SYSCONF_DIR=@abs_top_builddir@/etc | export SYSCONF_DIR=@abs_top_builddir@/etc | ||||||
|  | |||||||
| @ -344,7 +344,8 @@ tests = ['zpool_create_001_pos', 'zpool_create_002_pos', | |||||||
|     'zpool_create_draid_003_pos', 'zpool_create_draid_004_pos', |     'zpool_create_draid_003_pos', 'zpool_create_draid_004_pos', | ||||||
|     'zpool_create_features_001_pos', 'zpool_create_features_002_pos', |     'zpool_create_features_001_pos', 'zpool_create_features_002_pos', | ||||||
|     'zpool_create_features_003_pos', 'zpool_create_features_004_neg', |     'zpool_create_features_003_pos', 'zpool_create_features_004_neg', | ||||||
|     'zpool_create_features_005_pos', |     'zpool_create_features_005_pos', 'zpool_create_features_006_pos', | ||||||
|  |     'zpool_create_features_007_pos', 'zpool_create_features_008_pos', | ||||||
|     'create-o_ashift', 'zpool_create_tempname', 'zpool_create_dryrun_output'] |     'create-o_ashift', 'zpool_create_tempname', 'zpool_create_dryrun_output'] | ||||||
| tags = ['functional', 'cli_root', 'zpool_create'] | tags = ['functional', 'cli_root', 'zpool_create'] | ||||||
| 
 | 
 | ||||||
| @ -468,7 +469,8 @@ tests = ['zpool_split_cliargs', 'zpool_split_devices', | |||||||
| tags = ['functional', 'cli_root', 'zpool_split'] | tags = ['functional', 'cli_root', 'zpool_split'] | ||||||
| 
 | 
 | ||||||
| [tests/functional/cli_root/zpool_status] | [tests/functional/cli_root/zpool_status] | ||||||
| tests = ['zpool_status_001_pos', 'zpool_status_002_pos'] | tests = ['zpool_status_001_pos', 'zpool_status_002_pos', | ||||||
|  |     'zpool_status_features_001_pos'] | ||||||
| tags = ['functional', 'cli_root', 'zpool_status'] | tags = ['functional', 'cli_root', 'zpool_status'] | ||||||
| 
 | 
 | ||||||
| [tests/functional/cli_root/zpool_sync] | [tests/functional/cli_root/zpool_sync] | ||||||
| @ -491,7 +493,7 @@ tests = ['zpool_upgrade_001_pos', 'zpool_upgrade_002_pos', | |||||||
|     'zpool_upgrade_003_pos', 'zpool_upgrade_004_pos', |     'zpool_upgrade_003_pos', 'zpool_upgrade_004_pos', | ||||||
|     'zpool_upgrade_005_neg', 'zpool_upgrade_006_neg', |     'zpool_upgrade_005_neg', 'zpool_upgrade_006_neg', | ||||||
|     'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos', |     'zpool_upgrade_007_pos', 'zpool_upgrade_008_pos', | ||||||
|     'zpool_upgrade_009_neg'] |     'zpool_upgrade_009_neg', 'zpool_upgrade_features_001_pos'] | ||||||
| tags = ['functional', 'cli_root', 'zpool_upgrade'] | tags = ['functional', 'cli_root', 'zpool_upgrade'] | ||||||
| 
 | 
 | ||||||
| [tests/functional/cli_root/zpool_wait] | [tests/functional/cli_root/zpool_wait] | ||||||
|  | |||||||
| @ -37,6 +37,7 @@ | |||||||
| export ZEDLET_ETC_DIR=${ZEDLET_ETC_DIR:-@sysconfdir@/zfs/zed.d} | export ZEDLET_ETC_DIR=${ZEDLET_ETC_DIR:-@sysconfdir@/zfs/zed.d} | ||||||
| export ZEDLET_LIBEXEC_DIR=${ZEDLET_LIBEXEC_DIR:-@zfsexecdir@/zed.d} | export ZEDLET_LIBEXEC_DIR=${ZEDLET_LIBEXEC_DIR:-@zfsexecdir@/zed.d} | ||||||
| export ZPOOL_SCRIPT_DIR=${ZPOOL_SCRIPT_DIR:-@sysconfdir@/zfs/zpool.d} | export ZPOOL_SCRIPT_DIR=${ZPOOL_SCRIPT_DIR:-@sysconfdir@/zfs/zpool.d} | ||||||
|  | export ZPOOL_COMPAT_DIR=${ZPOOL_COMPAT_DIR:-@datadir@/zfs/compatibility.d} | ||||||
| 
 | 
 | ||||||
| # Define run length constants | # Define run length constants | ||||||
| export RT_LONG="3" | export RT_LONG="3" | ||||||
|  | |||||||
| @ -36,6 +36,9 @@ dist_pkgdata_SCRIPTS = \ | |||||||
| 	zpool_create_features_003_pos.ksh \
 | 	zpool_create_features_003_pos.ksh \
 | ||||||
| 	zpool_create_features_004_neg.ksh \
 | 	zpool_create_features_004_neg.ksh \
 | ||||||
| 	zpool_create_features_005_pos.ksh \
 | 	zpool_create_features_005_pos.ksh \
 | ||||||
|  | 	zpool_create_features_006_pos.ksh \
 | ||||||
|  | 	zpool_create_features_007_pos.ksh \
 | ||||||
|  | 	zpool_create_features_008_pos.ksh \
 | ||||||
| 	create-o_ashift.ksh \
 | 	create-o_ashift.ksh \
 | ||||||
| 	zpool_create_tempname.ksh \
 | 	zpool_create_tempname.ksh \
 | ||||||
| 	zpool_create_dryrun_output.ksh | 	zpool_create_dryrun_output.ksh | ||||||
|  | |||||||
| @ -107,3 +107,84 @@ function save_dump_dev | |||||||
| 	fi | 	fi | ||||||
| 	echo $dumpdev | 	echo $dumpdev | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Verify a pools enabled features match the provided feature set. | ||||||
|  | # $1, pool name | ||||||
|  | # $2, feature set(s) | ||||||
|  | # | ||||||
|  | # check_feature_set $TESTPOOL set1 set2 set3 ... | ||||||
|  | # | ||||||
|  | function check_feature_set | ||||||
|  | { | ||||||
|  | 	typeset pool=$1 | ||||||
|  | 	typeset feature_set=$2 | ||||||
|  | 	shift | ||||||
|  | 
 | ||||||
|  | 	for set in "$@"; do | ||||||
|  | 		if test -e "$ZPOOL_COMPAT_DIR/$set"; then | ||||||
|  | 			file="$ZPOOL_COMPAT_DIR/$set" | ||||||
|  | 		else | ||||||
|  | 			log_fail "Missing feature file: $ZPOOL_COMPAT_DIR/$set" | ||||||
|  | 		fi | ||||||
|  | 	done | ||||||
|  | 
 | ||||||
|  | 	# | ||||||
|  | 	# Create a temporary file which contains all features which are | ||||||
|  | 	# common to the listed feature sets.  This is used for comparison | ||||||
|  | 	# below to determine which features should be enabled. | ||||||
|  | 	# | ||||||
|  | 	typeset tmpfile=$(mktemp) | ||||||
|  | 
 | ||||||
|  | 	while read line; do | ||||||
|  | 		typeset flag=1 | ||||||
|  | 
 | ||||||
|  | 		if [[ "$line" == "#*" ]]; then | ||||||
|  | 			continue | ||||||
|  | 		fi | ||||||
|  | 
 | ||||||
|  | 		for set in "$@"; do | ||||||
|  | 			if ! grep -q "$line" $ZPOOL_COMPAT_DIR/$set; then | ||||||
|  | 				flag=0 | ||||||
|  | 				break; | ||||||
|  | 			fi | ||||||
|  | 		done | ||||||
|  | 
 | ||||||
|  | 		if [[ $flag -eq 1 ]]; then | ||||||
|  | 			echo "$line" >>$tmpfile | ||||||
|  | 		fi | ||||||
|  | 	done <"$file" | ||||||
|  | 
 | ||||||
|  | 	# | ||||||
|  | 	# Verify every enabled feature appears in the merged feature set. | ||||||
|  | 	# Verify every disabled feature does not. | ||||||
|  | 	# | ||||||
|  | 	for feature in $(zpool get all $pool | \ | ||||||
|  | 	    awk '$2 ~ /feature@/ { print $2 }'); do | ||||||
|  | 		state=$(get_pool_prop $feature $pool) | ||||||
|  | 		name=$(cut -d'@' -f2 <<<"$feature") | ||||||
|  | 
 | ||||||
|  | 		if [[ "$state" = "enabled" || "$state" = "active" ]]; then | ||||||
|  | 			if ! grep -q $name $tmpfile; then | ||||||
|  | 				cat $tmpfile | ||||||
|  | 				rm -f $tmpfile | ||||||
|  | 				log_fail "Enabled feature $name not " \ | ||||||
|  | 				    "in feature set file" | ||||||
|  | 			fi | ||||||
|  | 		elif [[ "$state" = "disabled" ]]; then | ||||||
|  | 			if grep -q $name $tmpfile; then | ||||||
|  | 				cat $tmpfile | ||||||
|  | 				rm -f $tmpfile | ||||||
|  | 				log_fail "Disabled feature $name is " \ | ||||||
|  | 				    "in feature set file" | ||||||
|  | 			fi | ||||||
|  | 		else | ||||||
|  | 			rm -f $tmpfile | ||||||
|  | 			log_fail "Feature $name in unknown state $state" | ||||||
|  | 		fi | ||||||
|  | 	done | ||||||
|  | 
 | ||||||
|  | 	log_note "Checked all features" | ||||||
|  | 
 | ||||||
|  | 	rm -f $tmpfile | ||||||
|  | } | ||||||
|  | |||||||
| @ -0,0 +1,58 @@ | |||||||
|  | #!/bin/ksh -p | ||||||
|  | # | ||||||
|  | # CDDL HEADER START | ||||||
|  | # | ||||||
|  | # The contents of this file are subject to the terms of the | ||||||
|  | # Common Development and Distribution License (the "License"). | ||||||
|  | # You may not use this file except in compliance with the License. | ||||||
|  | # | ||||||
|  | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | ||||||
|  | # or http://www.opensolaris.org/os/licensing. | ||||||
|  | # See the License for the specific language governing permissions | ||||||
|  | # and limitations under the License. | ||||||
|  | # | ||||||
|  | # When distributing Covered Code, include this CDDL HEADER in each | ||||||
|  | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | ||||||
|  | # If applicable, add the following below this CDDL HEADER, with the | ||||||
|  | # fields enclosed by brackets "[]" replaced with your own identifying | ||||||
|  | # information: Portions Copyright [yyyy] [name of copyright owner] | ||||||
|  | # | ||||||
|  | # CDDL HEADER END | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Copyright (c) 2021 Lawrence Livermore National Security, LLC. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | . $STF_SUITE/include/libtest.shlib | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # DESCRIPTION: | ||||||
|  | #	Verify '-o compatibility' reserved values 'off, legacy' | ||||||
|  | # | ||||||
|  | # STRATEGY: | ||||||
|  | #	1. Create a pool with '-o compatibility=off' | ||||||
|  | #	2. Create a pool with '-o compatibility=legacy' | ||||||
|  | #	3. Cannot create a pool with '-o compatibility=unknown' | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | verify_runnable "global" | ||||||
|  | 
 | ||||||
|  | function cleanup | ||||||
|  | { | ||||||
|  | 	datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | log_onexit cleanup | ||||||
|  | 
 | ||||||
|  | log_assert "verify '-o compatibility' reserved values 'off, legacy'" | ||||||
|  | 
 | ||||||
|  | log_must zpool create -f -o compatibility=off $TESTPOOL $DISKS | ||||||
|  | log_must zpool destroy -f $TESTPOOL | ||||||
|  | 
 | ||||||
|  | log_must zpool create -f -o compatibility=legacy $TESTPOOL $DISKS | ||||||
|  | log_must zpool destroy -f $TESTPOOL | ||||||
|  | 
 | ||||||
|  | log_mustnot zpool create -f -o compatibility=unknown $TESTPOOL $DISKS | ||||||
|  | 
 | ||||||
|  | log_pass "verify '-o compatibility' reserved values 'off, legacy'" | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | #!/bin/ksh -p | ||||||
|  | # | ||||||
|  | # CDDL HEADER START | ||||||
|  | # | ||||||
|  | # The contents of this file are subject to the terms of the | ||||||
|  | # Common Development and Distribution License (the "License"). | ||||||
|  | # You may not use this file except in compliance with the License. | ||||||
|  | # | ||||||
|  | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | ||||||
|  | # or http://www.opensolaris.org/os/licensing. | ||||||
|  | # See the License for the specific language governing permissions | ||||||
|  | # and limitations under the License. | ||||||
|  | # | ||||||
|  | # When distributing Covered Code, include this CDDL HEADER in each | ||||||
|  | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | ||||||
|  | # If applicable, add the following below this CDDL HEADER, with the | ||||||
|  | # fields enclosed by brackets "[]" replaced with your own identifying | ||||||
|  | # information: Portions Copyright [yyyy] [name of copyright owner] | ||||||
|  | # | ||||||
|  | # CDDL HEADER END | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Copyright (c) 2021 Lawrence Livermore National Security, LLC. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | . $STF_SUITE/include/libtest.shlib | ||||||
|  | . $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # DESCRIPTION: | ||||||
|  | #	Verify pools can be created with the expected feature set enabled. | ||||||
|  | # | ||||||
|  | # STRATEGY: | ||||||
|  | #	1. Create a pool with a known feature set. | ||||||
|  | #	2. Verify only those features are active/enabled. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | verify_runnable "global" | ||||||
|  | 
 | ||||||
|  | function cleanup | ||||||
|  | { | ||||||
|  | 	datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | log_onexit cleanup | ||||||
|  | 
 | ||||||
|  | log_assert "creates a pool with a specified feature set enabled" | ||||||
|  | 
 | ||||||
|  | log_must zpool create -f -o compatibility=compat-2020 $TESTPOOL $DISKS | ||||||
|  | check_feature_set $TESTPOOL compat-2020 | ||||||
|  | log_must zpool destroy -f $TESTPOOL | ||||||
|  | 
 | ||||||
|  | log_pass "creates a pool with a specified feature set enabled" | ||||||
| @ -0,0 +1,54 @@ | |||||||
|  | #!/bin/ksh -p | ||||||
|  | # | ||||||
|  | # CDDL HEADER START | ||||||
|  | # | ||||||
|  | # The contents of this file are subject to the terms of the | ||||||
|  | # Common Development and Distribution License (the "License"). | ||||||
|  | # You may not use this file except in compliance with the License. | ||||||
|  | # | ||||||
|  | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | ||||||
|  | # or http://www.opensolaris.org/os/licensing. | ||||||
|  | # See the License for the specific language governing permissions | ||||||
|  | # and limitations under the License. | ||||||
|  | # | ||||||
|  | # When distributing Covered Code, include this CDDL HEADER in each | ||||||
|  | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | ||||||
|  | # If applicable, add the following below this CDDL HEADER, with the | ||||||
|  | # fields enclosed by brackets "[]" replaced with your own identifying | ||||||
|  | # information: Portions Copyright [yyyy] [name of copyright owner] | ||||||
|  | # | ||||||
|  | # CDDL HEADER END | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Copyright (c) 2021 Lawrence Livermore National Security, LLC. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | . $STF_SUITE/include/libtest.shlib | ||||||
|  | . $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # DESCRIPTION: | ||||||
|  | #	Verify pools can be created with multiple feature sets. | ||||||
|  | # | ||||||
|  | # STRATEGY: | ||||||
|  | #	1. Create a pool with multiple feature sets. | ||||||
|  | #	2. Verify only the features common to both sets are enabled. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | verify_runnable "global" | ||||||
|  | 
 | ||||||
|  | function cleanup | ||||||
|  | { | ||||||
|  | 	datasetexists $TESTPOOL && log_must zpool destroy $TESTPOOL | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | log_onexit cleanup | ||||||
|  | 
 | ||||||
|  | log_assert "creates a pool with multiple feature sets enabled" | ||||||
|  | 
 | ||||||
|  | log_must zpool create -f -o compatibility=freebsd-11.0,zol-0.8 $TESTPOOL $DISKS | ||||||
|  | check_feature_set $TESTPOOL freebsd-11.0 zol-0.8 | ||||||
|  | log_must zpool destroy -f $TESTPOOL | ||||||
|  | 
 | ||||||
|  | log_pass "creates a pool with multiple feature sets enabled" | ||||||
| @ -57,6 +57,7 @@ typeset -a properties=( | |||||||
|     "leaked" |     "leaked" | ||||||
|     "multihost" |     "multihost" | ||||||
|     "autotrim" |     "autotrim" | ||||||
|  |     "compatibility" | ||||||
|     "feature@async_destroy" |     "feature@async_destroy" | ||||||
|     "feature@empty_bpobj" |     "feature@empty_bpobj" | ||||||
|     "feature@lz4_compress" |     "feature@lz4_compress" | ||||||
|  | |||||||
| @ -3,4 +3,5 @@ dist_pkgdata_SCRIPTS = \ | |||||||
| 	setup.ksh \
 | 	setup.ksh \
 | ||||||
| 	cleanup.ksh \
 | 	cleanup.ksh \
 | ||||||
| 	zpool_status_001_pos.ksh \
 | 	zpool_status_001_pos.ksh \
 | ||||||
| 	zpool_status_002_pos.ksh | 	zpool_status_002_pos.ksh \
 | ||||||
|  | 	zpool_status_features_001_pos.ksh | ||||||
|  | |||||||
| @ -0,0 +1,63 @@ | |||||||
|  | #!/bin/ksh -p | ||||||
|  | # | ||||||
|  | # CDDL HEADER START | ||||||
|  | # | ||||||
|  | # The contents of this file are subject to the terms of the | ||||||
|  | # Common Development and Distribution License (the "License"). | ||||||
|  | # You may not use this file except in compliance with the License. | ||||||
|  | # | ||||||
|  | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | ||||||
|  | # or http://www.opensolaris.org/os/licensing. | ||||||
|  | # See the License for the specific language governing permissions | ||||||
|  | # and limitations under the License. | ||||||
|  | # | ||||||
|  | # When distributing Covered Code, include this CDDL HEADER in each | ||||||
|  | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | ||||||
|  | # If applicable, add the following below this CDDL HEADER, with the | ||||||
|  | # fields enclosed by brackets "[]" replaced with your own identifying | ||||||
|  | # information: Portions Copyright [yyyy] [name of copyright owner] | ||||||
|  | # | ||||||
|  | # CDDL HEADER END | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Copyright (c) 2021 Lawrence Livermore National Security, LLC. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | . $STF_SUITE/include/libtest.shlib | ||||||
|  | . $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # DESCRIPTION: | ||||||
|  | #	Verify zpool status only recommends upgrading the pool when | ||||||
|  | #	the enabled features don't match those in the feature set. | ||||||
|  | # | ||||||
|  | # STRATEGY: | ||||||
|  | #	1. Create a pool with a known feature set. | ||||||
|  | #	2. Verify there is no `zpool status` notice to upgrade the pool. | ||||||
|  | #	3. Set the pool compatibility to a newer feature set. | ||||||
|  | #	4. Verify there is a `zpool status` notice to upgrade the pool. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | verify_runnable "global" | ||||||
|  | 
 | ||||||
|  | function cleanup | ||||||
|  | { | ||||||
|  | 	datasetexists $TESTPOOL1 && log_must zpool destroy $TESTPOOL1 | ||||||
|  | 	rm -f $FILEDEV | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FILEDEV="$TEST_BASE_DIR/filedev.$$" | ||||||
|  | 
 | ||||||
|  | log_onexit cleanup | ||||||
|  | 
 | ||||||
|  | log_assert "check 'zpool status' upgrade notice" | ||||||
|  | 
 | ||||||
|  | log_must truncate -s $MINVDEVSIZE $FILEDEV | ||||||
|  | log_must zpool create -f -o compatibility=compat-2018 $TESTPOOL1 $FILEDEV | ||||||
|  | log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" | ||||||
|  | 
 | ||||||
|  | log_must zpool set compatibility=compat-2020 $TESTPOOL1 | ||||||
|  | log_must check_pool_status $TESTPOOL1 "status" "features are not enabled" | ||||||
|  | 
 | ||||||
|  | log_pass "check 'zpool status' upgrade notice" | ||||||
| @ -12,7 +12,8 @@ dist_pkgdata_SCRIPTS = \ | |||||||
| 	zpool_upgrade_006_neg.ksh \
 | 	zpool_upgrade_006_neg.ksh \
 | ||||||
| 	zpool_upgrade_007_pos.ksh \
 | 	zpool_upgrade_007_pos.ksh \
 | ||||||
| 	zpool_upgrade_008_pos.ksh \
 | 	zpool_upgrade_008_pos.ksh \
 | ||||||
| 	zpool_upgrade_009_neg.ksh | 	zpool_upgrade_009_neg.ksh \
 | ||||||
|  | 	zpool_upgrade_features_001_pos.ksh | ||||||
| 
 | 
 | ||||||
| dist_pkgdata_DATA = \
 | dist_pkgdata_DATA = \
 | ||||||
| 	zpool_upgrade.cfg \
 | 	zpool_upgrade.cfg \
 | ||||||
|  | |||||||
| @ -0,0 +1,67 @@ | |||||||
|  | #!/bin/ksh -p | ||||||
|  | # | ||||||
|  | # CDDL HEADER START | ||||||
|  | # | ||||||
|  | # The contents of this file are subject to the terms of the | ||||||
|  | # Common Development and Distribution License (the "License"). | ||||||
|  | # You may not use this file except in compliance with the License. | ||||||
|  | # | ||||||
|  | # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | ||||||
|  | # or http://www.opensolaris.org/os/licensing. | ||||||
|  | # See the License for the specific language governing permissions | ||||||
|  | # and limitations under the License. | ||||||
|  | # | ||||||
|  | # When distributing Covered Code, include this CDDL HEADER in each | ||||||
|  | # file and include the License file at usr/src/OPENSOLARIS.LICENSE. | ||||||
|  | # If applicable, add the following below this CDDL HEADER, with the | ||||||
|  | # fields enclosed by brackets "[]" replaced with your own identifying | ||||||
|  | # information: Portions Copyright [yyyy] [name of copyright owner] | ||||||
|  | # | ||||||
|  | # CDDL HEADER END | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # Copyright (c) 2021 Lawrence Livermore National Security, LLC. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | . $STF_SUITE/include/libtest.shlib | ||||||
|  | . $STF_SUITE/tests/functional/cli_root/zpool_create/zpool_create.shlib | ||||||
|  | 
 | ||||||
|  | # | ||||||
|  | # DESCRIPTION: | ||||||
|  | #	Verify pools can be upgraded to known feature sets. | ||||||
|  | # | ||||||
|  | # STRATEGY: | ||||||
|  | #	1. Create a pool with a known feature set. | ||||||
|  | #	2. Verify only those features are active/enabled. | ||||||
|  | #	3. Upgrade the pool to a newer feature set. | ||||||
|  | #	4. Verify only those features are active/enabled. | ||||||
|  | # | ||||||
|  | 
 | ||||||
|  | verify_runnable "global" | ||||||
|  | 
 | ||||||
|  | function cleanup | ||||||
|  | { | ||||||
|  | 	datasetexists $TESTPOOL1 && log_must zpool destroy $TESTPOOL1 | ||||||
|  | 	rm -f $FILEDEV | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | FILEDEV="$TEST_BASE_DIR/filedev.$$" | ||||||
|  | 
 | ||||||
|  | log_onexit cleanup | ||||||
|  | 
 | ||||||
|  | log_assert "verify pools can be upgraded to known feature sets." | ||||||
|  | 
 | ||||||
|  | log_must truncate -s $MINVDEVSIZE $FILEDEV | ||||||
|  | log_must zpool create -f -o compatibility=compat-2018 $TESTPOOL1 $FILEDEV | ||||||
|  | check_feature_set $TESTPOOL1 compat-2018 | ||||||
|  | log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" | ||||||
|  | 
 | ||||||
|  | log_must zpool set compatibility=compat-2020 $TESTPOOL1 | ||||||
|  | log_must check_pool_status $TESTPOOL1 "status" "features are not enabled" | ||||||
|  | 
 | ||||||
|  | log_must zpool upgrade $TESTPOOL1 | ||||||
|  | check_feature_set $TESTPOOL1 compat-2020 | ||||||
|  | log_mustnot check_pool_status $TESTPOOL1 "status" "features are not enabled" | ||||||
|  | 
 | ||||||
|  | log_pass "verify pools can be upgraded to known feature sets." | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 Colm
						Colm