diff options
-rw-r--r-- | usr/src/grub/grub-0.95/stage2/fsys_zfs.c | 7 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs.h | 1 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_dataset.c | 11 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_pool.c | 99 | ||||
-rw-r--r-- | usr/src/lib/libzfs/common/libzfs_util.c | 3 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/spa.c | 25 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/spa_impl.h | 6 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/sys/vdev.h | 1 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/vdev.c | 32 | ||||
-rw-r--r-- | usr/src/uts/common/fs/zfs/zfs_ioctl.c | 43 |
10 files changed, 192 insertions, 36 deletions
diff --git a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c index 3d05d1456d..9d1ced14ef 100644 --- a/usr/src/grub/grub-0.95/stage2/fsys_zfs.c +++ b/usr/src/grub/grub-0.95/stage2/fsys_zfs.c @@ -64,10 +64,11 @@ static char *stackbase; decomp_entry_t decomp_table[ZIO_COMPRESS_FUNCTIONS] = { - {"noop", 0}, + {"inherit", 0}, /* ZIO_COMPRESS_INHERIT */ {"on", lzjb_decompress}, /* ZIO_COMPRESS_ON */ - {"off", 0}, - {"lzjb", lzjb_decompress} /* ZIO_COMPRESS_LZJB */ + {"off", 0}, /* ZIO_COMPRESS_OFF */ + {"lzjb", lzjb_decompress}, /* ZIO_COMPRESS_LZJB */ + {"empty", 0} /* ZIO_COMPRESS_EMPTY */ }; /* diff --git a/usr/src/lib/libzfs/common/libzfs.h b/usr/src/lib/libzfs/common/libzfs.h index 1df8d67870..a89f558cdb 100644 --- a/usr/src/lib/libzfs/common/libzfs.h +++ b/usr/src/lib/libzfs/common/libzfs.h @@ -115,6 +115,7 @@ enum { EZFS_BADCACHE, /* bad cache file */ EZFS_ISL2CACHE, /* device is for the level 2 ARC */ EZFS_VDEVNOTSUP, /* unsupported vdev type */ + EZFS_NOTSUP, /* ops not supported on this dataset */ EZFS_UNKNOWN }; diff --git a/usr/src/lib/libzfs/common/libzfs_dataset.c b/usr/src/lib/libzfs/common/libzfs_dataset.c index c5dea6f583..9841729056 100644 --- a/usr/src/lib/libzfs/common/libzfs_dataset.c +++ b/usr/src/lib/libzfs/common/libzfs_dataset.c @@ -1868,6 +1868,17 @@ zfs_prop_set(zfs_handle_t *zhp, const char *propname, const char *propval) (void) zfs_error(hdl, EZFS_BADVERSION, errbuf); break; + case ERANGE: + if (prop == ZFS_PROP_COMPRESSION) { + (void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "property setting is not allowed on " + "bootable datasets")); + (void) zfs_error(hdl, EZFS_NOTSUP, errbuf); + } else { + (void) zfs_standard_error(hdl, errno, errbuf); + } + break; + case EOVERFLOW: /* * This platform can't address a volume this big. diff --git a/usr/src/lib/libzfs/common/libzfs_pool.c b/usr/src/lib/libzfs/common/libzfs_pool.c index 00df5ca616..ec2102a05b 100644 --- a/usr/src/lib/libzfs/common/libzfs_pool.c +++ b/usr/src/lib/libzfs/common/libzfs_pool.c @@ -48,6 +48,7 @@ #include "zfs_prop.h" #include "libzfs_impl.h" +static int read_efi_label(nvlist_t *config, diskaddr_t *sb); /* * ==================================================================== @@ -284,6 +285,27 @@ bootfs_name_valid(const char *pool, char *bootfs) } /* + * Inspect the configuration to determine if any of the devices contain + * an EFI label. + */ +static boolean_t +pool_uses_efi(nvlist_t *config) +{ + nvlist_t **child; + uint_t c, children; + + if (nvlist_lookup_nvlist_array(config, ZPOOL_CONFIG_CHILDREN, + &child, &children) != 0) + return (read_efi_label(config, NULL) >= 0); + + for (c = 0; c < children; c++) { + if (pool_uses_efi(child[c])) + return (B_TRUE); + } + return (B_FALSE); +} + +/* * Given an nvlist of zpool properties to be set, validate that they are * correct, and parse any numeric properties (index, boolean, etc) if they are * specified as strings. @@ -299,6 +321,8 @@ zpool_validate_properties(libzfs_handle_t *hdl, const char *poolname, uint64_t intval; char *slash; struct stat64 statbuf; + zpool_handle_t *zhp; + nvlist_t *nvroot; if (nvlist_alloc(&retprops, NV_UNIQUE_NAME, 0) != 0) { (void) no_memory(hdl); @@ -372,6 +396,29 @@ zpool_validate_properties(libzfs_handle_t *hdl, const char *poolname, (void) zfs_error(hdl, EZFS_INVALIDNAME, errbuf); goto error; } + + if ((zhp = zpool_open_canfail(hdl, poolname)) == NULL) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "could not open pool '%s'"), poolname); + (void) zfs_error(hdl, EZFS_OPENFAILED, errbuf); + goto error; + } + verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL), + ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); + + /* + * bootfs property cannot be set on a disk which has + * been EFI labeled. + */ + if (pool_uses_efi(nvroot)) { + zfs_error_aux(hdl, dgettext(TEXT_DOMAIN, + "property '%s' not supported on " + "EFI labeled devices"), propname); + (void) zfs_error(hdl, EZFS_POOL_NOTSUP, errbuf); + zpool_close(zhp); + goto error; + } + zpool_close(zhp); break; case ZPOOL_PROP_ALTROOT: @@ -2502,6 +2549,38 @@ zpool_obj_to_path(zpool_handle_t *zhp, uint64_t dsobj, uint64_t obj, #define NEW_START_BLOCK 256 /* + * Read the EFI label from the config, if a label does not exist then + * pass back the error to the caller. If the caller has passed a non-NULL + * diskaddr argument then we set it to the starting address of the EFI + * partition. + */ +static int +read_efi_label(nvlist_t *config, diskaddr_t *sb) +{ + char *path; + int fd; + char diskname[MAXPATHLEN]; + int err = -1; + + if (nvlist_lookup_string(config, ZPOOL_CONFIG_PATH, &path) != 0) + return (err); + + (void) snprintf(diskname, sizeof (diskname), "%s%s", RDISK_ROOT, + strrchr(path, '/')); + if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { + struct dk_gpt *vtoc; + + if ((err = efi_alloc_and_read(fd, &vtoc)) >= 0) { + if (sb != NULL) + *sb = vtoc->efi_parts[0].p_start; + efi_free(vtoc); + } + (void) close(fd); + } + return (err); +} + +/* * determine where a partition starts on a disk in the current * configuration */ @@ -2510,10 +2589,7 @@ find_start_block(nvlist_t *config) { nvlist_t **child; uint_t c, children; - char *path; diskaddr_t sb = MAXOFFSET_T; - int fd; - char diskname[MAXPATHLEN]; uint64_t wholedisk; if (nvlist_lookup_nvlist_array(config, @@ -2523,21 +2599,8 @@ find_start_block(nvlist_t *config) &wholedisk) != 0 || !wholedisk) { return (MAXOFFSET_T); } - if (nvlist_lookup_string(config, - ZPOOL_CONFIG_PATH, &path) != 0) { - return (MAXOFFSET_T); - } - - (void) snprintf(diskname, sizeof (diskname), "%s%s", - RDISK_ROOT, strrchr(path, '/')); - if ((fd = open(diskname, O_RDONLY|O_NDELAY)) >= 0) { - struct dk_gpt *vtoc; - if (efi_alloc_and_read(fd, &vtoc) >= 0) { - sb = vtoc->efi_parts[0].p_start; - efi_free(vtoc); - } - (void) close(fd); - } + if (read_efi_label(config, &sb) < 0) + sb = MAXOFFSET_T; return (sb); } diff --git a/usr/src/lib/libzfs/common/libzfs_util.c b/usr/src/lib/libzfs/common/libzfs_util.c index 7238eadfaf..e026b7f5d7 100644 --- a/usr/src/lib/libzfs/common/libzfs_util.c +++ b/usr/src/lib/libzfs/common/libzfs_util.c @@ -206,6 +206,9 @@ libzfs_error_description(libzfs_handle_t *hdl) case EZFS_VDEVNOTSUP: return (dgettext(TEXT_DOMAIN, "vdev specification is not " "supported")); + case EZFS_NOTSUP: + return (dgettext(TEXT_DOMAIN, "operation not supported " + "on this dataset")); case EZFS_UNKNOWN: return (dgettext(TEXT_DOMAIN, "unknown error")); default: diff --git a/usr/src/uts/common/fs/zfs/spa.c b/usr/src/uts/common/fs/zfs/spa.c index 242f66d1f2..1f220dde2b 100644 --- a/usr/src/uts/common/fs/zfs/spa.c +++ b/usr/src/uts/common/fs/zfs/spa.c @@ -271,8 +271,6 @@ spa_prop_validate(spa_t *spa, nvlist_t *props) zpool_prop_t prop; char *propname, *strval; uint64_t intval; - vdev_t *rvdev; - char *vdev_type; objset_t *os; char *slash; @@ -303,15 +301,9 @@ spa_prop_validate(spa_t *spa, nvlist_t *props) } /* - * A bootable filesystem can not be on a RAIDZ pool - * nor a striped pool with more than 1 device. + * Make sure the vdev config is bootable */ - rvdev = spa->spa_root_vdev; - vdev_type = - rvdev->vdev_child[0]->vdev_ops->vdev_op_type; - if (rvdev->vdev_children > 1 || - strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || - strcmp(vdev_type, VDEV_TYPE_MISSING) == 0) { + if (!vdev_is_bootable(spa->spa_root_vdev)) { error = ENOTSUP; break; } @@ -321,6 +313,8 @@ spa_prop_validate(spa_t *spa, nvlist_t *props) error = nvpair_value_string(elem, &strval); if (!error) { + uint64_t compress; + if (strval == NULL || strval[0] == '\0') { objnum = zpool_prop_default_numeric( ZPOOL_PROP_BOOTFS); @@ -330,7 +324,16 @@ spa_prop_validate(spa_t *spa, nvlist_t *props) if (error = dmu_objset_open(strval, DMU_OST_ZFS, DS_MODE_USER | DS_MODE_READONLY, &os)) break; - objnum = dmu_objset_id(os); + + /* We don't support gzip bootable datasets */ + if ((error = dsl_prop_get_integer(strval, + zfs_prop_to_name(ZFS_PROP_COMPRESSION), + &compress, NULL)) == 0 && + !BOOTFS_COMPRESS_VALID(compress)) { + error = ENOTSUP; + } else { + objnum = dmu_objset_id(os); + } dmu_objset_close(os); } break; diff --git a/usr/src/uts/common/fs/zfs/sys/spa_impl.h b/usr/src/uts/common/fs/zfs/sys/spa_impl.h index 4248f0b80f..dbe1540010 100644 --- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h +++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h @@ -176,6 +176,12 @@ struct spa { extern const char *spa_config_path; +#define BOOTFS_COMPRESS_VALID(compress) \ + ((compress) == ZIO_COMPRESS_LZJB || \ + ((compress) == ZIO_COMPRESS_ON && \ + ZIO_COMPRESS_ON_VALUE == ZIO_COMPRESS_LZJB) || \ + (compress) == ZIO_COMPRESS_OFF) + #ifdef __cplusplus } #endif diff --git a/usr/src/uts/common/fs/zfs/sys/vdev.h b/usr/src/uts/common/fs/zfs/sys/vdev.h index 5a685a68ec..8800c05a14 100644 --- a/usr/src/uts/common/fs/zfs/sys/vdev.h +++ b/usr/src/uts/common/fs/zfs/sys/vdev.h @@ -56,6 +56,7 @@ extern void vdev_reopen(vdev_t *); extern int vdev_validate_aux(vdev_t *vd); extern int vdev_probe(vdev_t *); +extern boolean_t vdev_is_bootable(vdev_t *vd); extern vdev_t *vdev_lookup_top(spa_t *spa, uint64_t vdev); extern vdev_t *vdev_lookup_by_guid(vdev_t *vd, uint64_t guid); extern void vdev_dtl_dirty(space_map_t *sm, uint64_t txg, uint64_t size); diff --git a/usr/src/uts/common/fs/zfs/vdev.c b/usr/src/uts/common/fs/zfs/vdev.c index f3b3ecd66e..e2abde9bd6 100644 --- a/usr/src/uts/common/fs/zfs/vdev.c +++ b/usr/src/uts/common/fs/zfs/vdev.c @@ -2264,3 +2264,35 @@ vdev_set_state(vdev_t *vd, boolean_t isopen, vdev_state_t state, vdev_aux_t aux) if (!isopen) vdev_propagate_state(vd); } + +/* + * Check the vdev configuration to ensure that it's capable of supporting + * a root pool. Currently, we do not support RAID-Z or partial configuration. + * In addition, only a single top-level vdev is allowed and none of the leaves + * can be wholedisks. + */ +boolean_t +vdev_is_bootable(vdev_t *vd) +{ + int c; + + if (!vd->vdev_ops->vdev_op_leaf) { + char *vdev_type = vd->vdev_ops->vdev_op_type; + + if (strcmp(vdev_type, VDEV_TYPE_ROOT) == 0 && + vd->vdev_children > 1) { + return (B_FALSE); + } else if (strcmp(vdev_type, VDEV_TYPE_RAIDZ) == 0 || + strcmp(vdev_type, VDEV_TYPE_MISSING) == 0) { + return (B_FALSE); + } + } else if (vd->vdev_wholedisk == 1) { + return (B_FALSE); + } + + for (c = 0; c < vd->vdev_children; c++) { + if (!vdev_is_bootable(vd->vdev_child[c])) + return (B_FALSE); + } + return (B_TRUE); +} diff --git a/usr/src/uts/common/fs/zfs/zfs_ioctl.c b/usr/src/uts/common/fs/zfs/zfs_ioctl.c index 81097a1aa1..b503c21b57 100644 --- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c +++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c @@ -155,6 +155,30 @@ history_str_get(zfs_cmd_t *zc) } /* + * Check to see if the named dataset is currently defined as bootable + */ +static boolean_t +zfs_is_bootfs(const char *name) +{ + spa_t *spa; + boolean_t ret = B_FALSE; + + if (spa_open(name, &spa, FTAG) == 0) { + if (spa->spa_bootfs) { + objset_t *os; + + if (dmu_objset_open(name, DMU_OST_ZFS, + DS_MODE_USER | DS_MODE_READONLY, &os) == 0) { + ret = (dmu_objset_id(os) == spa->spa_bootfs); + dmu_objset_close(os); + } + } + spa_close(spa, FTAG); + } + return (ret); +} + +/* * zfs_check_version * * Return non-zero if the spa version is less than requested version. @@ -1370,12 +1394,23 @@ zfs_set_prop_nvlist(const char *name, nvlist_t *nvl) * we'll catch them later. */ if (nvpair_type(elem) == DATA_TYPE_UINT64 && - nvpair_value_uint64(elem, &intval) == 0 && - intval >= ZIO_COMPRESS_GZIP_1 && - intval <= ZIO_COMPRESS_GZIP_9) { - if (zfs_check_version(name, + nvpair_value_uint64(elem, &intval) == 0) { + if (intval >= ZIO_COMPRESS_GZIP_1 && + intval <= ZIO_COMPRESS_GZIP_9 && + zfs_check_version(name, SPA_VERSION_GZIP_COMPRESSION)) return (ENOTSUP); + + /* + * If this is a bootable dataset then + * verify that the compression algorithm + * is supported for booting. We must return + * something other than ENOTSUP since it + * implies a downrev pool version. + */ + if (zfs_is_bootfs(name) && + !BOOTFS_COMPRESS_VALID(intval)) + return (ERANGE); } break; |