Index: sys/boot/zfs/zfsimpl.c =================================================================== --- sys/boot/zfs/zfsimpl.c (revision 236715) +++ sys/boot/zfs/zfsimpl.c (working copy) @@ -49,6 +49,13 @@ struct zfsmount { */ static vdev_list_t zfs_vdevs; + /* + * List of ZFS features supported for read + */ +static const char *features_for_read[] = { + NULL +}; + /* * List of all pools, chained through spa_link. */ @@ -198,6 +205,57 @@ nvlist_find(const unsigned char *nvlist, const cha return (EIO); } +static int +nvlist_check_features_for_read(const unsigned char *nvlist) +{ + const unsigned char *p, *pair; + int junk; + int encoded_size, decoded_size; + int rc; + + rc = 0; + + p = nvlist; + xdr_int(&p, &junk); + xdr_int(&p, &junk); + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + while (encoded_size && decoded_size) { + int namelen, pairtype; + const char *pairname; + int i, found; + + found = 0; + + xdr_int(&p, &namelen); + pairname = (const char*) p; + p += roundup(namelen, 4); + xdr_int(&p, &pairtype); + + for (i = 0; features_for_read[i] != NULL; i++) { + if (!memcmp(pairname, features_for_read[i], namelen)) { + found = 1; + break; + } + } + + if (!found) { + printf("ZFS: unsupported feature: %s\n", pairname); + rc = EIO; + } + + p = pair + encoded_size; + + pair = p; + xdr_int(&p, &encoded_size); + xdr_int(&p, &decoded_size); + } + + return (rc); +} + /* * Return the next nvlist in an nvlist array. */ @@ -788,6 +846,7 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv uint64_t is_log; const char *pool_name; const unsigned char *vdevs; + const unsigned char *features; int i, rc, is_newer; char *upbuf; const struct uberblock *up; @@ -822,12 +881,18 @@ vdev_probe(vdev_phys_read_t *read, void *read_priv return (EIO); } - if (val > SPA_VERSION) { + if (!SPA_VERSION_IS_SUPPORTED(val)) { printf("ZFS: unsupported ZFS version %u (should be %u)\n", (unsigned) val, (unsigned) SPA_VERSION); return (EIO); } + /* Check ZFS features for read */ + rc = nvlist_find(nvlist, ZPOOL_CONFIG_FEATURES_FOR_READ, + DATA_TYPE_NVLIST, 0, &features); + if (nvlist_check_features_for_read(features) != 0) + return (EIO); + if (nvlist_find(nvlist, ZPOOL_CONFIG_POOL_STATE, DATA_TYPE_UINT64, 0, &val)) { Index: sys/cddl/boot/zfs/zfsimpl.h =================================================================== --- sys/cddl/boot/zfs/zfsimpl.h (revision 236715) +++ sys/cddl/boot/zfs/zfsimpl.h (working copy) @@ -53,6 +53,8 @@ * Use is subject to license terms. */ +#define MAXNAMELEN 256 + /* CRC64 table */ #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */ @@ -508,6 +510,7 @@ typedef enum { #define SPA_VERSION_26 26ULL #define SPA_VERSION_27 27ULL #define SPA_VERSION_28 28ULL +#define SPA_VERSION_5000 5000ULL /* * When bumping up SPA_VERSION, make sure GRUB ZFS understands the on-disk @@ -515,8 +518,8 @@ typedef enum { * and do the appropriate changes. Also bump the version number in * usr/src/grub/capability. */ -#define SPA_VERSION SPA_VERSION_28 -#define SPA_VERSION_STRING "28" +#define SPA_VERSION SPA_VERSION_5000 +#define SPA_VERSION_STRING "5000" /* * Symbolic names for the changes that caused a SPA_VERSION switch. @@ -567,7 +570,13 @@ typedef enum { #define SPA_VERSION_DEADLISTS SPA_VERSION_26 #define SPA_VERSION_FAST_SNAP SPA_VERSION_27 #define SPA_VERSION_MULTI_REPLACE SPA_VERSION_28 +#define SPA_VERSION_BEFORE_FEATURES SPA_VERSION_28 +#define SPA_VERSION_FEATURES SPA_VERSION_5000 +#define SPA_VERSION_IS_SUPPORTED(v) \ + (((v) >= SPA_VERSION_INITIAL && (v) <= SPA_VERSION_BEFORE_FEATURES) || \ + ((v) >= SPA_VERSION_FEATURES && (v) <= SPA_VERSION)) + /* * The following are configuration names used in the nvlist describing a pool's * configuration. @@ -602,6 +611,7 @@ typedef enum { #define ZPOOL_CONFIG_HOSTNAME "hostname" #define ZPOOL_CONFIG_IS_LOG "is_log" #define ZPOOL_CONFIG_TIMESTAMP "timestamp" /* not stored on disk */ +#define ZPOOL_CONFIG_FEATURES_FOR_READ "features_for_read" /* * The persistent vdev state is stored as separate values rather than a single