From owner-svn-src-all@freebsd.org Wed Jul 26 14:55:49 2017 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 2C78FDBFCF7; Wed, 26 Jul 2017 14:55:49 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 078DC656B1; Wed, 26 Jul 2017 14:55:48 +0000 (UTC) (envelope-from mav@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id v6QEtmgW030580; Wed, 26 Jul 2017 14:55:48 GMT (envelope-from mav@FreeBSD.org) Received: (from mav@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id v6QEtlq6030576; Wed, 26 Jul 2017 14:55:47 GMT (envelope-from mav@FreeBSD.org) Message-Id: <201707261455.v6QEtlq6030576@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: mav set sender to mav@FreeBSD.org using -f From: Alexander Motin Date: Wed, 26 Jul 2017 14:55:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-11@freebsd.org Subject: svn commit: r321519 - in stable/11/sys: boot/zfs cddl/boot/zfs X-SVN-Group: stable-11 X-SVN-Commit-Author: mav X-SVN-Commit-Paths: in stable/11/sys: boot/zfs cddl/boot/zfs X-SVN-Commit-Revision: 321519 X-SVN-Commit-Repository: base MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 26 Jul 2017 14:55:49 -0000 Author: mav Date: Wed Jul 26 14:55:47 2017 New Revision: 321519 URL: https://svnweb.freebsd.org/changeset/base/321519 Log: MFC r303630 (by allanjude): Make boot code and loader check for unsupported ZFS feature flags OpenZFS uses feature flags instead of a zpool version number to track features since the split from Oracle. In addition to avoiding confusion on ZFS vs OpenZFS version numbers, this also allows features to be added to different operating systems that use OpenZFS in different order. The previous zfs boot code (gptzfsboot) and loader (zfsloader) blindly tries to read the pool, and if failed provided only a vague error message. With this change, both the boot code and loader check the MOS features list in the ZFS label and compare it against the list of features that the loader supports. If any unsupported feature is active, the pool is not considered as a candidate for booting, and a helpful diagnostic message is printed to the screen. Features that are merely enabled via zpool upgrade, but not in use, do not block booting from the pool. Submitted by: Toomas Soome Reviewed by: delphij, mav Relnotes: yes Differential Revision: https://reviews.freebsd.org/D6857 Modified: stable/11/sys/boot/zfs/libzfs.h stable/11/sys/boot/zfs/zfs.c stable/11/sys/boot/zfs/zfsimpl.c stable/11/sys/cddl/boot/zfs/zfsimpl.h Directory Properties: stable/11/ (props changed) Modified: stable/11/sys/boot/zfs/libzfs.h ============================================================================== --- stable/11/sys/boot/zfs/libzfs.h Wed Jul 26 12:07:46 2017 (r321518) +++ stable/11/sys/boot/zfs/libzfs.h Wed Jul 26 14:55:47 2017 (r321519) @@ -65,7 +65,7 @@ int zfs_probe_dev(const char *devname, uint64_t *pool_ int zfs_list(const char *name); void init_zfs_bootenv(char *currdev); int zfs_bootenv(const char *name); -int zfs_belist_add(const char *name); +int zfs_belist_add(const char *name, uint64_t __unused); int zfs_set_env(void); extern struct devsw zfs_dev; Modified: stable/11/sys/boot/zfs/zfs.c ============================================================================== --- stable/11/sys/boot/zfs/zfs.c Wed Jul 26 12:07:46 2017 (r321518) +++ stable/11/sys/boot/zfs/zfs.c Wed Jul 26 14:55:47 2017 (r321519) @@ -801,7 +801,7 @@ zfs_bootenv(const char *name) } int -zfs_belist_add(const char *name) +zfs_belist_add(const char *name, uint64_t value __unused) { /* Skip special datasets that start with a $ character */ Modified: stable/11/sys/boot/zfs/zfsimpl.c ============================================================================== --- stable/11/sys/boot/zfs/zfsimpl.c Wed Jul 26 12:07:46 2017 (r321518) +++ stable/11/sys/boot/zfs/zfsimpl.c Wed Jul 26 14:55:47 2017 (r321519) @@ -1472,12 +1472,12 @@ zap_lookup(const spa_t *spa, const dnode_phys_t *dnode * the directory contents. */ static int -mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *)) +mzap_list(const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) { const mzap_phys_t *mz; const mzap_ent_phys_t *mze; size_t size; - int chunks, i; + int chunks, i, rc; /* * Microzap objects use exactly one block. Read the whole @@ -1489,9 +1489,11 @@ mzap_list(const dnode_phys_t *dnode, int (*callback)(c for (i = 0; i < chunks; i++) { mze = &mz->mz_chunk[i]; - if (mze->mze_name[0]) - //printf("%-32s 0x%jx\n", mze->mze_name, (uintmax_t)mze->mze_value); - callback(mze->mze_name); + if (mze->mze_name[0]) { + rc = callback(mze->mze_name, mze->mze_value); + if (rc != 0) + return (rc); + } } return (0); @@ -1502,12 +1504,12 @@ mzap_list(const dnode_phys_t *dnode, int (*callback)(c * the directory header. */ static int -fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *)) +fzap_list(const spa_t *spa, const dnode_phys_t *dnode, int (*callback)(const char *, uint64_t)) { int bsize = dnode->dn_datablkszsec << SPA_MINBLOCKSHIFT; zap_phys_t zh = *(zap_phys_t *) zap_scratch; fat_zap_t z; - int i, j; + int i, j, rc; if (zh.zap_magic != ZAP_MAGIC) return (EIO); @@ -1565,14 +1567,16 @@ fzap_list(const spa_t *spa, const dnode_phys_t *dnode, value = fzap_leaf_value(&zl, zc); //printf("%s 0x%jx\n", name, (uintmax_t)value); - callback((const char *)name); + rc = callback((const char *)name, value); + if (rc != 0) + return (rc); } } return (0); } -static int zfs_printf(const char *name) +static int zfs_printf(const char *name, uint64_t value __unused) { printf("%s\n", name); @@ -1867,7 +1871,7 @@ zfs_list_dataset(const spa_t *spa, uint64_t objnum/*, } int -zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *name)) +zfs_callback_dataset(const spa_t *spa, uint64_t objnum, int (*callback)(const char *, uint64_t)) { uint64_t dir_obj, child_dir_zapobj, zap_type; dnode_phys_t child_dir_zap, dir, dataset; @@ -2007,9 +2011,67 @@ zfs_mount(const spa_t *spa, uint64_t rootobj, struct z return (0); } +/* + * callback function for feature name checks. + */ static int +check_feature(const char *name, uint64_t value) +{ + int i; + + if (value == 0) + return (0); + if (name[0] == '\0') + return (0); + + for (i = 0; features_for_read[i] != NULL; i++) { + if (strcmp(name, features_for_read[i]) == 0) + return (0); + } + printf("ZFS: unsupported feature: %s\n", name); + return (EIO); +} + +/* + * Checks whether the MOS features that are active are supported. + */ +static int +check_mos_features(const spa_t *spa) +{ + dnode_phys_t dir; + uint64_t objnum, zap_type; + size_t size; + int rc; + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, DMU_OT_OBJECT_DIRECTORY, + &dir)) != 0) + return (rc); + if ((rc = zap_lookup(spa, &dir, DMU_POOL_FEATURES_FOR_READ, &objnum)) != 0) + return (rc); + + if ((rc = objset_get_dnode(spa, &spa->spa_mos, objnum, &dir)) != 0) + return (rc); + + if (dir.dn_type != DMU_OTN_ZAP_METADATA) + return (EIO); + + size = dir.dn_datablkszsec * 512; + if (dnode_read(spa, &dir, 0, zap_scratch, size)) + return (EIO); + + zap_type = *(uint64_t *) zap_scratch; + if (zap_type == ZBT_MICRO) + rc = mzap_list(&dir, check_feature); + else + rc = fzap_list(spa, &dir, check_feature); + + return (rc); +} + +static int zfs_spa_init(spa_t *spa) { + int rc; if (zio_read(spa, &spa->spa_uberblock.ub_rootbp, &spa->spa_mos)) { printf("ZFS: can't read MOS of pool %s\n", spa->spa_name); @@ -2019,7 +2081,13 @@ zfs_spa_init(spa_t *spa) printf("ZFS: corrupted MOS of pool %s\n", spa->spa_name); return (EIO); } - return (0); + + rc = check_mos_features(spa); + if (rc != 0) { + printf("ZFS: pool %s is not supported\n", spa->spa_name); + } + + return (rc); } static int Modified: stable/11/sys/cddl/boot/zfs/zfsimpl.h ============================================================================== --- stable/11/sys/cddl/boot/zfs/zfsimpl.h Wed Jul 26 12:07:46 2017 (r321518) +++ stable/11/sys/cddl/boot/zfs/zfsimpl.h Wed Jul 26 14:55:47 2017 (r321519) @@ -63,6 +63,8 @@ #define _NOTE(s) +typedef enum { B_FALSE, B_TRUE } boolean_t; + /* CRC64 table */ #define ZFS_CRC64_POLY 0xC96C5795D7870F42ULL /* ECMA-182, reflected form */ @@ -899,6 +901,41 @@ typedef struct dnode_phys { blkptr_t dn_spill; } dnode_phys_t; +typedef enum dmu_object_byteswap { + DMU_BSWAP_UINT8, + DMU_BSWAP_UINT16, + DMU_BSWAP_UINT32, + DMU_BSWAP_UINT64, + DMU_BSWAP_ZAP, + DMU_BSWAP_DNODE, + DMU_BSWAP_OBJSET, + DMU_BSWAP_ZNODE, + DMU_BSWAP_OLDACL, + DMU_BSWAP_ACL, + /* + * Allocating a new byteswap type number makes the on-disk format + * incompatible with any other format that uses the same number. + * + * Data can usually be structured to work with one of the + * DMU_BSWAP_UINT* or DMU_BSWAP_ZAP types. + */ + DMU_BSWAP_NUMFUNCS +} dmu_object_byteswap_t; + +#define DMU_OT_NEWTYPE 0x80 +#define DMU_OT_METADATA 0x40 +#define DMU_OT_BYTESWAP_MASK 0x3f + +/* + * Defines a uint8_t object type. Object types specify if the data + * in the object is metadata (boolean) and how to byteswap the data + * (dmu_object_byteswap_t). + */ +#define DMU_OT(byteswap, metadata) \ + (DMU_OT_NEWTYPE | \ + ((metadata) ? DMU_OT_METADATA : 0) | \ + ((byteswap) & DMU_OT_BYTESWAP_MASK)) + typedef enum dmu_object_type { DMU_OT_NONE, /* general: */ @@ -959,7 +996,21 @@ typedef enum dmu_object_type { DMU_OT_SA_ATTR_LAYOUTS, /* ZAP */ DMU_OT_SCAN_XLATE, /* ZAP */ DMU_OT_DEDUP, /* fake dedup BP from ddt_bp_create() */ - DMU_OT_NUMTYPES + DMU_OT_NUMTYPES, + + /* + * Names for valid types declared with DMU_OT(). + */ + DMU_OTN_UINT8_DATA = DMU_OT(DMU_BSWAP_UINT8, B_FALSE), + DMU_OTN_UINT8_METADATA = DMU_OT(DMU_BSWAP_UINT8, B_TRUE), + DMU_OTN_UINT16_DATA = DMU_OT(DMU_BSWAP_UINT16, B_FALSE), + DMU_OTN_UINT16_METADATA = DMU_OT(DMU_BSWAP_UINT16, B_TRUE), + DMU_OTN_UINT32_DATA = DMU_OT(DMU_BSWAP_UINT32, B_FALSE), + DMU_OTN_UINT32_METADATA = DMU_OT(DMU_BSWAP_UINT32, B_TRUE), + DMU_OTN_UINT64_DATA = DMU_OT(DMU_BSWAP_UINT64, B_FALSE), + DMU_OTN_UINT64_METADATA = DMU_OT(DMU_BSWAP_UINT64, B_TRUE), + DMU_OTN_ZAP_DATA = DMU_OT(DMU_BSWAP_ZAP, B_FALSE), + DMU_OTN_ZAP_METADATA = DMU_OT(DMU_BSWAP_ZAP, B_TRUE) } dmu_object_type_t; typedef enum dmu_objset_type { @@ -1097,6 +1148,7 @@ typedef struct dsl_dataset_phys { */ #define DMU_POOL_DIRECTORY_OBJECT 1 #define DMU_POOL_CONFIG "config" +#define DMU_POOL_FEATURES_FOR_READ "features_for_read" #define DMU_POOL_ROOT_DATASET "root_dataset" #define DMU_POOL_SYNC_BPLIST "sync_bplist" #define DMU_POOL_ERRLOG_SCRUB "errlog_scrub"